X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=fusefile.c;h=ab97ff7f0f50c8902066075c2df1951f5c9fdb31;hb=f1bd0ce70cdde903b79e1fb1ab2f895a674b5a6e;hp=5f7850ba106e2dd9d60278d9bfc2ceb5208f3070;hpb=0df8fcce46695d24edea6218bb460cce0818b0d0;p=rrq%2Ffusefile.git diff --git a/fusefile.c b/fusefile.c index 5f7850b..ab97ff7 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 @@ -295,8 +310,14 @@ static int RANGE(int s,int n ) { static int setup_source(struct Source *p,char *frag) { struct stat filestat; // Open the fragment file rw if possible, else ro - range = strrchr( frag, '/' ); // last '/' - p->filename = range? strndup( frag, range - frag ) : frag; + // First try the fragment in full, thereafter with range appendix + if ( stat( frag, &filestat ) == 0 ) { + p->filename = strdup( frag ); + range = 0; + } else { + range = strrchr( frag, '/' ); // last '/' + p->filename = range? strndup( frag, range - frag ) : frag; + } p->fd = open( p->filename, O_RDWR ); int rdonly = 0; if ( p->fd < 0 ) { @@ -307,7 +328,7 @@ static int setup_source(struct Source *p,char *frag) { perror( p->filename ); return 1; // Error return } - if ( stat( p->filename, &filestat ) ) { + if ( ( range == 0 ) && stat( p->filename, &filestat ) ) { perror( p->filename ); return 1; } @@ -327,21 +348,21 @@ static int setup_source(struct Source *p,char *frag) { p->to = filestat.st_size; // Process any range variation if ( range && *(++range) ) { - int a,b; + long int a,b; if ( 0 ) { - } else if ( RANGE( sscanf( range, "%d:%d%n", &a, &b, &c ), 2 )) { + } else if ( RANGE( sscanf( range, "%ld:%ld%n", &a, &b, &c ), 2 )) { p->from = ( a < 0 )? ( p->to + a ) : a; p->to = ( b < 0 )? ( p->to + b ) : b; - } else if ( RANGE( sscanf( range, "%d+%d%n", &a, &b, &c ), 2 )) { + } else if ( RANGE( sscanf( range, "%ld+%ld%n", &a, &b, &c ), 2 )) { p->from = ( a < 0 )? ( p->to + a ) : a; p->to = ( ( b < 0 )? p->to : p->from ) + b; - } else if ( RANGE( sscanf( range, "%d+%n", &a, &c ), 1 )) { + } else if ( RANGE( sscanf( range, "%ld+%n", &a, &c ), 1 )) { p->from = ( a < 0 )? ( p->to + a ) : a; - } else if ( RANGE( sscanf( range, ":%d%n", &b, &c ), 1 )) { + } else if ( RANGE( sscanf( range, ":%ld%n", &b, &c ), 1 )) { p->to = ( b < 0 )? ( p->to + b ) : b; - } else if ( RANGE( sscanf( range, "%d:%n", &a, &c ), 1 )) { + } else if ( RANGE( sscanf( range, "%ld:%n", &a, &c ), 1 )) { p->from = ( a < 0 )? ( p->to + a ) : a; - } else if ( RANGE( sscanf( range, "%d%n", &a, &c ), 1 )) { + } else if ( RANGE( sscanf( range, "%ld%n", &a, &c ), 1 )) { if ( a >= 0 ) { p->from = a; } else { @@ -620,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 */ @@ -711,6 +837,40 @@ static int fusefile_write(const char *path, const char *buf, size_t size, return size; } +#define PUSHBUF 104857600 +/** + * Write data from overlay to source. + */ +static void push_oly(off_t beg, off_t end) { + static char * buffer = 0; + // Pretend that there isn't an overlay + char *filename = overlay.source.filename; + if ( buffer == 0 ) { + buffer = malloc( PUSHBUF ); + if ( buffer == 0 ) { + fprintf( stderr, "** OOM!!\n" ); + exit( 1 ); + } + } + overlay.source.filename = 0; + while ( beg < end ) { + off_t size = end - beg; + if ( size > PUSHBUF ) { + size = PUSHBUF; + } + if ( lseek( overlay.source.fd, beg, SEEK_SET ) < 0 ) { + fprintf( stderr, "** Cannot seek overlay at %ld\n", beg ); + break; + } + size = read( overlay.source.fd, buffer, size ); + if ( write_block( beg, buffer, size ) < 0 ) { + fprintf( stderr, "** Cannot push %ld bytes at %ld\n", size, beg ); + } + beg += size; + } + overlay.source.filename = filename; +} + static void fusefile_destroy(void *data) { char *mnt = (char*) data; // As passed to fuse_main #if DEBUG @@ -793,12 +953,10 @@ 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. */ -static int dump_fragments() { +static int dump_fragments(int push) { int oly = 0; int src = 0; size_t pos = 0; @@ -808,25 +966,33 @@ static int dump_fragments() { for ( ; src < sources.count && ENDSOURCE( sources.array[ src ] ) <= x; src++ ) { // Dump sources.array[src] in full - fprintf( stdout, "%s/%ld:%ld\n", - sources.array[ src ].filename, - pos - sources.array[ src ].start, - sources.array[ src ].to ); + if ( !push ) { + fprintf( stdout, "%s/%ld:%ld\n", + sources.array[ src ].filename, + pos - sources.array[ src ].start, + sources.array[ src ].to ); + } pos = ENDSOURCE( sources.array[ src ] ); } - if ( sources.array[ src ].start < x ) { + if ( ( src < sources.count ) && ( sources.array[ src ].start < x ) ) { // Dump sources.array[src] up to x; - fprintf( stdout, "%s/%ld:%ld\n", - sources.array[ src ].filename, - pos - sources.array[ src ].start, - x - sources.array[ src ].start ); + if ( !push ) { + fprintf( stdout, "%s/%ld:%ld\n", + sources.array[ src ].filename, + pos - sources.array[ src ].start, + x - sources.array[ src ].start ); + } pos = ENDSOURCE( sources.array[ src ] ); } if ( oly < overlay.count ) { - fprintf( stdout, "%s/%ld:%ld\n", - overlay.source.filename, - overlay.table[ oly ].beg, - overlay.table[ oly ].end ); + if ( !push ) { + fprintf( stdout, "%s/%ld:%ld\n", + overlay.source.filename, + overlay.table[ oly ].beg, + overlay.table[ oly ].end ); + } else { + push_oly( overlay.table[ oly ].beg, overlay.table[ oly ].end ); + } pos = overlay.table[ oly++ ].end; } for ( ; src < sources.count && @@ -920,11 +1086,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 + #define OVERLAYTAG "-overlay:" + if ( strncmp( argv[i], OVERLAYTAG, strlen( OVERLAYTAG ) ) == 0 ) { + // consume "-overlay:filename[,filename]*" + overlay_setup( argv[i++] + strlen( OVERLAYTAG ) ); if ( i >= argc ) { usage(); } @@ -934,7 +1099,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 ); @@ -969,7 +1134,10 @@ int main(int argc, char *argv[]) } fuseargc = setup_argv( fuseargc, &argv ); if ( strcmp( "-dump", argv[ 1 ] ) == 0 ) { - return dump_fragments(); + return dump_fragments( 0 ); + } + if ( strcmp( "-push", argv[ 1 ] ) == 0 ) { + return dump_fragments( 1 ); } struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv ); if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) {