File: handle-empty-file-reading.patch

package info (click to toggle)
wtmpdb 0.74.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 584 kB
  • sloc: ansic: 4,193; xml: 697; sh: 63; makefile: 16
file content (104 lines) | stat: -rw-r--r-- 3,426 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
From: Andrew Bower <andrew@bower.uk>
Subject: Use empty memory table instead of failing to read empty file

Forwarded: https://github.com/thkukuk/wtmpdb/pull/39
Bug-Debian: https://bugs.debian.org/1094965
Last-Update: 2025-09-29

Previously, attempting to read an empty file gave an error
message and non-zero return code. Instead, when asked to open
an empty file as a read-only database, open a memory database
and populate it with an empty table. This avoids needing any
special case handling in calling code and matches the behaviour
of classic 'last' on an empty file.
---
 lib/sqlite.c | 47 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/lib/sqlite.c b/lib/sqlite.c
index 001eb71..0f3090c 100644
--- a/lib/sqlite.c
+++ b/lib/sqlite.c
@@ -61,12 +61,37 @@ strip_extension(char *in_str)
     }
 }
 
+/* Creates the table if it does not exist.
+ * Returns 0 on success, -1 on failure. */
+static int64_t
+create_table (sqlite3 *db, char **error)
+{
+  char *err_msg = NULL;
+  char *sql_table = "CREATE TABLE IF NOT EXISTS wtmp(ID INTEGER PRIMARY KEY, Type INTEGER, User TEXT NOT NULL, Login INTEGER, Logout INTEGER, TTY TEXT, RemoteHost TEXT, Service TEXT) STRICT;";
+
+  if (sqlite3_exec (db, sql_table, 0, 0, &err_msg) != SQLITE_OK)
+    {
+      if (error)
+	if (asprintf (error, "SQL error creating table: %s", err_msg) < 0)
+	  *error = strdup ("create_table: Out of memory");
+      sqlite3_free (err_msg);
+
+      return -1;
+    }
+  return 0;
+}
+
 static int
 open_database_ro (const char *path, sqlite3 **db, char **error)
 {
+  struct stat statbuf;
+  int empty_file;
   int r;
 
-  r = sqlite3_open_v2 (path, db, SQLITE_OPEN_READONLY, NULL);
+  empty_file = stat(path, &statbuf) == 0 && statbuf.st_size == 0;
+  r = sqlite3_open_v2 (path, db, empty_file ?
+                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_MEMORY :
+                       SQLITE_OPEN_READONLY, NULL);
   if (r != SQLITE_OK)
     {
       if (error)
@@ -80,7 +105,10 @@ open_database_ro (const char *path, sqlite3 **db, char **error)
 
   sqlite3_busy_timeout(*db, TIMEOUT);
 
-  return 0;
+  if (empty_file)
+    r = create_table (*db, error);
+
+  return r == SQLITE_OK ? 0 : -1;
 }
 
 static int
@@ -114,7 +142,8 @@ open_database_rw (const char *path, sqlite3 **db, char **error)
 
   sqlite3_busy_timeout(*db, TIMEOUT);
 
-  return 0;
+  r = create_table (*db, error);
+  return r == SQLITE_OK ? 0 : -1;
 }
 
 /* Add a new entry. Returns ID (>=0) on success, -1 on failure. */
@@ -123,21 +152,9 @@ add_entry (sqlite3 *db, int type, const char *user,
 	   uint64_t usec_login, const char *tty, const char *rhost,
 	   const char *service, char **error)
 {
-  char *err_msg = NULL;
   sqlite3_stmt *res;
-  char *sql_table = "CREATE TABLE IF NOT EXISTS wtmp(ID INTEGER PRIMARY KEY, Type INTEGER, User TEXT NOT NULL, Login INTEGER, Logout INTEGER, TTY TEXT, RemoteHost TEXT, Service TEXT) STRICT;";
   char *sql_insert = "INSERT INTO wtmp (Type,User,Login,TTY,RemoteHost,Service) VALUES(?,?,?,?,?,?);";
 
-  if (sqlite3_exec (db, sql_table, 0, 0, &err_msg) != SQLITE_OK)
-    {
-      if (error)
-	if (asprintf (error, "add_entry: SQL error: %s", err_msg) < 0)
-	  *error = strdup ("add_entry: Out of memory");
-      sqlite3_free (err_msg);
-
-      return -1;
-    }
-
   if (sqlite3_prepare_v2 (db, sql_insert, -1, &res, 0) != SQLITE_OK)
     {
       if (error)