mirror of https://github.com/vitalif/tdpkg
283 lines
6.9 KiB
C
283 lines
6.9 KiB
C
/*
|
|
Copyright © 2010 Luca Bruno
|
|
|
|
This file is part of tdpkg.
|
|
|
|
tdpkg is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
tdpkg is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with tdpkg. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "cache.h"
|
|
|
|
/* real functions */
|
|
static int (*realopen)(const char *path, int oflag, ...);
|
|
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);
|
|
|
|
/* state */
|
|
static struct FopenState
|
|
{
|
|
FILE* file;
|
|
int putc_called;
|
|
} fopen_state;
|
|
|
|
#define FAKE_FD 1234
|
|
static struct OpenState
|
|
{
|
|
int fd;
|
|
char* contents;
|
|
size_t len;
|
|
size_t read;
|
|
} open_state;
|
|
|
|
static FILE* ignore_file;
|
|
static int cache_initialized;
|
|
|
|
/* called once library is preloaded */
|
|
void _init (void)
|
|
{
|
|
static int initialized = 0;
|
|
if (!initialized)
|
|
initialized = 1;
|
|
else
|
|
return;
|
|
|
|
memset (&fopen_state, '\0', sizeof (fopen_state));
|
|
memset (&open_state, '\0', sizeof (open_state));
|
|
open_state.fd = -1;
|
|
|
|
realopen = dlsym (RTLD_NEXT, "open");
|
|
real__fxstat = dlsym (RTLD_NEXT, "__fxstat");
|
|
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");
|
|
|
|
const char* cache_filename = "cache.db";
|
|
if (!tdpkg_cache_init (cache_filename))
|
|
cache_initialized = 1;
|
|
else
|
|
fprintf (stderr, "tdpkg: cache at %s initialization failed, no wrapping\n", cache_filename);
|
|
}
|
|
|
|
static int
|
|
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)
|
|
{
|
|
if (!cache_initialized)
|
|
return realfclose (fp);
|
|
|
|
if (fp == ignore_file)
|
|
{
|
|
printf ("tdpkg: ignored %p\n", ignore_file);
|
|
ignore_file = NULL;
|
|
return realfclose (fp);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (!cache_initialized)
|
|
return realopen (path, oflag, mode);
|
|
|
|
if (!is_list_file (path))
|
|
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);
|
|
return realopen (path, oflag, mode);
|
|
}
|
|
|
|
open_state.contents = tdpkg_cache_read_filename (path);
|
|
if (!open_state.contents)
|
|
{
|
|
fprintf (stderr, "tdpkg: file %s not up-to-date in cache, rebuild cache\n", path);
|
|
cache_initialized = 0;
|
|
if (tdpkg_cache_rebuild ())
|
|
{
|
|
fprintf (stderr, "tdpkg: can't rebuild cache, no wrapping\n");
|
|
return realopen (path, oflag, mode);
|
|
}
|
|
cache_initialized = 1;
|
|
|
|
open_state.contents = tdpkg_cache_read_filename (path);
|
|
if (!open_state.contents)
|
|
{
|
|
fprintf (stderr, "tdpkg: path %s not being indexed, no wrapping\n", path);
|
|
return realopen (path, oflag, 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;
|
|
}
|
|
|
|
int
|
|
__fxstat (int ver, int fd, struct stat* buf)
|
|
{
|
|
if (!cache_initialized)
|
|
return real__fxstat (ver, fd, buf);
|
|
|
|
if (open_state.fd < 0)
|
|
return real__fxstat (ver, fd, buf);
|
|
|
|
if (open_state.fd != fd)
|
|
{
|
|
fprintf (stderr, "tdpkg: __fxstat() to unknown fd %d\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;
|
|
}
|
|
|
|
int
|
|
__fxstat64 (int ver, int fd, struct stat64* buf)
|
|
{
|
|
if (!cache_initialized)
|
|
return real__fxstat64 (ver, fd, buf);
|
|
|
|
if (open_state.fd < 0)
|
|
return real__fxstat64 (ver, fd, buf);
|
|
|
|
if (open_state.fd != fd)
|
|
{
|
|
fprintf (stderr, "tdpkg: __fxstat64() to unknown fd %d\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;
|
|
}
|
|
|
|
ssize_t
|
|
read (int fildes, void *buf, size_t nbyte)
|
|
{
|
|
if (!cache_initialized)
|
|
return realread (fildes, buf, nbyte);
|
|
|
|
if (open_state.fd < 0)
|
|
return realread (fildes, buf, nbyte);
|
|
|
|
if (open_state.fd != fildes)
|
|
{
|
|
fprintf (stderr, "tdpkg: read() to unknown fd %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);
|
|
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;
|
|
}
|
|
|
|
int
|
|
close (int fd)
|
|
{
|
|
if (!cache_initialized)
|
|
return realclose (fd);
|
|
|
|
if (open_state.fd < 0)
|
|
return realclose (fd);
|
|
|
|
if (open_state.fd != fd)
|
|
{
|
|
fprintf (stderr, "tdpkg: close() on unknown fd %d, no wrapping\n", fd);
|
|
return realclose (fd);
|
|
}
|
|
|
|
open_state.fd = -1;
|
|
if (open_state.contents)
|
|
free (open_state.contents);
|
|
open_state.contents = NULL;
|
|
open_state.len = 0;
|
|
open_state.read = 0;
|
|
return 0;
|
|
}
|