X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=fusefile.c;h=a976660e29fb56a5c73297e27e24ab0e212db5a7;hb=9c63c2c9b00d4e1faa0482f5cc2dc21a26ff2c03;hp=41c6ed6042f6ca9462b02f19b45f6136a8eb0ae3;hpb=26b59ee2e0ee0a47f19153e629ce0c7a94bb134d;p=rrq%2Ffusefile.git diff --git a/fusefile.c b/fusefile.c index 41c6ed6..a976660 100644 --- a/fusefile.c +++ b/fusefile.c @@ -45,24 +45,19 @@ struct Source { static struct { struct Source *array; int count; - int limit; ssize_t size; } sources; -#define SOURCEARRAYP(i) ((void*)&sources.array[ i ]) - -/** - * Holds info about scratch pad file for 'write' events. - */ static struct { - char *filename; - int fd; -} pad; - + time_t atime; + time_t mtime; + time_t ctime; +} times; + #if DEBUG static void print_source(struct Source *p) { fprintf( stderr, "%p { %s, %ld, %ld, %ld, %d }\n", - p, p->filename, p->from, p->to, p->start, p->fd ); + p, p->filename, p->from, p->to, p->start, p-> fd ); } #endif @@ -117,7 +112,6 @@ static int setup_sources(char **argv,int i,int n) { return 1; } sources.count = n; - sources.limit = n; int j = 0; sources.size = 0; for ( ; j < n; i++, j++ ) { @@ -128,7 +122,11 @@ static int setup_sources(char **argv,int i,int n) { } p->start = sources.size; sources.size += p->to - p->from; - p->fd = open( p->filename, O_RDONLY ); + p->fd = open( p->filename, O_RDWR ); + if ( p->fd < 0 ) { + fprintf( stderr, "** %s opened read-only\n", p->filename ); + p->fd = open( p->filename, O_RDONLY ); + } if ( p->fd < 0 ) { perror( p->filename ); return 1; @@ -151,21 +149,24 @@ static int fusefile_getattr(const char *path,struct stat *stbuf) { fprintf( stderr, "getattr %ld\n", sources.size ); #endif memset( stbuf, 0, sizeof( struct stat ) ); - stbuf->st_mode = S_IFREG | 0444; // Hmmm - if ( pad.filename ) { - stbuf->st_mode |= 0200; - } + stbuf->st_mode = S_IFREG | 0644; // Hmmm stbuf->st_nlink = 1; stbuf->st_size = sources.size; - time_t now = time( 0 ); - stbuf->st_atime = now; - stbuf->st_mtime = now; - stbuf->st_ctime = now; + stbuf->st_atime = times.atime; + stbuf->st_mtime = times.mtime; + stbuf->st_ctime = times.ctime; stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); return 0; } +static int fusefile_chmod(const char *path,mode_t m) { +#if DEBUG + fprintf( stderr, "fusefile_chmod( %s, %d )\n", path, m ); +#endif + return -1; +} + static int fusefile_open(const char *path,struct fuse_file_info *fi) { #if DEBUG fprintf( stderr, "fusefile_open( %s, %d )\n", path, fi->flags ); @@ -175,85 +176,35 @@ static int fusefile_open(const char *path,struct fuse_file_info *fi) { return -ENOENT; } // set O-CLOEXEC for this opening? + times.atime = time( 0 ); return 0; } static int find_source(off_t offset) { int lo = 0; int hi = sources.count; - if ( offset > sources.size ) { + if ( offset >= sources.size ) { return -1; } - while ( lo < hi ) { + while ( lo + 1 < hi ) { int m = ( lo + hi ) / 2; - if ( sources.array[m].start > offset ) { + if ( offset < sources.array[ m ].start ) { hi = m; - } else if ( m+1 < hi && sources.array[m+1].start < offset ) { - lo = m+1; } else { - return m; + lo = m; } } return lo; } -/** - * Insert a source fragment description into the table at . - */ -static int insert_source(struct Source *source,size_t off) { - int index = find_source( off ); - // Ensure at least 5 "free" Sources in - // and allocate space for 20 new otherwise. - if ( sources.count + 5 > sources.limit ) { - size_t size = sources.limit + 20; - struct Source *new = realloc( - sources.array, size * sizeof( struct Source ) ); - if ( new == 0 ) { - return -1; - } - sources.array = new; - sources.limit = size; - } - if ( index < sources.count ) { - ssize_t b = ( sources.count - index ) * sizeof(struct Source); - if ( sources.array[ index ].start < off ) { - // Split the record at - // and adjust index - b *= 2; - memcpy( SOURCEARRAYP( index+2 ), SOURCEARRAYP( index ), b ); - sources.count += 2; - b = off - sources.array[ index ].start; - sources.array[ index + 2 ].from += b; // adjust tail fragment - sources.array[ index++ ].to = b; // adjust head fragment - } else { - // Insert the new source at - memcpy( SOURCEARRAYP( index+1 ), SOURCEARRAYP( index ), b ); - sources.count += 1; - } - } else { - // Append the new source to (at ) - sources.count += 1; - } - sources.array[ index ].filename = source->filename; - sources.array[ index ].fd = source->fd; - sources.array[ index ].from = source->from; - sources.array[ index ].to = source->to; - for ( ; index < sources.count; index++ ) { - sources.array[ index ].start = off; - off += sources.array[ index ].to - sources.array[ index ].from; - } - sources.size = off; - return index; -} - -// Read bytes from in file +// Read bytes from in file static int fusefile_read(const char *path, char *buf, size_t size, off_t off, struct fuse_file_info *fi) { #if DEBUG fprintf( stderr, "fusefile_read( %s )\n", path ); #endif - if ( strcmp( path, "/" ) != 0 ) { + if( strcmp( path, "/" ) != 0 ) { return -ENOENT; } #if DEBUG @@ -266,7 +217,7 @@ static int fusefile_read(const char *path, char *buf, size_t size, #endif int i = find_source( off ); if ( i < 0 ) { - return -ENOENT; + return ( off == sources.size )? 0 : -ENOENT; } if ( sources.array[i].fd < 0 ) { return -ENOENT; @@ -301,64 +252,90 @@ static int fusefile_read(const char *path, char *buf, size_t size, off += r; size -= r; } + times.atime = time( 0 ); return rr; } /** - * Write a full block of data. + * Write a full block of data over the sources at the offset */ -static int write_block(int fd,const char *buf,size_t size) { - size_t orig = size; +static int write_block(off_t off,const char *buf,size_t size) { +#if DEBUG + fprintf( stderr, "write_block( %ld, ?, %ld )\n", off, size ); +#endif while ( size > 0 ) { - ssize_t n = write( fd, buf, size ); - if ( n <= 0 ) { - return n; + int index = find_source( off ); // index of source file + if ( index < 0 ) { + return -EIO; // past EOF + } + struct Source *source = &sources.array[ index ]; + off_t from = off - source->start + source->from; + off_t max = source->to - from; + if ( lseek( source->fd, from, SEEK_SET ) < 0 ) { + return -EIO; + } + ssize_t todo = ( size < max )? size : max; + while ( todo > 0 ) { + times.mtime = time( 0 ); + ssize_t n = write( source->fd, buf, todo ); + if ( n <= 0 ) { + return -EIO; // Something wrong + } + buf += n; + todo -= n; + size -= n; + off += n; + } + } + return 0; +} + +static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf, + off_t off, struct fuse_file_info *fi) { +#if DEBUG + fprintf( stderr, "fusefile_write_buf( %s )\n", path ); +#endif + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + + size_t size = 0; + int i; + for ( i = 0; i < buf->count; i++ ) { + struct fuse_buf *p = &buf->buf[i]; + if ( p->flags & FUSE_BUF_IS_FD ) { +#if DEBUG + fprintf( stderr, "Content held in a file ... HELP!!\n" ); +#endif + return -EIO; } + if ( write_block( off, (char*) p->mem, p->size ) < 0 ) { + return -EIO; + } + size += p->size; } - return orig; +#if DEBUG + fprintf( stderr, "fusefile_write_buf written %ld\n", size ); +#endif + return size; } /** - * Insert a fragment at . The data is appended to the pad file, - * and a descriptor is inserted; the fragment containing is - * first split, unless is at its start, and then new fragment - * descriptor is inserted. + * Write a fragment at . This overwrites files. */ static int fusefile_write(const char *path, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { #if DEBUG - fprintf( stderr, "fusefile_write( %s )\n", path ); + fprintf( stderr, "fusefile_write( %s %ld )\n", path, size ); #endif if ( strcmp( path, "/" ) != 0 ) { return -ENOENT; } -#if DEBUG - fprintf( stderr, "write %ld %ld\n", off, size ); -#endif - // Ensure a pad was nominated - if ( pad.filename == 0 ) { - return 1; - } - static char meta[ 100 ]; - sprintf( meta, "%ld\n%ld\n", off, size ); - if ( write_block( pad.fd, meta, strlen( meta ) ) <= 0 ) { - perror( pad.filename ); + + if ( write_block( off, buf, size ) < 0 ) { return -EIO; } - struct Source source = { - .filename = pad.filename, - .fd = pad.fd, - .from = lseek( pad.fd, 0, SEEK_END ), - .to = 0, - .start = 0 - }; - ssize_t n = write_block( pad.fd, buf, size ); - if ( n != size ) { - return n; - } - source.to = source.from + size; - insert_source( &source, off ); return size; } @@ -402,21 +379,34 @@ static int fusefile_fsync(const char *path, int x, struct fuse_file_info *fi) { return 0; } +/** + * + */ +static int fusefile_truncate(const char *path, off_t len) { +#if DEBUG + fprintf( stderr, "fusefile_truncate( %s, %ld )\n", path, len ); +#endif + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + return -EIO; +} + static struct fuse_operations fusefile_oper = { .getattr = fusefile_getattr, + .chmod = fusefile_chmod, .open = fusefile_open, .read = fusefile_read, .write = fusefile_write, + .write_buf = fusefile_write_buf, .destroy = fusefile_destroy, .flush = fusefile_flush, .release = fusefile_release, .fsync = fusefile_fsync, - //void *(*init) (struct fuse_conn_info *conn); - //int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, - // struct fuse_file_info *); + .truncate = fusefile_truncate, //.truncate = fusefile_truncate, - //.flush = fusefile_flush, //.release = fusefile_release, + //void *(*init) (struct fuse_conn_info *conn); }; static void usage() { @@ -430,15 +420,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) { - int n = argc + 1; - char **out = calloc( n--, sizeof( char* ) ); - memcpy( (void*) out, (void*) (*argv), argc-- * sizeof( char* ) ); - out[ n++ ] = out[ argc ]; // mount point - out[ argc++ ] = "-odefault_permissions"; + // note: (*argv)[ argc ] is the mount point argument + char *OURS[] = { + "-odefault_permissions", + (*argv)[ argc ] + }; +#define OURSN ( sizeof( OURS ) / 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 ] ); + } + for ( i = 0; i < OURSN; i++ ) { + out[ argc + i ] = OURS[i]; + //fprintf( stderr, " %s", out[ i ] ); + } + out[ N ] = 0; + //fprintf( stderr, "\n" ); (*argv) = out; - return n; + return N; // Don't include the terminating null pointer } /** @@ -463,21 +469,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; - if ( strncmp( argv[ i ], "pad=", 4 ) == 0 ) { - // First argument is the pad, if any, signaled with "pad=" prefix - pad.filename = argv[ i++ ] + 4; // (also move arg index) -#if DEBUG - fprintf( stderr, "scratch pad=%s\n", pad.filename ); -#endif - pad.fd = open( pad.filename, O_RDWR | O_CREAT, 0600 ); - if ( pad.fd < 0 ) { - perror( pad.filename ); - exit( errno ); - } - lseek( pad.fd, 0, SEEK_END ); // initial seek - } + mnt = argv[ i++ ]; // First non-option argument is the mount pount if ( setup_sources( argv, i, argc-i ) ) { return 1; } @@ -487,12 +480,21 @@ int main(int argc, char *argv[]) perror( mnt ); return 1; } + time_t now = time( 0 ); + times.atime = now; + times.mtime = now; + times.ctime = now; temporary = 1; close( fd ); } else if ( ! S_ISREG( stbuf.st_mode ) ) { fprintf( stderr, "mountpoint is not a regular file\n" ); return 1; + } else { + times.atime = stbuf.st_atime; + times.mtime = stbuf.st_mtime; + times.ctime = stbuf.st_ctime; } + fuseargc = setup_argv( fuseargc, &argv ); struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv ); if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) {