From 79ad3ccaefe9383207f11e32cb324b88f0086137 Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Sat, 12 Aug 2023 11:31:13 +1000 Subject: [PATCH] added stacked overlays --- fusefile.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 15 deletions(-) diff --git a/fusefile.c b/fusefile.c index 9e5cb45..e05b90e 100644 --- a/fusefile.c +++ b/fusefile.c @@ -41,6 +41,8 @@ struct Region { off_t end; }; +#define REGIONKEEP(r) ((r,beg == r.end)?: 0 : 1) + struct Source { char *filename; ssize_t from; @@ -50,6 +52,8 @@ struct Source { int dirty; }; +#define ENDSOURCE( S ) ( S.start + ( S.to - S.from ) ) + static struct { struct Source *array; int count; @@ -65,12 +69,12 @@ static struct { /** * Overlay */ -static struct { +static struct Overlay { struct Source source; struct Region *table; size_t count; size_t limit; -} overlay; +} overlay; // The current overlay. static void usage(); @@ -270,13 +274,24 @@ static void overlay_mark(off_t beg,off_t end) { #endif } -static void setup_overlay(char *filename) { - overlay.source.filename = filename; - overlay.source.fd = open( filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ); - if ( overlay.source.fd < 0 ) { - perror( filename ); +/** + * Capture overlay filenames for processing after source fragments. + */ +static void overlay_setup(char *filenames) { + overlay.source.filename = filenames; +} + +// Duplicate the source record data at the given index. +static void dup_source_item(int index) { + sources.count++; + sources.array = realloc( + sources.array, sources.count * sizeof( struct Source ) ); + if ( sources.array == 0 ) { + fprintf( stderr, "** OOM when expanding frament table\n" ); usage(); } + memcpy( &sources.array[ index+1 ], &sources.array[ index ], + sizeof( struct Source ) ); } #if DEBUG @@ -626,6 +641,111 @@ static void overlay_load() { } } +/** + * Inject an overlay fragment into the source table, end return the + * end of the injected fragment. + */ +static off_t overlay_inject_from_region(off_t beg,off_t end) { + int index = find_source( beg ); + if ( index < 0 ) { + fprintf( stderr, "** Injecting %s at %ld failed\n", + overlay.source.filename, beg ); + usage(); + } + if ( end > ENDSOURCE( sources.array[ index ] ) ) { + end = ENDSOURCE( sources.array[ index ] ); + } + struct Region frags[3] = { + { sources.array[ index ].start, beg }, + { beg, ENDSOURCE( sources.array[ index ] ) }, + { ENDSOURCE( sources.array[ index ] ), end } }; + ssize_t size = frags[0].end - frags[0].beg; + if ( size ) { + // "Duplicate" the indexed source data, copying the filename + dup_source_item( index ); + sources.array[ index ].to = sources.array[ index ].from + size; + index++; + sources.array[ index ].start = beg; + sources.array[ index ].from = sources.array[ index-1 ].to; + } + size = frags[2].end - frags[2].beg; + if ( size ) { + dup_source_item( index ); + sources.array[ index+1 ].start = frags[2].beg; + sources.array[ index+1 ].from = sources.array[ index+1 ].to -size; + } + // Replace the [index] fragment + sources.array[ index ].filename = overlay.source.filename; + sources.array[ index ].start = beg; + sources.array[ index ].from = beg; + sources.array[ index ].to = end; + sources.array[ index ].fd = overlay.source.fd; //? + return end; +} + +/** + * Inject the current (unopened) overlay into the source list. + */ +static void overlay_inject() { + overlay.source.fd = open( overlay.source.filename, O_RDONLY ); + if ( overlay.source.fd < 0 ) { + perror( overlay.source.filename ); + usage(); + } + + if ( lseek( overlay.source.fd, overlay.source.to, SEEK_SET ) < 0 ) { + perror( overlay.source.filename ); + usage(); + } + size_t count = 0; + size_t size = sizeof( overlay.count ); + if ( read( overlay.source.fd, &count, size ) != size ) { + fprintf( stderr, "** error injecting %s\n", overlay.source.filename ); + usage(); + } + if ( count == 0 ) { + close( overlay.source.fd ); + return; + } + size = count * sizeof( struct Region ); + overlay.table = calloc( sizeof( struct Region ), count ); + if ( read( overlay.source.fd, overlay.table, size ) != size ) { + fprintf( stderr, "** error injecting %s\n", overlay.source.filename ); + usage(); + } + size_t i; + for ( i = 0; i < count; i++ ) { + off_t beg = overlay.table[i].beg; + while ( beg < overlay.table[i].end ) { + beg = overlay_inject_from_region( beg, overlay.table[i].end ); + } + } + free( overlay.table ); + overlay.table = 0; + close( overlay.source.fd ); +} + +/** + * Each stacked overlay file is nested into to source list + */ +static void overlay_post_setup() { + char *end; + while ( ( end = strchr( overlay.source.filename, ':' ) ) ) { + *end = 0; // + overlay_inject(); + overlay.source.filename = end + 1; + } + if ( *overlay.source.filename ) { + overlay.source.fd = open( overlay.source.filename, + O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ); + if ( overlay.source.fd < 0 ) { + perror( overlay.source.filename ); + usage(); + } + overlay_load(); + } +} + /** * Write a full block of data over the sources at the offset */ @@ -799,8 +919,6 @@ void *fusefile_init(struct fuse_conn_info *fci) { return 0; } -#define ENDSOURCE( S ) ( S.start + ( S.to - S.from ) ) - /** * Dump the current fragmentation to stdout. */ @@ -926,11 +1044,10 @@ 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 ( strcmp( argv[i], "-overlay:" ) == 0 ) { + // consume "-overlay:filename[,filename]*" + // Verify file access; to overlay must be writable. + overlay_setup( argv[i++] + strlen( "-overlay:" ) ); if ( i >= argc ) { usage(); } @@ -940,7 +1057,7 @@ int main(int argc, char *argv[]) } if ( overlay.source.filename ) { overlay.source.to = sources.size; // Register total size. - overlay_load(); + overlay_post_setup(); } if ( stat( mnt, &stbuf ) == -1 ) { int fd = open( mnt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR ); -- 2.39.2