From 553411c6165d112512030098dea261cbc9624a06 Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Sun, 14 Mar 2010 22:04:52 +0100 Subject: [PATCH] Support for list file writing. Improve and cleanup everything --- Makefile | 3 +- cache.c => cache-sqlite.c | 204 ++++++++++++++++++++++++++------------ cache.h | 4 +- tdpkg.c | 106 ++++++-------------- 4 files changed, 173 insertions(+), 144 deletions(-) rename cache.c => cache-sqlite.c (50%) diff --git a/Makefile b/Makefile index 7e05a71..5de59f1 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,11 @@ +CACHE = sqlite CC = gcc CFLAGS = -g -Wall -fPIC LIBS = -lc -ldl -lsqlite3 LDFLAGS = -nostdlib -shared COMPILE = $(CC) $(CFLAGS) LINK = $(CC) $(LDFLAGS) $(LIBS) -SRCS = tdpkg.c cache.c +SRCS = tdpkg.c cache-$(CACHE).c OBJS = $(subst .c,.o,$(SRCS)) all: libtdpkg.so diff --git a/cache.c b/cache-sqlite.c similarity index 50% rename from cache.c rename to cache-sqlite.c index c7c4eb1..8755045 100644 --- a/cache.c +++ b/cache-sqlite.c @@ -27,12 +27,13 @@ #include "cache.h" #define sqlite_error(ret) { fprintf (stderr, "tdpkg sqlite: %s\n", sqlite3_errmsg (db)); return ret; } +#define CREATE_TABLE_SQL "CREATE TABLE IF NOT EXISTS files (filename varchar(255) PRIMARY KEY ON CONFLICT REPLACE, contents text);" #define READ_FILE_SQL "SELECT contents FROM files WHERE filename=?" #define INSERT_FILE_SQL "INSERT INTO files (filename, contents) VALUES (?, ?)" -static sqlite3* db; -static sqlite3_stmt* read_file_stmt; -static sqlite3_stmt* insert_file_stmt; +static sqlite3* db = NULL; +static sqlite3_stmt* read_file_stmt = NULL; +static sqlite3_stmt* insert_file_stmt = NULL; static int _sqlite_exec (const char* sql) @@ -50,26 +51,96 @@ _sqlite_exec (const char* sql) /* returns 0 on success */ int -tdpkg_cache_init (const char* filename) +tdpkg_cache_initialize (const char* filename) { if (sqlite3_initialize () != SQLITE_OK) sqlite_error (-1); if (sqlite3_open (filename, &db) != SQLITE_OK) - sqlite_error (-1); + { + tdpkg_cache_finalize (); + sqlite_error (-1); + } - if (_sqlite_exec ("CREATE TABLE IF NOT EXISTS files (filename varchar(255) primary key, contents text);")) - return -1; + if (_sqlite_exec (CREATE_TABLE_SQL)) + { + tdpkg_cache_finalize (); + return -1; + } if (sqlite3_prepare (db, READ_FILE_SQL, -1, &read_file_stmt, NULL) != SQLITE_OK) - sqlite_error (-1); + { + tdpkg_cache_finalize (); + sqlite_error (-1); + } if (sqlite3_prepare (db, INSERT_FILE_SQL, -1, &insert_file_stmt, NULL) != SQLITE_OK) - sqlite_error (-1); + { + tdpkg_cache_finalize (); + sqlite_error (-1); + } + + /* ensure cache consistency with the file system */ + struct stat stat_buf; + if (__xstat (0, filename, &stat_buf)) + { + fprintf (stderr, "tdpkg sqlite: can't stat %s\n", filename); + tdpkg_cache_finalize (); + return -1; + } + time_t db_time = stat_buf.st_mtime; + + glob_t glob_list; + if (glob ("/var/lib/dpkg/info/*.list", 0, NULL, &glob_list)) + { + fprintf (stderr, "tdpkg sqlite: can't glob /var/lib/dpkg/info/*.list\n"); + tdpkg_cache_finalize (); + return -1; + } + + int i; + for (i=0; i < glob_list.gl_pathc; i++) + { + const char* filename = glob_list.gl_pathv[i]; + struct stat stat_buf; + + /* we don't use fstat because it's been wrapped */ + if (__xstat (0, filename, &stat_buf)) + { + fprintf (stderr, "tdpkg sqlite: can't stat %s\n", filename); + tdpkg_cache_finalize (); + return -1; + } + + /* list file more recent than cache */ + if (stat_buf.st_mtime > db_time) + { + if (tdpkg_cache_rebuild ()) + { + globfree (&glob_list); + tdpkg_cache_finalize (); + return -1; + } + break; + } + } + globfree (&glob_list); return 0; } +void +tdpkg_cache_finalize (void) +{ + if (read_file_stmt) + sqlite3_finalize (read_file_stmt); + if (insert_file_stmt) + sqlite3_finalize (insert_file_stmt); + if (db) + sqlite3_close (db); + sqlite3_shutdown (); +} + char* tdpkg_cache_read_filename (const char* filename) { @@ -93,6 +164,57 @@ tdpkg_cache_read_filename (const char* filename) return result; } +int +tdpkg_cache_write_filename (const char* filename) +{ + struct stat stat_buf; + + if (__xstat (0, filename, &stat_buf)) + { + fprintf (stderr, "tdpkg sqlite: can't stat %s\n", filename); + return -1; + } + size_t size = stat_buf.st_size; + + FILE* file = fopen (filename, "r"); + if (!file) + { + fprintf (stderr, "tdpkg sqlite: can't open %s\n", filename); + return -1; + } + + char* contents = malloc (size); + if (fread (contents, sizeof (char), size, file) < size) + { + // FIXME: let's handle this? + fprintf (stderr, "tdpkg sqlite: can't read full file %s of size %ld\n", filename, size); + fclose (file); + return -1; + } + fclose (file); + + if (sqlite3_reset (insert_file_stmt) != SQLITE_OK) + sqlite_error (-1); + + if (sqlite3_bind_text (insert_file_stmt, 1, filename, -1, SQLITE_STATIC) != SQLITE_OK) + sqlite_error (-1); + + if (sqlite3_bind_text (insert_file_stmt, 2, contents, size, SQLITE_STATIC) != SQLITE_OK) + { + free (contents); + sqlite_error (-1); + } + + if (sqlite3_step (insert_file_stmt) != SQLITE_DONE) + { + free (contents); + sqlite_error (-1); + } + + free (contents); + return 0; +} + int tdpkg_cache_rebuild (void) { @@ -104,74 +226,28 @@ tdpkg_cache_rebuild (void) } if (_sqlite_exec ("DELETE FROM files; BEGIN;")) - return -1; + { + globfree (&glob_list); + return -1; + } int i; for (i=0; i < glob_list.gl_pathc; i++) { const char* filename = glob_list.gl_pathv[i]; - struct stat stat_buf; - - /* we don't use fstat because it's been wrapped */ - if (__xstat (1, filename, &stat_buf)) - { - fprintf (stderr, "tdpkg sqlite: can't stat %s\n", filename); - return -1; - } - size_t size = stat_buf.st_size; - - FILE* file = fopen (filename, "r"); - if (!file) - { - fprintf (stderr, "tdpkg sqlite: can't open %s\n", filename); - return -1; - } - printf ("tdpkg: (Indexing list file %d...)\r", i+1); - - char* contents = malloc (size); - if (fread (contents, sizeof (char), size, file) < size) - { - // FIXME: let's handle this? - _sqlite_exec ("ROLLBACK;"); - fclose (file); - fprintf (stderr, "tdpkg sqlite: can't read full file %s of size %ld\n", filename, size); - } - fclose (file); - - if (sqlite3_reset (insert_file_stmt) != SQLITE_OK) + if (tdpkg_cache_write_filename (filename)) { _sqlite_exec ("ROLLBACK;"); - sqlite_error (-1); + globfree (&glob_list); + return -1; } - - if (sqlite3_bind_text (insert_file_stmt, 1, filename, -1, SQLITE_STATIC) != SQLITE_OK) - { - _sqlite_exec ("ROLLBACK;"); - sqlite_error (-1); - } - - if (sqlite3_bind_text (insert_file_stmt, 2, contents, size, SQLITE_STATIC) != SQLITE_OK) - { - _sqlite_exec ("ROLLBACK;"); - free (contents); - sqlite_error (-1); - } - - if (sqlite3_step (insert_file_stmt) != SQLITE_DONE) - { - _sqlite_exec ("ROLLBACK;"); - free (contents); - sqlite_error (-1); - } - - free (contents); } + globfree (&glob_list); if (_sqlite_exec ("COMMIT;")) return -1; - printf ("tdpkg: %d list files inserted succefully\n", i); - + printf ("tdpkg: %d list files cached succefully\n", i); return 0; } diff --git a/cache.h b/cache.h index 12d6a76..bc5aa58 100644 --- a/cache.h +++ b/cache.h @@ -1,8 +1,10 @@ #ifndef CACHE_H #define CACHE_H -int tdpkg_cache_init (const char* filename); +int tdpkg_cache_initialize (const char* filename); +void tdpkg_cache_finalize (void); char* tdpkg_cache_read_filename (const char* filename); +int tdpkg_cache_write_filename (const char* filename); int tdpkg_cache_rebuild (void); #endif diff --git a/tdpkg.c b/tdpkg.c index c4f986c..e6b740b 100644 --- a/tdpkg.c +++ b/tdpkg.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "cache.h" @@ -33,18 +35,10 @@ static int (*real__fxstat)(int ver, int fd, struct stat* buf); static int (*real__fxstat64)(int ver, int fd, struct stat64* buf); static ssize_t (*realread)(int fildes, void *buf, size_t nbyte); static int (*realclose)(int fd); -static FILE* (*realfopen)(const char *path, const char *mode); -static FILE* (*realfdopen)(int fd, const char *mode); -static int (*realfclose)(FILE* fp); +static int (*realrename)(const char *old, const char *new); -/* state */ -static struct FopenState -{ - FILE* file; - int putc_called; -} fopen_state; - -#define FAKE_FD 1234 +/* handle open() of dpkg/src/filesdb.c */ +#define FAKE_FD 4321 static struct OpenState { int fd; @@ -53,7 +47,6 @@ static struct OpenState size_t read; } open_state; -static FILE* ignore_file; static int cache_initialized; /* called once library is preloaded */ @@ -65,7 +58,6 @@ void _init (void) else return; - memset (&fopen_state, '\0', sizeof (fopen_state)); memset (&open_state, '\0', sizeof (open_state)); open_state.fd = -1; @@ -74,12 +66,10 @@ void _init (void) real__fxstat64 = dlsym (RTLD_NEXT, "__fxstat64"); realread = dlsym (RTLD_NEXT, "read"); realclose = dlsym (RTLD_NEXT, "close"); - realfopen = dlsym (RTLD_NEXT, "fopen"); - realfdopen = dlsym (RTLD_NEXT, "fdopen"); - realfclose = dlsym (RTLD_NEXT, "fclose"); + realrename = dlsym (RTLD_NEXT, "rename"); const char* cache_filename = "cache.db"; - if (!tdpkg_cache_init (cache_filename)) + if (!tdpkg_cache_initialize (cache_filename)) cache_initialized = 1; else fprintf (stderr, "tdpkg: cache at %s initialization failed, no wrapping\n", cache_filename); @@ -91,74 +81,38 @@ is_list_file (const char* path) return strstr (path, "/var/lib/dpkg/info/") && strstr (path, ".list"); } -FILE* -fopen (const char *path, const char *mode) -{ - if (!cache_initialized) - return realfopen (path, mode); - - if (!is_list_file (path)) - return realfopen (path, mode); - - if (fopen_state.file) - { - fprintf (stderr, "tdpkg: multiple fopen(%s, %s) without fclose() detected, no wrapping\n", path, mode); - return realfopen (path, mode); - } - - printf ("tpkdg: fopen(%s, %s)\n", path, mode); - fopen_state.file = realfopen (path, mode); - return fopen_state.file; -} - -FILE* -fdopen (int fd, const char *mode) -{ - if (!cache_initialized) - return realfdopen (fd, mode); - - ignore_file = realfdopen (fd, mode); - return ignore_file; -} - int -fclose (FILE *fp) +rename (const char *old, const char *new) { - if (!cache_initialized) - return realfclose (fp); - - if (fp == ignore_file) + int result = realrename (old, new); + if (!result && is_list_file (new)) { - printf ("tdpkg: ignored %p\n", ignore_file); - ignore_file = NULL; - return realfclose (fp); + if (tdpkg_cache_write_filename (new)) + { + fprintf (stderr, "tdpkg: can't update cache for file %s, no wrapping\n", new); + tdpkg_cache_finalize (); + } } - - if (fopen_state.file != fp) - { - fprintf (stderr, "tdpkg: fclose() to unknown file %p detected, no wrapping\n", fp); - return realfclose (fp); - } - - printf ("tdpkg: fclose()\n"); - int result = realfclose (fopen_state.file); - fopen_state.file = NULL; - return result; } int -open (const char *path, int oflag, int mode) +open (const char *path, int oflag, ...) { + va_list ap; + va_start (ap, oflag); + int mode = va_arg (ap, int); + va_end (ap); + if (!cache_initialized) return realopen (path, oflag, mode); - if (!is_list_file (path)) + if (!is_list_file (path) || (oflag & O_RDONLY) != O_RDONLY) return realopen (path, oflag, mode); if (open_state.fd >= 0) { - fprintf (stderr, "tdpkg: multiple open(%s, %d, %d) without close() detected, no wrapping\n", path, oflag, mode); + fprintf (stderr, "tdpkg: nested open(%s, %d, %d) detected, no wrapping\n", path, oflag, mode); return realopen (path, oflag, mode); } @@ -170,6 +124,7 @@ open (const char *path, int oflag, int mode) if (tdpkg_cache_rebuild ()) { fprintf (stderr, "tdpkg: can't rebuild cache, no wrapping\n"); + tdpkg_cache_finalize (); return realopen (path, oflag, mode); } cache_initialized = 1; @@ -182,10 +137,8 @@ open (const char *path, int oflag, int mode) } } - printf ("tdpkg: open(%s, %d, %d)\n", path, oflag, mode); open_state.fd = FAKE_FD; open_state.len = strlen (open_state.contents); - return open_state.fd; } @@ -200,11 +153,10 @@ __fxstat (int ver, int fd, struct stat* buf) if (open_state.fd != fd) { - fprintf (stderr, "tdpkg: __fxstat() to unknown fd %d\n", fd); + fprintf (stderr, "tdpkg: nested __fxstat(%d) detected, no wrapping\n", fd); return real__fxstat (ver, fd, buf); } - printf ("tdpkg: __fxstat(%d) is %ld\n", fd, open_state.len); buf->st_size = open_state.len; return 0; } @@ -220,11 +172,10 @@ __fxstat64 (int ver, int fd, struct stat64* buf) if (open_state.fd != fd) { - fprintf (stderr, "tdpkg: __fxstat64() to unknown fd %d\n", fd); + fprintf (stderr, "tdpkg: nested __fxstat64(%d) detected, no wrapping\n", fd); return real__fxstat64 (ver, fd, buf); } - printf ("tdpkg: __fxstat64(%d) is %ld\n", fd, open_state.len); buf->st_size = open_state.len; return 0; } @@ -240,20 +191,19 @@ read (int fildes, void *buf, size_t nbyte) if (open_state.fd != fildes) { - fprintf (stderr, "tdpkg: read() to unknown fd %d detected, no wrapping\n", fildes); + fprintf (stderr, "tdpkg: nested read(%d) detected, no wrapping\n", fildes); return realread (fildes, buf, nbyte); } if (open_state.read > open_state.len) { - fprintf (stderr, "tdpkg: read() already done on %d, returning 0\n", open_state.fd); + fprintf (stderr, "tdpkg: useless read(%d) detected, returning 0\n", open_state.fd); return 0; } size_t nowread = (open_state.len-open_state.read) > nbyte ? nbyte : (open_state.len-open_state.read); memcpy (buf, open_state.contents+open_state.read, nowread); open_state.read += nowread; - printf ("tdpkg: read(%d, %p, %ld) -> %ld\n", fildes, buf, nbyte, nowread); return nowread; }