revise argument processing
[rrq/fusefile.git] / fusefile.c
index 476ca9d8fb1ffa847e094150b44223a816ed7603..5a51066232251a3db09dc310df5abdd4fbb6c043 100644 (file)
@@ -61,49 +61,10 @@ static void print_source(struct Source *p) {
 }
 #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) {
@@ -115,22 +76,56 @@ 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
@@ -217,7 +212,7 @@ static int fusefile_read(const char *path, char *buf, size_t size,
 #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;
@@ -225,6 +220,7 @@ 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 ) {
@@ -252,10 +248,28 @@ static int fusefile_read(const char *path, char *buf, size_t 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
  */
@@ -269,8 +283,8 @@ static int write_block(off_t off,const char *buf,size_t size) {
            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;
        }
@@ -392,11 +406,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,
@@ -406,7 +434,7 @@ 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() {
@@ -420,28 +448,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) {
+    // 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
 }
 
 /**
@@ -466,8 +497,8 @@ 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;
+    mnt = argv[ i++ ]; // First non-option argument is the mount pount
     if ( setup_sources( argv, i, argc-i ) ) {
        return 1;
     }