added overlay option
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Sun, 7 Aug 2022 07:06:49 +0000 (17:06 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Sun, 7 Aug 2022 07:06:49 +0000 (17:06 +1000)
fusefile.c

index 59dcaa5fb746b13f90098c69c7e278b21b73490e..8371d1f6c9448d538daa7b4ba1f2fc89feb89676 100644 (file)
@@ -53,7 +53,9 @@ static struct {
     time_t mtime;
     time_t ctime;
 } times;
-    
+
+static struct Source overlay;
+
 #if DEBUG
 static void print_source(struct Source *p) {
     fprintf( stderr, "%p { %s, %ld, %ld, %ld, %d }\n",
@@ -67,6 +69,17 @@ static int RANGE(int s,int n ) {
     return ( s == n ) && *(range+c) == 0;
 }
 
+static void usage();
+
+static void setup_overlay(char *filename) {
+    overlay.filename = filename;
+    overlay.fd = open( filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
+    if ( overlay.fd < 0 ) {
+       perror( filename );
+       usage();
+    }
+}
+
 static int setup_sources(char **argv,int i,int n) {
     sources.array = calloc( n, sizeof( struct Source ) );
     if ( sources.array == 0 ) {
@@ -225,6 +238,53 @@ static int find_source(off_t offset) {
     return lo;
 }
 
+#define OBUFSZ 1048576
+static int overlay_merge(char *buf,off_t off,size_t size) {
+    static char obuf[ OBUFSZ ];
+#if DEBUG
+    fprintf( stderr, "merge %ld %ld\n", off, size );
+#endif
+    while ( size > 0 ) {
+       size_t n = size < OBUFSZ? size : OBUFSZ;
+       off_t ox = lseek( overlay.fd, off, SEEK_SET );
+#if DEBUG
+       fprintf( stderr, "  seek %ld %ld %ld\n", off, ox, n );
+#endif
+       if ( ox < 0 ) {
+           perror( overlay.filename );
+           return -ENOENT;
+       }
+       if ( ox < off ) {
+           break;
+       }
+       n = read( overlay.fd, obuf, n );
+#if DEBUG
+       fprintf( stderr, "  got %ld\n", n );
+#endif
+       if ( n < 0 ) {
+           perror( overlay.filename );
+            return -ENOENT;
+       }
+       if ( n == 0 ) {
+           break;
+       }
+       char *p = obuf;
+       while ( n-- > 0 ) {
+           if ( *p ) {
+               *buf = *p;
+           }
+           p++;
+           buf++;
+           size--;
+           off++;
+       }
+    }
+#if DEBUG
+    fprintf( stderr, "merged\n" );
+#endif
+    return 0;
+}
+
 // Read <size> bytes from <offset> in file
 static int fusefile_read(const char *path, char *buf, size_t size,
                         off_t off, struct fuse_file_info *fi)
@@ -271,6 +331,12 @@ static int fusefile_read(const char *path, char *buf, size_t size,
                 n, sources.array[i].fd );
 #endif
        ssize_t r = read( sources.array[i].fd, buf + rr, n );
+       if ( overlay.filename ) {
+           int x = overlay_merge( buf + rr, off + rr, r );
+           if ( x ) {
+               return x;
+           }
+       }
 #if DEBUG
        fprintf( stderr, "  got %ld bytes\n", r );
 #endif
@@ -322,7 +388,8 @@ static int write_block(off_t off,const char *buf,size_t size) {
        if ( index < 0 ) {
            return -EIO; // past EOF
        }
-       struct Source *source = &sources.array[ index ];
+       struct Source *source =
+           overlay.filename? &overlay : &sources.array[ index ];
        off_t from = off - source->start + source->from;
        off_t max = source->to - from;
        if ( lseek( source->fd, from, SEEK_SET ) < 0 ) {
@@ -539,9 +606,19 @@ int main(int argc, char *argv[])
     }
     fuseargc = i;
     mnt = argv[ i++ ]; // First non-option argument is the mount pount
+    char *overlaytag = "-overlay:";
+    int overlaytagsize = strlen( overlaytag );
+    if ( strncmp( argv[i], overlaytag, overlaytagsize ) == 0 ) {
+       // consume "-overlay:filename"
+       setup_overlay( argv[i++] + overlaytagsize ); // Need a writable file
+       if ( i >= argc ) {
+           usage();
+       }
+    }
     if ( setup_sources( argv, i, argc-i ) ) {
        return 1;
     }
+    overlay.to = sources.size; // Register total size.
     if ( stat( mnt, &stbuf ) == -1 ) {
        int fd = open( mnt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
        if ( fd < 0 ) {