Support for list file writing. Improve and cleanup everything

master
Luca Bruno 2010-03-14 22:04:52 +01:00
parent 71f10389a1
commit 553411c616
4 changed files with 173 additions and 144 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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

106
tdpkg.c
View File

@ -24,6 +24,8 @@
#include <string.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#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;
}