}
#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
#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;
}
+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() {