X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=fusefile.c;h=f886287b3f806bd70da4cc7fa9830a55b5fe0f21;hb=7c1ade7a255ff7f3ded7865c013e34e1bb29139b;hp=eeb0e72789f1e322b52419b2fcd04ebf3b995fc1;hpb=36b31903885b6fac4989334f53d207ac184123d9;p=rrq%2Ffusefile.git diff --git a/fusefile.c b/fusefile.c index eeb0e72..f886287 100644 --- a/fusefile.c +++ b/fusefile.c @@ -1,8 +1,8 @@ /*** fusefile - overlay a file path with a concatenation of parts of - other files, read only. + other files. - Copyright (C) 2019 Ralph Ronnquist + Copyright (C) 2019- Ralph Ronnquist This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -290,6 +290,78 @@ static int RANGE(int s,int n ) { return ( s == n ) && *(range+c) == 0; } +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; + p->fd = open( p->filename, O_RDWR ); + int rdonly = 0; + if ( p->fd < 0 ) { + rdonly = 1; + 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", frag ); + 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", + frag, p->from, p->to ); + return 1; + } + p->start = sources.size; // the fusefile position of fragment + sources.size += p->to - p->from; + return 0; +} + static int setup_sources(char **argv,int i,int n) { sources.array = calloc( n, sizeof( struct Source ) ); if ( sources.array == 0 ) { @@ -299,71 +371,8 @@ static int setup_sources(char **argv,int i,int n) { int j = 0; sources.size = 0; for ( ; j < n; i++, j++ ) { - struct stat filestat; struct Source *p = sources.array + j; - // 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 ); - } - 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 ); + if ( setup_source( p, argv[i] ) ) { return 1; } p->start = sources.size; // the fusefile position of fragment @@ -775,8 +784,53 @@ 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() { + int oly = 0; + int src = 0; + size_t pos = 0; + while ( src < sources.count ) { + size_t x = ( oly < overlay.count )? + overlay.table[ oly ].beg : sources.size; + 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 ); + pos = ENDSOURCE( sources.array[ src ] ); + } + if ( 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 ); + 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 ); + pos = overlay.table[ oly++ ].end; + } + for ( ; src < sources.count && + ENDSOURCE( sources.array[ src ] ) <= pos; src++ ) { + // Just skip these fragments. + } + } + return( 0 ); +} + static struct fuse_operations fusefile_oper = { .getattr = fusefile_getattr, + // NYI .fgetattr = fusefile_fgetattr, .chmod = fusefile_chmod, .open = fusefile_open, .read = fusefile_read, @@ -784,9 +838,11 @@ static struct fuse_operations fusefile_oper = { .write = fusefile_write, .write_buf = fusefile_write_buf, .destroy = fusefile_destroy, + // NYI .access = fusefile_access, .flush = fusefile_flush, .release = fusefile_release, .fsync = fusefile_fsync, + // NYI .ftruncate = fusefile_ftruncate, .truncate = fusefile_truncate, //.truncate = fusefile_truncate, //.release = fusefile_release, @@ -903,6 +959,9 @@ int main(int argc, char *argv[]) } } fuseargc = setup_argv( fuseargc, &argv ); + if ( strcmp( "-dump", argv[ 1 ] ) == 0 ) { + return dump_fragments(); + } struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv ); if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) { return 1;