}
#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;
- }
- if ( in[i] == '-' ) {
- m = i;
- }
- }
-#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;
- }
- p->from = ( s < 0 )? 0 : atol( in+s+1 );
- if ( p->from < 0 ) {
- p->from = 0;
- }
-#if DEBUG
- fprintf( stderr, "p->from=%ld\n", p->from );
-#endif
- p->to = ( m < 0 )? buf.st_size : atol( in+m+1 );
- if ( p->from > p->to || p->to > buf.st_size ) {
- return 1;
- }
- return 0;
+static char *range;
+static unsigned int c;
+static int RANGE(int s,int n ) {
+ return ( s == n ) && *(range+c) == 0;
}
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;
- if ( scan_source( argv[i], p ) ) {
- // should free everything malloc-ed
- return 1;
- }
- p->start = sources.size;
- sources.size += p->to - p->from;
+ // 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 ) {
- fprintf( stderr, "** %s opened read-only\n", p->filename );
+ 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 );
return 1;
}
+ p->start = sources.size; // the fusefile position of fragment
+ sources.size += p->to - p->from;
#if DEBUG
print_source( p );
#endif
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;
}
#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 ) {
#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 DEBUG
- fprintf( stderr, "got %ld bytes\n", r );
+ fprintf( stderr, " got %ld bytes\n", r );
#endif
if ( r < 0 ) {
perror( sources.array[i].filename );
off += r;
size -= r;
}
- times.atime = time( 0 );
+#if DEBUG
+ fprintf( stderr, " total reading %ld bytes\n", rr );
+#endif
return rr;
}
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,
.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 [ <fuse options> ] <mount> <file/from-to> ... \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 );
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 ) ) {