X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=fusefile.c;h=a1bf2bd926792844ecee3c989dd131da641d69e2;hb=HEAD;hp=37f8a2c0448de17eb35174090fdae01393cdbcec;hpb=5101a793944fe2285cd5077897bc15c3f1681349;p=rrq%2Ffusefile.git diff --git a/fusefile.c b/fusefile.c index 37f8a2c..a1bf2bd 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,25 @@ 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(); } + // copy elements from [index] to [count-1] one element down + size_t size = ( sources.count - index - 1 ) * sizeof( struct Source ); + memmove( &sources.array[ index+1 ], &sources.array[ index ], size ); } #if DEBUG @@ -313,7 +329,7 @@ static int setup_source(struct Source *p,char *frag) { perror( p->filename ); return 1; // Error return } - if ( ( range == 0 ) && stat( p->filename, &filestat ) ) { + if ( ( range != 0 ) && stat( p->filename, &filestat ) ) { perror( p->filename ); return 1; } @@ -447,28 +463,14 @@ static int find_source(off_t offset) { if ( offset >= sources.size ) { return -1; } -#if DEBUG - fprintf( stderr, "find_source( %ld )\n", offset ); -#endif while ( lo + 1 < hi ) { int m = ( lo + hi ) / 2; if ( offset < sources.array[ m ].start ) { -#if DEBUG - fprintf( stderr, " offset < [%d].start: %ld\n", - m, sources.array[ m ].start ); -#endif hi = m; } else { -#if DEBUG - fprintf( stderr, " offset >= [%d].start: %ld\n", - m, sources.array[ m ].start ); -#endif lo = m; } } -#if DEBUG - fprintf( stderr, "found %d\n", lo ); -#endif return lo; } @@ -507,30 +509,25 @@ static int overlay_merge(char *buf,off_t beg,off_t end) { static int fusefile_read(const char *path, char *buf, size_t size, off_t off, struct fuse_file_info *fi) { -#if DEBUG - fprintf( stderr, "fusefile_read( %s )\n", path ); -#endif if( strcmp( path, "/" ) != 0 ) { return -ENOENT; } -#if DEBUG - fprintf( stderr, "read %ld %ld\n", off, size ); -#endif size_t rr = 0; // total reading - while ( size > 0 ) { #if DEBUG - fprintf( stderr, " find_source %ld %ld\n", off, size ); + fprintf( stderr, "fusefile_read %ld + %ld\n", off, size ); #endif + while ( size > 0 ) { int i = find_source( off ); if ( i < 0 ) { return ( off == sources.size )? rr : -ENOENT; } +#if DEBUG + fprintf( stderr, " item: %d ", i ); + print_source(& sources.array[i] ); +#endif if ( sources.array[i].fd < 0 ) { return -ENOENT; } -#if DEBUG - print_source( &sources.array[i] ); -#endif times.atime = time( 0 ); size_t b = off - sources.array[i].start + sources.array[i].from; size_t n = sources.array[i].to - b; @@ -541,20 +538,13 @@ static int fusefile_read(const char *path, char *buf, size_t size, fsync( sources.array[i].fd ); sources.array[i].dirty = 0; } -#if DEBUG - fprintf( stderr, " seek fd=%d to %ld\n", sources.array[i].fd, b ); -#endif if ( lseek( sources.array[i].fd, b, SEEK_SET ) < 0 ) { perror( sources.array[i].filename ); return -ENOENT; } -#if DEBUG - fprintf( stderr, " now read %ld from fd=%d\n", - n, sources.array[i].fd ); -#endif ssize_t r = read( sources.array[i].fd, buf + rr, n ); #if DEBUG - fprintf( stderr, " got %ld bytes\n", r ); + fprintf( stderr, " got: %ld bytes of %ld at %ld\n", r, n, rr ); #endif if ( r < 0 ) { perror( sources.array[i].filename ); @@ -626,6 +616,145 @@ 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, end }, + { end, ENDSOURCE( sources.array[ index ] ) } }; +#if DEBUG + int i; + for ( i = 0; i < 3; i++ ) { + fprintf( stderr, "frags[%d] = (%ld, %ld)\n", + i, frags[i].beg, frags[i].end ); + } +#endif + ssize_t size = frags[0].end - frags[0].beg; + if ( size ) { + // Handle any portion before injection point. + dup_source_item( index ); + off_t point = sources.array[ index ].from + size; + sources.array[ index ].to = point; +#if DEBUG + fprintf( stderr, "item %d ", index ); + print_source( &sources.array[ index ] ); +#endif + // Adjust item after injection point + index++; + sources.array[ index ].start = beg; + sources.array[ index ].from = point; +#if DEBUG + fprintf( stderr, "item %d adjust ", index ); + print_source( &sources.array[ index ] ); +#endif + } + size = frags[2].end - frags[2].beg; + if ( size ) { + // Handle any remaining portion following injection fragment + dup_source_item( index ); + sources.array[ index+1 ].start = frags[2].beg; + sources.array[ index+1 ].from += frags[1].end - frags[1].beg; +#if DEBUG + fprintf( stderr, "item %d ", index+1 ); + print_source( &sources.array[ index+1 ] ); +#endif + } + // Set up the injection fragment + sources.array[ index ].filename = overlay.source.filename; + sources.array[ index ].from = beg; + sources.array[ index ].to = end; + sources.array[ index ].fd = overlay.source.fd; +#if DEBUG + fprintf( stderr, "item %d ", index ); + print_source( &sources.array[ index ] ); +#endif + 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 ); + size_t n; + if ( ( n = read( overlay.source.fd, &count, size ) ) != size ) { + if ( n != 0 ) { + fprintf( stderr, "** error injecting %s\n", + overlay.source.filename ); + usage(); + } + fprintf( stderr, "** ignoring empty %s\n", overlay.source.filename ); + } + 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 ) { +#if DEBUG + fprintf( stderr, "inject [%ld,%ld] ", beg, overlay.table[i].end ); + print_source( &overlay.source ); +#endif + + beg = overlay_inject_from_region( beg, overlay.table[i].end ); + } + } + free( overlay.table ); + overlay.table = 0; +} + +/** + * 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 */ @@ -676,7 +805,6 @@ static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf, if ( strcmp( path, "/" ) != 0 ) { return -ENOENT; } - size_t size = 0; int i; for ( i = 0; i < buf->count; i++ ) { @@ -717,6 +845,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 @@ -799,12 +961,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; @@ -814,25 +974,37 @@ 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 ].from, + 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, + sources.array[ src ].from + + pos - sources.array[ src ].start, + x - sources.array[ src ].start + + sources.array[ src ].from + ); + } 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 && @@ -881,6 +1053,7 @@ static int setup_argv(int argc,char ***argv) { // note: (*argv)[ argc ] is the mount point argument char *OURS[] = { "-odefault_permissions", + //"-s", // Forced single-threading (*argv)[ argc ] }; #define OURSN ( sizeof( OURS ) / sizeof( char* ) ) @@ -926,11 +1099,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(); } @@ -940,7 +1112,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 ); @@ -975,7 +1147,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 ) ) {