more argument polishing
[rrq/fusefile.git] / fusefile.c
index a0f09818da187d7958c75d6117ef5ed6bdebd06c..0936da92219a0e5877679c1bdbae2fc91d1680e6 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 s,int n ) {
+    return ( s == n ) && *(range+c) == 0;
 }
 
 static int setup_sources(char **argv,int i,int n) {
@@ -115,22 +76,75 @@ 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
@@ -225,6 +239,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,7 +267,6 @@ static int fusefile_read(const char *path, char *buf, size_t size,
        off += r;
        size -= r;
     }
-    times.atime = time( 0 );
     return rr;
 }
 
@@ -411,6 +425,19 @@ 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,
@@ -426,7 +453,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() {