X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=fusefile.c;h=99424c5fd8ea7f8b1247d404da41cd8be7f06280;hb=601bda51e02c3f5fe1b1590c583d34c19ed44d5c;hp=55ba86aae686986003fefb3b6e083abfb44d4b75;hpb=78348bed8433e7b7429ff4a0233b43ba614ac28d;p=rrq%2Ffusefile.git diff --git a/fusefile.c b/fusefile.c index 55ba86a..99424c5 100644 --- a/fusefile.c +++ b/fusefile.c @@ -34,6 +34,11 @@ #include #include +struct Region { + off_t pos; + size_t size; +}; + struct Source { char *filename; ssize_t from; @@ -45,7 +50,6 @@ struct Source { static struct { struct Source *array; int count; - int limit; ssize_t size; } sources; @@ -54,67 +58,145 @@ static struct { time_t mtime; time_t ctime; } times; - -#define SOURCEARRAYP(i) ((void*)&sources.array[ i ]) /** - * Holds info about scratch pad file for 'write' events. + * Overlay */ static struct { - char *filename; - int fd; -} pad; - -#if DEBUG -static void print_source(struct Source *p) { - fprintf( stderr, "%p { %s, %ld, %ld, %ld, %d }\n", - p, p->filename, p->from, p->to, p->start, p->fd ); + struct Source source; + struct Region *table; + size_t count; + size_t limit; +} overlay; + +#define FRAG(m) (overlay.table+m) +#define BEG(m) (FRAG(m)->pos) +#define END(m) (FRAG(m)->pos + FRAG(m)->size) + +static ssize_t overlay_prior_fragment(off_t pos) { + size_t lo = 0, hi = overlay.count; + while ( lo < hi ) { + size_t m = ( lo + hi ) / 2; + if ( m == lo ) { + return BEG( m ) < pos? m : -1; + } + if ( BEG( m ) <= pos ) { + lo = m; + } else { + hi = m; + } + } + return -1; } -#endif -// Scan the source specification, and return the length of the -// inclusion. "filename/from,to" -// filename -// filename/from -// filename/-to -// filename/from-to -static size_t scan_source(char *in,struct Source *p) { - int e = strlen( in ); - int i = e-1; - int s = -1; - int m = -1; - // scan for last '/' and last '-' - for ( ; i >= 0; i-- ) { - if ( in[i] == '/' ) { - s = i; - break; +static void overlay_save_count() { + lseek( overlay.source.fd, overlay.source.to, SEEK_SET ); + size_t size = sizeof( overlay.count ); + char *p = (char *) &overlay.count ; + while ( size > 0 ) { + size_t n = write( overlay.source.fd, p, size ); + if ( n < 0 ) { + perror( overlay.source.filename ); + exit( 1 ); } - if ( in[i] == '-' ) { - m = i; + size -= n; + p += n; + } +} + +static void overlay_save_table(size_t lo,size_t hi) { + char *p = (char *) FRAG(lo); + size_t pos = overlay.source.to + sizeof( overlay.count ) + + lo * sizeof( struct Region ); + size_t size = ( hi - lo ) * sizeof( struct Region ); + if ( pos != lseek( overlay.source.fd, pos, SEEK_SET ) ) { + fprintf( stderr, "%s: seek error\n", overlay.source.filename ); + exit( 1 ); + } + while ( size > 0 ) { + size_t n = write( overlay.source.fd, p, size ); + if ( n < 0 ) { + perror( overlay.source.filename ); + exit( 1 ); } + size -= n; + p += n; } -#if DEBUG - fprintf( stderr, "m=%d s=%d\n", m, s ); -#endif - // Copy the filename, and set from and to - p->filename = strndup( in, ( s < 0 )? e : s ); - struct stat buf; - if ( stat( p->filename, & buf ) ) { - perror( p->filename ); - return 1; +} + +static void overlay_insert(size_t p,off_t pos,size_t size) { + size_t bytes; + if ( overlay.count >= overlay.limit ) { + overlay.limit = overlay.count + 10; + bytes = overlay.limit * sizeof( struct Region ); + overlay.table = overlay.table? + realloc( overlay.table, bytes ) : malloc( bytes ); + } + bytes = ( overlay.count++ - p ) * sizeof( struct Region ); + if ( bytes ) { + memmove( FRAG( p+1 ), FRAG( p ), bytes ); + } + FRAG( p )->pos = pos; + FRAG( p )->size = size; + overlay_save_count(); +} + +static void overlay_delete(size_t p) { + if ( p < --overlay.count ) { + size_t size = ( overlay.count - p ) * sizeof( struct Region ); + memmove( FRAG(p), FRAG(p+1), size ); } - p->from = ( s < 0 )? 0 : atol( in+s+1 ); - if ( p->from < 0 ) { - p->from = 0; + overlay_save_count(); +} + +static void overlay_mark(off_t pos,size_t size) { + ssize_t p = overlay_prior_fragment( pos ); + if ( p >= 0 && pos <= END(p) ) { + // Merge new marks with fragment p + FRAG(p)->size = pos + size - BEG(p); + if ( p+1 < overlay.count && BEG(p+1) <= END(p) ) { + FRAG(p)->size = END(p+1) - BEG(p); + overlay_delete( p+1 ); + overlay_save_table( p, overlay.count ); + } else { + overlay_save_table( p, p+1 ); + } + return; + } + p++; // index of subsequent fragment + if ( p < overlay.count && BEG(p) < pos + size ) { + // Merge new marks with pragment p+1 + FRAG(p)->size = END(p) - pos; + FRAG(p)->pos = pos; + overlay_save_table( p, p+1 ); + } else { + overlay_insert( p, pos, size); + overlay_save_table( p, overlay.count ); } +} + #if DEBUG - fprintf( stderr, "p->from=%ld\n", p->from ); +static void print_source(struct Source *p) { + fprintf( stderr, "%p { %s, %ld, %ld, %ld, %d }\n", + p, p->filename, p->from, p->to, p->start, p-> fd ); +} #endif - p->to = ( m < 0 )? buf.st_size : atol( in+m+1 ); - if ( p->from > p->to || p->to > buf.st_size ) { - return 1; + +static char *range; +static unsigned int c; +static int RANGE(int s,int n ) { + return ( s == n ) && *(range+c) == 0; +} + +static void usage(); + +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 ); + usage(); } - return 0; } static int setup_sources(char **argv,int i,int n) { @@ -123,22 +205,78 @@ static int setup_sources(char **argv,int i,int n) { return 1; } sources.count = n; - sources.limit = n; int j = 0; sources.size = 0; for ( ; j < n; i++, j++ ) { + struct stat filestat; struct Source *p = sources.array + j; - if ( scan_source( argv[i], p ) ) { - // should free everything malloc-ed - return 1; + // Open the fragment file rw if possible, else ro + range = strrchr( argv[i], '/' ); // last '/' + p->filename = range? strndup( argv[i], range - argv[i] ) : argv[i]; + p->fd = open( p->filename, O_RDWR ); + int rdonly = 0; + if ( p->fd < 0 ) { + rdonly = 1; + p->fd = open( p->filename, O_RDONLY ); } - p->start = sources.size; - sources.size += p->to - p->from; - p->fd = open( p->filename, O_RDONLY ); if ( p->fd < 0 ) { perror( p->filename ); + return 1; // Error return + } + if ( stat( p->filename, &filestat ) ) { + perror( p->filename ); + return 1; + } + if ( rdonly ) { + fprintf( stderr, "** %s opened read-only\n", p->filename ); + } + p->from = 0; + p->to = filestat.st_size; + // Process any range variation + if ( range && *(++range) ) { + int a,b; + if ( 0 ) { + } else if ( RANGE( sscanf( range, "%d:%d%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 )) { + 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 )) { + p->from = ( a < 0 )? ( p->to + a ) : a; + } else if ( RANGE( sscanf( range, ":%d%n", &b, &c ), 1 )) { + p->to = ( b < 0 )? ( p->to + b ) : b; + } else if ( RANGE( sscanf( range, "%d:%n", &a, &c ), 1 )) { + p->from = ( a < 0 )? ( p->to + a ) : a; + } else if ( RANGE( sscanf( range, "%d%n", &a, &c ), 1 )) { + if ( a >= 0 ) { + p->from = a; + } else { + p->from = p->to + a; + } + } else if ( RANGE( sscanf( range, ":%n", &c), 0 ) ) { + // to end from start + } else { + fprintf( stderr, "** BAD RANGE: %s\n", argv[i] ); + return 1; + } + } + if ( ( filestat.st_mode & S_IFMT ) == S_IFCHR ) { + filestat.st_size = p->to; // Pretend size of character device + } + if ( p->from < 0 ) { + p->from = 0; + } + if ( p->to > filestat.st_size ) { + p->to = filestat.st_size; + } + if ( p->from >= p->to || p->from >= filestat.st_size ) { + fprintf( stderr, "** BAD RANGE: %s [%ld:%ld]\n", + argv[i], p->from, p->to ); return 1; } + p->start = sources.size; // the fusefile position of fragment + sources.size += p->to - p->from; #if DEBUG print_source( p ); #endif @@ -157,10 +295,7 @@ static int fusefile_getattr(const char *path,struct stat *stbuf) { fprintf( stderr, "getattr %ld\n", sources.size ); #endif memset( stbuf, 0, sizeof( struct stat ) ); - stbuf->st_mode = S_IFREG | 0444; // Hmmm - if ( pad.filename ) { - stbuf->st_mode |= 0200; - } + stbuf->st_mode = S_IFREG | 0644; // Hmmm stbuf->st_nlink = 1; stbuf->st_size = sources.size; stbuf->st_atime = times.atime; @@ -171,6 +306,13 @@ static int fusefile_getattr(const char *path,struct stat *stbuf) { return 0; } +static int fusefile_chmod(const char *path,mode_t m) { +#if DEBUG + fprintf( stderr, "fusefile_chmod( %s, %d )\n", path, m ); +#endif + return -1; +} + static int fusefile_open(const char *path,struct fuse_file_info *fi) { #if DEBUG fprintf( stderr, "fusefile_open( %s, %d )\n", path, fi->flags ); @@ -187,108 +329,92 @@ static int fusefile_open(const char *path,struct fuse_file_info *fi) { static int find_source(off_t offset) { int lo = 0; int hi = sources.count; - if ( offset > sources.size ) { + 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; } -/** - * Insert a source fragment description into the table at . - */ -static int insert_source(struct Source *source,size_t off) { - int index = find_source( off ); - int i; - // Ensure at least 5 "free" Sources in - // and allocate space for 20 new otherwise. - if ( sources.count + 5 > sources.limit ) { - size_t size = sources.limit + 20; - struct Source *new = realloc( - sources.array, size * sizeof( struct Source ) ); - if ( new == 0 ) { - return -1; - } - sources.array = new; - sources.limit = size; - } +static int overlay_merge(char *buf,off_t off,size_t size) { #if DEBUG - fprintf( stderr, "index=%d\n", index ); -#endif - if ( index < sources.count ) { - ssize_t b = ( sources.count - index ) * sizeof(struct Source); -#if DEBUG - fprintf( stderr, "b=%ld\n", b ); -#endif - if ( sources.array[ index ].start < off ) { - // Split the record at - // and adjust index - memcpy( SOURCEARRAYP( index+2 ), SOURCEARRAYP( index ), b ); - sources.count += 2; - b = off - sources.array[ index ].start; - sources.array[ index + 2 ].from += b; // adjust tail fragment - sources.array[ index++ ].to = b; // adjust head fragment -#if DEBUG - print_source( &sources.array[ index-1 ] ); - print_source( &sources.array[ index ] ); - print_source( &sources.array[ index+1 ] ); - fprintf( stderr, "---\n"); + fprintf( stderr, "merge %ld %ld\n", off, size ); #endif + // Find nearest overlay data before or at off + ssize_t p = overlay_prior_fragment( off ); + if ( p < 0 ) { + p = 0; + } + for ( ; p < overlay.count && BEG(p) < off+size; p++ ) { + size_t delta = FRAG(p)->size; + if ( BEG(p) > off ) { + size_t skip = BEG(p) - off; + off += skip; + size -= skip; + buf += skip; } else { - // Insert the new source at - memcpy( SOURCEARRAYP( index+1 ), SOURCEARRAYP( index ), b ); - sources.count += 1; + delta = off - BEG(p); + } + if ( delta > size ) { + delta = size; + } + lseek( overlay.source.fd, off, SEEK_SET ); + while ( delta > 0 ) { + size_t n = read( overlay.source.fd, buf, delta ); + off += n; + size -= n; + delta -= n; + buf += n; } - } else { - // Append the new source to (at ) - sources.count += 1; - } - sources.array[ index ].filename = source->filename; - sources.array[ index ].fd = source->fd; - sources.array[ index ].from = source->from; - sources.array[ index ].to = source->to; - for ( i = index; i < sources.count; i++ ) { - sources.array[ i ].start = off; - off += sources.array[ i ].to - sources.array[ i ].from; -#if DEBUG - print_source( &sources.array[ i ] ); -#endif } - sources.size = off; #if DEBUG - fprintf( stderr, "count=%d size=%ld\n", sources.count, sources.size ); + fprintf( stderr, "merged\n" ); #endif - return index; + return 0; } -// Read bytes from in file +// Read bytes from in file 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 ) { + if( strcmp( path, "/" ) != 0 ) { return -ENOENT; } #if DEBUG fprintf( stderr, "read %ld %ld\n", off, size ); #endif - size_t rr = 0; + size_t rr = 0; // total reading while ( size > 0 ) { #if DEBUG - fprintf( stderr, "find_source %ld %ld\n", off, size ); + fprintf( stderr, " find_source %ld %ld\n", off, size ); #endif int i = find_source( off ); if ( i < 0 ) { - return -ENOENT; + return ( off == sources.size )? rr : -ENOENT; } if ( sources.array[i].fd < 0 ) { return -ENOENT; @@ -296,21 +422,32 @@ static int fusefile_read(const char *path, char *buf, size_t size, #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; if ( n > size ) { n = size; } +#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, "get %ld bytes at %ld\n", n, rr ); + 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 ( overlay.source.filename ) { + int x = overlay_merge( buf + rr, off + rr, r ); + if ( x ) { + return x; + } + } #if DEBUG - fprintf( stderr, "got %ld bytes\n", r ); + fprintf( stderr, " got %ld bytes\n", r ); #endif if ( r < 0 ) { perror( sources.array[i].filename ); @@ -323,24 +460,93 @@ static int fusefile_read(const char *path, char *buf, size_t size, off += r; size -= r; } - times.atime = time( 0 ); +#if DEBUG + fprintf( stderr, " total reading %ld bytes\n", rr ); +#endif return rr; } /** - * Write a full block of data. + * Poll for IO readiness. + */ +int fusefile_poll(const char *path, struct fuse_file_info *fi, + struct fuse_pollhandle *ph, unsigned *reventsp ) +{ +#if DEBUG + fprintf( stderr, "fusefile_poll( %s ) %p %d\n", path, ph, *reventsp ); +#endif + if( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + if ( ph ) { + return fuse_notify_poll( ph ); + } + return 0; +} + +static void overlay_load() { + lseek( overlay.source.fd, overlay.source.to, SEEK_SET ); + size_t x = 0; + size_t size = sizeof( overlay.count ); + if ( read( overlay.source.fd, &x, size ) != size ) { + return; + } +#if DEBUG + fprintf( stderr, "overlay: %s with %ld regions\n", + overlay.source.filename, x ); +#endif + struct Region f = { 0, 0 }; + size = sizeof( struct Region ); + while ( x-- > 0 ) { + if ( read( overlay.source.fd, &f, size ) != size ) { + fprintf( stderr, "%s: bad meta data\n", overlay.source.filename ); + exit( 1 ); + } +#if DEBUG + fprintf( stderr, "overlay region: %ld %ld\n", f.pos, f.size ); +#endif + overlay_mark( f.pos, f.size ); + } +} + +/** + * Write a full block of data over the sources at the offset */ -static int write_block(int fd,const char *buf,size_t size) { - size_t orig = size; +static int write_block(off_t off,const char *buf,size_t size) { +#if DEBUG + fprintf( stderr, "write_block( %ld, ?, %ld )\n", off, size ); +#endif while ( size > 0 ) { - ssize_t n = write( fd, buf, size ); - if ( n <= 0 ) { - return n; + int index = find_source( off ); // index of source file + if ( index < 0 ) { + return -EIO; // past EOF + } + struct Source *source; + if ( overlay.source.filename ) { + source = &overlay.source; + overlay_mark( off, size ); // Mark region as written + } else { + source = &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 ) { + return -EIO; + } + ssize_t todo = ( size < max )? size : max; + while ( todo > 0 ) { + times.mtime = time( 0 ); + ssize_t n = write( source->fd, buf, todo ); + if ( n <= 0 ) { + return -EIO; // Something wrong + } + buf += n; + todo -= n; + size -= n; + off += n; } - buf += n; - size -= n; } - return orig; + return 0; } static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf, @@ -351,38 +557,9 @@ static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf, if ( strcmp( path, "/" ) != 0 ) { return -ENOENT; } - - // Ensure a pad was nominated - if ( pad.filename == 0 ) { - return 1; - } - // Determine total size size_t size = 0; int i; -#if DEBUG - fprintf( stderr, "count = %ld\n", buf->count ); -#endif - for ( i = 0; i < buf->count; i++ ) { - struct fuse_buf *p = &buf->buf[ i ]; - size += p->size; - } - static char meta[ 100 ]; - sprintf( meta, "%ld\n%ld\n", off, size ); -#if DEBUG - fprintf( stderr, "meta( %ld %ld )\n", off, size ); -#endif - if ( write_block( pad.fd, meta, strlen( meta ) ) <= 0 ) { - perror( pad.filename ); - return -EIO; - } - struct Source source = { - .filename = pad.filename, - .fd = pad.fd, - .from = lseek( pad.fd, 0, SEEK_END ), - .to = 0, - .start = 0 - }; for ( i = 0; i < buf->count; i++ ) { struct fuse_buf *p = &buf->buf[i]; if ( p->flags & FUSE_BUF_IS_FD ) { @@ -390,24 +567,20 @@ static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf, fprintf( stderr, "Content held in a file ... HELP!!\n" ); #endif return -EIO; - } else { - ssize_t n = write_block( pad.fd, (char*) p->mem, p->size ); - if ( n != p->size ) { - return -EIO; - } } + if ( write_block( off, (char*) p->mem, p->size ) < 0 ) { + return -EIO; + } + size += p->size; } - source.to = source.from + size; - insert_source( &source, off ); - times.mtime = time( 0 ); +#if DEBUG + fprintf( stderr, "fusefile_write_buf written %ld\n", size ); +#endif return size; } /** - * Insert a fragment at . The data is appended to the pad file, - * and a descriptor is inserted; the fragment containing is - * first split, unless is at its start, and then new fragment - * descriptor is inserted. + * Write a fragment at . This overwrites files. */ static int fusefile_write(const char *path, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) @@ -419,30 +592,9 @@ static int fusefile_write(const char *path, const char *buf, size_t size, return -ENOENT; } - // Ensure a pad was nominated - if ( pad.filename == 0 ) { - return 1; - } - static char meta[ 100 ]; - sprintf( meta, "%ld\n%ld\n", off, size ); - if ( write_block( pad.fd, meta, strlen( meta ) ) <= 0 ) { - perror( pad.filename ); + if ( write_block( off, buf, size ) < 0 ) { return -EIO; } - struct Source source = { - .filename = pad.filename, - .fd = pad.fd, - .from = lseek( pad.fd, 0, SEEK_END ), - .to = 0, - .start = 0 - }; - ssize_t n = write_block( pad.fd, buf, size ); - if ( n != size ) { - return n; - } - source.to = source.from + size; - insert_source( &source, off ); - times.mtime = time( 0 ); return size; } @@ -499,10 +651,25 @@ static int fusefile_truncate(const char *path, off_t len) { return -EIO; } +void *fusefile_init(struct fuse_conn_info *fci) { +#if DEBUG + fprintf( stderr, "fusefile_init( %d, %d )\n", fci->async_read, fci->want ); +#endif + // Disable asynchronous reading + fci->async_read = 0; + fci->want &= ~FUSE_CAP_ASYNC_READ; +#if DEBUG + fprintf( stderr, "fusefile_init( %d, %d )\n", fci->async_read, fci->want ); +#endif + return 0; +} + static struct fuse_operations fusefile_oper = { .getattr = fusefile_getattr, + .chmod = fusefile_chmod, .open = fusefile_open, .read = fusefile_read, + .poll = fusefile_poll, .write = fusefile_write, .write_buf = fusefile_write_buf, .destroy = fusefile_destroy, @@ -512,13 +679,13 @@ static struct fuse_operations fusefile_oper = { .truncate = fusefile_truncate, //.truncate = fusefile_truncate, //.release = fusefile_release, - //void *(*init) (struct fuse_conn_info *conn); + .init = fusefile_init, }; static void usage() { char *usage = "Usage: fusefile [ ] ... \n" -"Mounts a virtual, read-only file that is a concatenation of file fragments\n" +"Mounts a virtual, file that is a concatenation of file fragments\n" ; fprintf( stderr, "%s", usage ); exit( 1 ); @@ -526,15 +693,31 @@ static void usage() { /** * Set up the arguments for the fuse_main call, adding our own. + * argv[argc] is the mount point argument */ static int setup_argv(int argc,char ***argv) { - int n = argc + 1; - char **out = calloc( n--, sizeof( char* ) ); - memcpy( (void*) out, (void*) (*argv), argc-- * sizeof( char* ) ); - out[ n++ ] = out[ argc ]; // mount point - out[ argc++ ] = "-odefault_permissions"; + // note: (*argv)[ argc ] is the mount point argument + char *OURS[] = { + "-odefault_permissions", + (*argv)[ argc ] + }; +#define OURSN ( sizeof( OURS ) / sizeof( char* ) ) + int N = argc + OURSN; + // Allocate new arg array plus terminating null pointer + char **out = malloc( ( N + 1 ) * sizeof( char* ) ); + int i; + for ( i = 0; i < argc; i++ ) { + out[ i ] = (*argv)[i]; + //fprintf( stderr, " %s", out[ i ] ); + } + for ( i = 0; i < OURSN; i++ ) { + out[ argc + i ] = OURS[i]; + //fprintf( stderr, " %s", out[ i ] ); + } + out[ N ] = 0; + //fprintf( stderr, "\n" ); (*argv) = out; - return n; + return N; // Don't include the terminating null pointer } /** @@ -559,24 +742,24 @@ int main(int argc, char *argv[]) if ( i > argc - 2 ) { // At least mount point plus one source usage(); } - mnt = argv[ i++ ]; // First non-option argument is the mount pount fuseargc = i; - if ( strncmp( argv[ i ], "pad=", 4 ) == 0 ) { - // First argument is the pad, if any, signaled with "pad=" prefix - pad.filename = argv[ i++ ] + 4; // (also move arg index) -#if DEBUG - fprintf( stderr, "scratch pad=%s\n", pad.filename ); -#endif - pad.fd = open( pad.filename, O_RDWR | O_CREAT, 0600 ); - if ( pad.fd < 0 ) { - perror( pad.filename ); - exit( errno ); + 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(); } - lseek( pad.fd, 0, SEEK_END ); // initial seek } if ( setup_sources( argv, i, argc-i ) ) { return 1; } + if ( overlay.source.filename ) { + overlay.source.to = sources.size; // Register total size. + overlay_load(); + } if ( stat( mnt, &stbuf ) == -1 ) { int fd = open( mnt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR ); if ( fd < 0 ) { @@ -598,6 +781,16 @@ int main(int argc, char *argv[]) times.ctime = stbuf.st_ctime; } + { + int fd = open( mnt, O_RDWR, S_IRUSR | S_IWUSR ); + if ( fd < 0 ) { + perror( mnt ); + return 1; + } + if ( lseek( fd, sources.size, SEEK_SET ) < 0 ) { + return -EIO; + } + } fuseargc = setup_argv( fuseargc, &argv ); struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv ); if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) {