}
#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 SCAN,int N ) {
+ return ( SCAN == 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;
+ 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) ) {
+ unsigned int a,b;
+ if ( RANGE( sscanf( range, "%u-%u%n", &a, &b, &c ), 2 ) ) {
+ p->from = a;
+ p->to = b;
+ } else if ( RANGE( sscanf( range, "%u--%u%n", &a, &b, &c ), 2 ) ) {
+ p->from = a;
+ p->to -= b;
+ } else if ( RANGE( sscanf( range, "%u-%n", &a, &c ), 1 ) ) {
+ p->from = a;
+ } else if ( RANGE( sscanf( range, "%u%n", &a, &c ), 1 ) ) {
+ p->from = a;
+ } else if ( RANGE( sscanf( range, "-%u%n", &b, &c ), 1 ) ) {
+ p->to = b;
+ } else if ( RANGE( sscanf( range, "--%u%n", &b, &c ), 1 ) ) {
+ p->to -= b;
+ } else if ( RANGE( sscanf( range, "-%n", &c), 0 ) ) {
+ // Acceptable as "start-end" range
+ } else {
+ fprintf( stderr, "** BAD RANGE: %s\n", argv[i] );
+ return 1;
+ }
}
+ p->start = sources.size; // the fusefile position of fragment
+ sources.size += p->to - p->from;
#if DEBUG
print_source( p );
#endif
#endif
int i = find_source( off );
if ( i < 0 ) {
- return ( off == sources.size )? 0 : -ENOENT;
+ return ( off == sources.size )? rr : -ENOENT;
}
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;
if ( n > size ) {
off += r;
size -= r;
}
- times.atime = time( 0 );
return rr;
}
+/**
+ * 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;
+}
+
+
/**
* Write a full block of data over the sources at the offset
*/
return -EIO; // past EOF
}
struct Source *source = &sources.array[ index ];
- off_t from = off - source->start;
- off_t max = source->to - source->from - from;
+ off_t from = off - source->start + source->from;
+ off_t max = source->to - from;
if ( lseek( source->fd, from, SEEK_SET ) < 0 ) {
return -EIO;
}
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,
.truncate = fusefile_truncate,
//.truncate = fusefile_truncate,
//.release = fusefile_release,
- //void *(*init) (struct fuse_conn_info *conn);
+ .init = fusefile_init,
};
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) {
+ // note: (*argv)[ argc ] is the mount point argument
char *OURS[] = {
"-odefault_permissions",
- (*argv)[ --argc ] // note: (*argv)[ argc-1 ] = the mount point
+ (*argv)[ argc ]
};
#define OURSN ( sizeof( OURS ) / sizeof( char* ) )
- int N = argc + OURSN; // new argv-tobe size, excluding null
- char **out = malloc( ( N + 1 ) * 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 ] );
+ //fprintf( stderr, " %s", out[ i ] );
}
for ( i = 0; i < OURSN; i++ ) {
out[ argc + i ] = OURS[i];
- fprintf( stderr, " %s", out[ i ] );
+ //fprintf( stderr, " %s", out[ i ] );
}
out[ N ] = 0;
- fprintf( stderr, "\n" );
+ //fprintf( stderr, "\n" );
(*argv) = out;
- return N;
+ return N; // Don't include the terminating null pointer
}
/**
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;
+ mnt = argv[ i++ ]; // First non-option argument is the mount pount
if ( setup_sources( argv, i, argc-i ) ) {
return 1;
}