Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | First attempt at code for a FuseFS on an SQLite archive. Compiles, but does not work quite right. Added -Wall and -Werror to the makefile. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
a394ea2f57ac4507f435de554b34a428 |
User & Date: | drh 2014-06-13 17:57:18.400 |
Context
2014-06-13
| ||
17:59 | Add a "clean" target to the Makefile. check-in: 5766e8f04e user: drh tags: trunk | |
17:57 | First attempt at code for a FuseFS on an SQLite archive. Compiles, but does not work quite right. Added -Wall and -Werror to the makefile. check-in: a394ea2f57 user: drh tags: trunk | |
17:16 | Change the name of the table in the database to "sqlar". check-in: 50d50f29fd user: drh tags: trunk | |
Changes
Changes to Makefile.
1 2 | #!/bin/make | | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/bin/make CC = gcc -g -I. -D_FILE_OFFSET_BITS=64 -Wall -Werror ZLIB = -lz FUSELIB = -lfuse SQLITE_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION all: sqlar sqlar: sqlar.c sqlite3.o $(CC) -o sqlar sqlar.c sqlite3.o $(ZLIB) sqlarfs: sqlarfs.c sqlite3.o $(CC) -o sqlarfs sqlarfs.c sqlite3.o $(ZLIB) $(FUSELIB) sqlite3.o: sqlite3.c sqlite3.h $(CC) -c sqlite3.c $(SQLITE_OPT) sqlite3.c |
Changes to sqlar.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <stdarg.h> #include <stdlib.h> #include <zlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> /* ** Show a help message and quit. */ static void showHelp(const char *argv0){ fprintf(stderr, "Usage: %s [options] archive [files...]\n", argv0); fprintf(stderr, "Options:\n" | > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <stdarg.h> #include <stdlib.h> #include <zlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> #include <string.h> /* ** Show a help message and quit. */ static void showHelp(const char *argv0){ fprintf(stderr, "Usage: %s [options] archive [files...]\n", argv0); fprintf(stderr, "Options:\n" |
︙ | ︙ | |||
158 159 160 161 162 163 164 | if( noCompress ){ *pSizeOrig = *pSizeCompr = nIn; return zIn; } nCompr = 13 + nIn + (nIn+999)/1000; zCompr = sqlite3_malloc( nCompr+1 ); if( zCompr==0 ) errorMsg("cannot malloc for %d bytes\n", nCompr+1); | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | if( noCompress ){ *pSizeOrig = *pSizeCompr = nIn; return zIn; } nCompr = 13 + nIn + (nIn+999)/1000; zCompr = sqlite3_malloc( nCompr+1 ); if( zCompr==0 ) errorMsg("cannot malloc for %d bytes\n", nCompr+1); rc = compress((Bytef*)zCompr, &nCompr, (const Bytef*)zIn, nIn); if( rc!=Z_OK ) errorMsg("Cannot compress %s\n", zFilename); if( nIn>nCompr ){ sqlite3_free(zIn); *pSizeOrig = nIn; *pSizeCompr = (int)nCompr; return zCompr; }else{ |
︙ | ︙ | |||
231 232 233 234 235 236 237 | if( sz>0 && fwrite(pCompr, sz, 1, out)!=1 ){ errorMsg("failed to write: %s\n", zFilename); } }else{ pOut = sqlite3_malloc( sz+1 ); if( pOut==0 ) errorMsg("cannot allocate %d bytes\n", sz+1); nOut = sz; | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | if( sz>0 && fwrite(pCompr, sz, 1, out)!=1 ){ errorMsg("failed to write: %s\n", zFilename); } }else{ pOut = sqlite3_malloc( sz+1 ); if( pOut==0 ) errorMsg("cannot allocate %d bytes\n", sz+1); nOut = sz; rc = uncompress((Bytef*)pOut, &nOut, (const Bytef*)pCompr, nCompr); if( rc!=Z_OK ) errorMsg("uncompress failed for %s\n", zFilename); if( nOut>0 && fwrite(pOut, nOut, 1, out)!=1 ){ errorMsg("failed to write: %s\n", zFilename); } sqlite3_free(pOut); } fclose(out); |
︙ | ︙ | |||
265 266 267 268 269 270 271 | static void add_file( const char *zFilename, /* Name of file to add */ int verboseFlag, /* If true, show each file added */ int noCompress /* If true, always omit compression */ ){ int rc; struct stat x; | < | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | static void add_file( const char *zFilename, /* Name of file to add */ int verboseFlag, /* If true, show each file added */ int noCompress /* If true, always omit compression */ ){ int rc; struct stat x; int szOrig; int szCompr; const char *zName; check_filename(zFilename); rc = stat(zFilename, &x); if( rc ) errorMsg("no such file or directory: %s\n", zFilename); |
︙ | ︙ | |||
317 318 319 320 321 322 323 | char *zSubpath; d = opendir(zFilename); if( d ){ while( (pEntry = readdir(d))!=0 ){ if( strcmp(pEntry->d_name,".")==0 || strcmp(pEntry->d_name,"..")==0 ){ continue; } | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | char *zSubpath; d = opendir(zFilename); if( d ){ while( (pEntry = readdir(d))!=0 ){ if( strcmp(pEntry->d_name,".")==0 || strcmp(pEntry->d_name,"..")==0 ){ continue; } zSubpath = sqlite3_mprintf("%s/%s", zFilename, pEntry->d_name); add_file(zSubpath, verboseFlag, noCompress); sqlite3_free(zSubpath); } } } } |
︙ | ︙ | |||
393 394 395 396 397 398 399 | azFiles = &argv[i]; nFiles = argc - i; break; } } if( zArchive==0 ) showHelp(argv[0]); if( listFlag ){ | < | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | azFiles = &argv[i]; nFiles = argc - i; break; } } if( zArchive==0 ) showHelp(argv[0]); if( listFlag ){ db_open(zArchive, 0); if( verboseFlag ){ db_prepare( "SELECT name, sz, length(data), mode, datetime(mtime,'unixepoch')" " FROM sqlar ORDER BY name" ); while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
︙ | ︙ | |||
419 420 421 422 423 424 425 | while( sqlite3_step(pStmt)==SQLITE_ROW ){ printf("%s\n", sqlite3_column_text(pStmt,0)); } } db_close(1); }else if( extractFlag ){ const char *zSql; | < | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | while( sqlite3_step(pStmt)==SQLITE_ROW ){ printf("%s\n", sqlite3_column_text(pStmt,0)); } } db_close(1); }else if( extractFlag ){ const char *zSql; db_open(zArchive, 0); if( nFiles ){ NameList x; x.azName = azFiles; x.nName = nFiles; sqlite3_create_function(db, "name_on_list", 1, SQLITE_UTF8, (char*)&x, name_on_list, 0, 0); |
︙ | ︙ |
Added sqlarfs.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | /* ** This file implements a FuseFS userspace client to mount an SQLAR ** file archive (read-only). ** ** Usage: ** ** sqlarfs ARCHIVE-FILE MOUNT-POINT */ #define FUSE_USE_VERSION 26 #include <fuse.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <zlib.h> #include "sqlite3.h" #include <stdlib.h> /* ** Global state information about the archive */ struct sGlobal { sqlite3 *db; /* Open database connection */ sqlite3_stmt *pStat; /* Prepared statement to read stat info */ sqlite3_stmt *pFList; /* Prepared statement to list all files */ sqlite3_stmt *pExists; /* Prepared statement to check if a file exists */ sqlite3_stmt *pRead; /* Prepared statement to get file content */ char *zCacheName; /* Cached file */ unsigned long int szCache; /* Size of the cached file */ char *zCacheData; /* Content of the cached files */ } g; /* ** Implementation of stat() */ static int sqlarfs_getattr(const char *path, struct stat *stbuf){ int rc = 0; memset(stbuf, 0, sizeof(*stbuf)); if( strcmp(path, "/")==0 ){ stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; return 0; } if( g.pStat==0 ){ rc = sqlite3_prepare_v2(g.db, "SELECT mode, mtime, sz FROM sqlar WHERE name=?1", -1, &g.pStat, 0); if( rc!=SQLITE_OK ){ return -ENOENT; } } sqlite3_bind_text(g.pStat, 1, &path[1], -1, SQLITE_STATIC); if( sqlite3_step(g.pStat)==SQLITE_ROW ){ stbuf->st_mode = sqlite3_column_int(g.pStat, 0); stbuf->st_nlink = 1; stbuf->st_mtime = sqlite3_column_int(g.pStat, 1); stbuf->st_size = sqlite3_column_int64(g.pStat, 2); rc = 0; }else{ rc = -ENOENT; } sqlite3_reset(g.pStat); return rc; } /* ** Implementation of readdir() */ static int sqlarfs_readdir( const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi ){ int rc; if( strcmp(path, "/")!=0 ) return -ENOENT; if( g.pFList==0 ){ rc = sqlite3_prepare_v2(g.db, "SELECT name FROM sqlar" " WHERE name BETWEEN ?1 AND ?1 || char(1114111)" " AND substr(name,length(?1)) NOT GLOB '*/*'", -1, &g.pFList, 0); if( rc!=SQLITE_OK ){ return -ENOENT; } } filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); sqlite3_bind_text(g.pFList, 1, &path[1], -1, SQLITE_STATIC); while( sqlite3_step(g.pFList)==SQLITE_ROW ){ filler(buf, (const char*)sqlite3_column_text(g.pFList, 0), NULL, 0); } sqlite3_reset(g.pFList); return 0; return 0; } /* ** Implementation of open() */ static int sqlarfs_open(const char *path, struct fuse_file_info *fi){ int rc; if( (fi->flags & 3) != O_RDONLY ) return -EACCES; if( g.pExists==0 ){ rc = sqlite3_prepare_v2(g.db, "SELECT 1 FROM sqlar WHERE name=?1", -1, &g.pExists, 0); if( rc!=SQLITE_OK ){ return -ENOENT; } } sqlite3_bind_text(g.pExists, 1, &path[1], -1, SQLITE_STATIC); rc = sqlite3_step(g.pExists); sqlite3_reset(g.pExists); if( rc==SQLITE_DONE ) return -ENOENT; return 0; } /* ** Load the file named path[] into the cache, if it is not there already. ** ** Return 0 on success. Return an error code if the file could not be loaded. */ static int loadCache(const char *path){ unsigned long int nIn; const char *zIn; int rc; if( g.zCacheName ){ if( strcmp(path, g.zCacheName)==0 ) return 0; sqlite3_free(g.zCacheName); g.zCacheName = 0; sqlite3_free(g.zCacheData); g.zCacheData = 0; } if( g.pRead==0 ){ rc = sqlite3_prepare_v2(g.db, "SELECT sz, data FROM sqlar WHERE name=?1", -1, &g.pRead, 0); if( rc!=SQLITE_OK ){ return -EIO; } } sqlite3_bind_text(g.pRead, 1, path, -1, SQLITE_STATIC); if( sqlite3_step(g.pRead)==SQLITE_ROW ){ g.szCache = sqlite3_column_int64(g.pRead, 0); zIn = (const char*)sqlite3_column_blob(g.pRead, 1); nIn = (unsigned long int)sqlite3_column_bytes(g.pRead, 1); g.zCacheData = sqlite3_malloc( g.szCache ); if( g.zCacheData==0 ){ rc = -EIO; }else{ rc = uncompress((Bytef*)g.zCacheData, &g.szCache, (const Bytef*)zIn, nIn); if( rc!=Z_OK ){ sqlite3_free(g.zCacheData); g.zCacheData = 0; rc = -EIO; } } if( g.zCacheData ){ g.zCacheName = sqlite3_mprintf("%s", path); if( g.zCacheName==0 ){ rc = -EIO; sqlite3_free(g.zCacheData); g.zCacheData = 0; } } } sqlite3_reset(g.pRead); return rc; } /* ** Implementation of read() */ static int sqlarfs_read( const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi ){ int rc; rc = loadCache(&path[1]); if( rc==0 ){ if( offset>=g.szCache ){ return 0; } if( offset+size>g.szCache ) size = g.szCache - offset; memcpy(buf, g.zCacheData + offset, size); return size; }else{ return rc; } } static struct fuse_operations sqlarfs_methods = { .getattr = sqlarfs_getattr, .readdir = sqlarfs_readdir, .open = sqlarfs_open, .read = sqlarfs_read, }; int main(int argc, char **argv){ int rc; if( argc<2 ){ fprintf(stderr, "Usage: %s SQLAR-ARCHIVE [-d] [-s] [-f] MOUNT-POINT\n", argv[0]); exit(1); } rc = sqlite3_open(argv[1], &g.db); if( rc!=SQLITE_OK ){ fprintf(stderr, "Cannot open sqlar file [%s]\n", argv[1]); exit(1); } rc = sqlite3_exec(g.db, "SELECT 1 FROM sqlar LIMIT 1", 0, 0, 0); if( rc!=SQLITE_OK ){ fprintf(stderr, "File [%s] is not an SQLite archive\n", argv[1]); exit(1); } rc = fuse_main(argc-1, argv+1, &sqlarfs_methods, NULL); return rc; } |