From 671f428ec0d4478a8a497ab47c7f6e9f5d4b51cf Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 18 Jul 2013 15:45:11 -0400 Subject: [PATCH] super basic 'ls' and 'cat' for reading sqlfs files without mounting them * both only take a single file arg * 'ls' only shows the file names * both currently only work with unencrypted sqlfs.db files --- .gitignore | 5 ++++ Makefile.am | 8 ++++- configure.in | 3 +- sqlfscat.c | 68 ++++++++++++++++++++++++++++++++++++++++++ sqlfsls.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 sqlfscat.c create mode 100644 sqlfsls.cpp diff --git a/.gitignore b/.gitignore index f5f6936..a447594 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ m4/ # # build products fuse_sqlfs +sqlfscat +sqlfsls libsqlfs-1.0.la libsqlfs.pc *.o @@ -34,3 +36,6 @@ tests/c_thread_api_key tests/c_api_key tests/c_api_key.db tests/fuse_test +# +# emacs! +*~ diff --git a/Makefile.am b/Makefile.am index 810cfcf..171a69b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,8 +11,14 @@ libsqlfs_1_0_la_SOURCES = sqlfs.c libsqlfs_1_0_la_LIBADD = @SQLITE@ @LIBFUSE@ libsqlfs_1_0_la_LDFLAGS = -version-info 1:0:0 +bin_PROGRAMS = sqlfscat sqlfsls +sqlfscat_SOURCES = sqlfscat.c +sqlfscat_LDADD = -lpthread @SQLITE@ ./.libs/libsqlfs-1.0.la +sqlfsls_SOURCES = sqlfsls.cpp +sqlfsls_LDADD = -lpthread @SQLITE@ ./.libs/libsqlfs-1.0.la + if WITH_LIBFUSE -bin_PROGRAMS = fuse_sqlfs +bin_PROGRAMS += fuse_sqlfs fuse_sqlfs_SOURCES = fuse_sqlfs.c fuse_sqlfs_LDADD = -lpthread @SQLITE@ @LIBFUSE@ ./.libs/libsqlfs-1.0.la endif diff --git a/configure.in b/configure.in index f892357..60039a2 100644 --- a/configure.in +++ b/configure.in @@ -9,6 +9,7 @@ AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([dist-bzip2 -Wall]) AC_PROG_CC +AC_PROG_CXX AC_PROG_LIBTOOL # needed for "per-product" flags, i.e. fsx_CFLAGS AM_PROG_CC_C_O @@ -81,7 +82,7 @@ AS_IF([test "x$with_fuse" != xno], AC_DEFINE([HAVE_LIBFUSE], [1], [Define if you have fuse]) with_fuse=yes - CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=25" + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=25" LIBS="$LIBS -lpthread" ], [if test "x$with_fuse" != xcheck; then diff --git a/sqlfscat.c b/sqlfscat.c new file mode 100644 index 0000000..c787b1a --- /dev/null +++ b/sqlfscat.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +#include "sqlfs.h" + +#define BUF_SIZE 8192 + +int main(int argc, char *argv[]) +{ + int n; + char buf[BUF_SIZE]; + struct stat s; + sqlfs_t *sqlfs = 0; + if (argc != 3) + { + fprintf(stderr, "Usage: %s sqlfs.db /path/to/file/to/cat\n", argv[0]); + exit(1); + } + const char *db = argv[1]; + const char *file = argv[2]; + +/* first setup the database file */ + if(access(db, R_OK)) + { + fprintf(stderr, "sqlfs file is not readable! (%s)\n", db); + exit(1); + } + if(stat(db, &s) < 0) + { + fprintf(stderr, "stat on %s failed!\n", db); + exit(1); + } + if(S_ISREG(s.st_mode)<0) + { + fprintf(stderr, "Not a regular file: %s\n", db); + exit(1); + } + if (!sqlfs_open(db, &sqlfs)) { + fprintf(stderr, "Failed to open: %s\n", db); + return 1; + } + sqlfs_init(db); + + // TODO memset(0) the key after its passed to sqlfs + + if (!sqlfs_proc_access(sqlfs, file, R_OK)) { + fprintf(stderr, "Cannot access %s in %s\n", file, db); + //return 1; + } + + +/* now read the file from sqlfs */ + struct fuse_file_info ffi; + int wrote = 0; // this is used to track were we are in the read + sqlfs_proc_open(sqlfs, file, &ffi); + while((n = sqlfs_proc_read(sqlfs, file, buf, BUF_SIZE, wrote, &ffi)) > 0) + { + wrote += write(1, buf, n); // write to stdout + } + + sqlfs_close(sqlfs); + // TODO return proper exit value + return 0; +} diff --git a/sqlfsls.cpp b/sqlfsls.cpp new file mode 100644 index 0000000..a28bbaf --- /dev/null +++ b/sqlfsls.cpp @@ -0,0 +1,83 @@ +#include +#include + +#include +#include +#include + +#include "sqlfs.h" + +typedef std::vector DirEntries; + +/* FUSE filler() function for use with the FUSE style readdir() that + * libsqlfs provides. Note: this function only ever expects statp to + * be NULL and off to be 0. buf is DirEntries */ +static int fill_dir(void *buf, const char *name, const struct stat *statp, off_t off) { + DirEntries *entries = (DirEntries*) buf; + if(statp != NULL) + fprintf(stderr, "File.listImpl() fill_dir always expects statp to be NULL"); + if(off != 0) + fprintf(stderr, "File.listImpl() fill_dir always expects off to be 0"); + entries->push_back(name); + // TODO implement returning an error (1) if something bad happened + return 0; +} + +int main(int argc, char *argv[]) +{ + int n; + struct stat s; + sqlfs_t *sqlfs = 0; + const char *db; + const char *file; + if (argc == 2) + { + db = argv[1]; + file = "/"; + } + else if (argc != 3) + { + fprintf(stderr, "Usage: %s sqlfs.db [ /path ]\n", argv[0]); + exit(1); + } + else + { + db = argv[1]; + file = argv[2]; + } + +/* first setup the database file */ + if(access(db, R_OK)) + { + fprintf(stderr, "sqlfs file is not readable! (%s)\n", db); + exit(1); + } + if(stat(db, &s) < 0) + { + fprintf(stderr, "stat on %s failed!\n", db); + exit(1); + } + if(S_ISREG(s.st_mode)<0) + { + fprintf(stderr, "Not a regular file: %s\n", db); + exit(1); + } + if (!sqlfs_open(db, &sqlfs)) { + fprintf(stderr, "Failed to open: %s\n", db); + return 1; + } + sqlfs_init(db); + // TODO memset(0) the key after its passed to sqlfs + +/* now read the dir entries */ + DirEntries entries; + // using FUSE readdir in old getdir() style which gives us the whole thing at once + int ret = sqlfs_proc_readdir(0, file, (void *)&entries, (fuse_fill_dir_t)fill_dir, 0, NULL); + for(DirEntries::const_iterator i = entries.begin() + 2; i != entries.end(); ++i) { + std::cout << *i << "\n"; // this will print all the contents of *features* + } + + sqlfs_close(sqlfs); + + return abs(ret); // FUSE returns negative error values +}