From: Ralph Ronnquist Date: Fri, 15 Jul 2022 01:28:04 +0000 (+1000) Subject: allow overwriting without changing size X-Git-Tag: 0.4~11^2~3 X-Git-Url: https://git.rrq.au/?a=commitdiff_plain;h=a83a2cd9258ecb0420a019bb5d4cd32db8a444ac;p=rrq%2Ffusefile.git allow overwriting without changing size --- diff --git a/fusefile.c b/fusefile.c index 00f7f7f..476ca9d 100644 --- a/fusefile.c +++ b/fusefile.c @@ -23,9 +23,9 @@ 2001-2007 Miklos Szeredi . */ -#define FUSE_USE_VERSION 31 +#define FUSE_USE_VERSION 33 -#include +#include #include #include #include @@ -48,6 +48,12 @@ static struct { ssize_t size; } sources; +static struct { + 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", @@ -76,7 +82,9 @@ static size_t scan_source(char *in,struct Source *p) { 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; @@ -88,7 +96,9 @@ static size_t scan_source(char *in,struct Source *p) { 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; @@ -112,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; @@ -124,8 +138,10 @@ static int setup_sources(char **argv,int i,int n) { return 0; } -static int fusefile_getattr(const char *path, struct stat *stbuf ) -{ +static int fusefile_getattr(const char *path,struct stat *stbuf) { +#if DEBUG + fprintf( stderr, "fusefile_getattr( %s )\n", path ); +#endif if ( strcmp( path, "/" ) != 0 ) { return -ENOENT; } @@ -133,40 +149,49 @@ 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 + 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_open(const char *path, struct fuse_file_info *fi) -{ +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 ); + fprintf( stderr, "fixing( %d )\n", fi->flags | O_CLOEXEC ); +#endif if ( strcmp( path, "/" ) != 0 ) { 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; @@ -174,22 +199,25 @@ static int find_source(off_t offset) { // Read bytes from in file static int fusefile_read(const char *path, char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t off, struct fuse_file_info *fi) { +#if DEBUG + fprintf( stderr, "fusefile_read( %s )\n", path ); +#endif if( strcmp( path, "/" ) != 0 ) { return -ENOENT; } #if DEBUG - fprintf( stderr, "read %ld %ld\n", offset, size ); + fprintf( stderr, "read %ld %ld\n", off, size ); #endif size_t rr = 0; while ( size > 0 ) { #if DEBUG - fprintf( stderr, "find_source %ld %ld\n", offset, size ); + fprintf( stderr, "find_source %ld %ld\n", off, size ); #endif - int i = find_source( offset ); + int i = find_source( off ); if ( i < 0 ) { - return -ENOENT; + return ( off == sources.size )? 0 : -ENOENT; } if ( sources.array[i].fd < 0 ) { return -ENOENT; @@ -197,7 +225,7 @@ static int fusefile_read(const char *path, char *buf, size_t size, #if DEBUG print_source( &sources.array[i] ); #endif - size_t b = offset - sources.array[i].start + sources.array[i].from; + size_t b = off - sources.array[i].start + sources.array[i].from; size_t n = sources.array[i].to - b; if ( n > size ) { n = size; @@ -221,24 +249,164 @@ static int fusefile_read(const char *path, char *buf, size_t size, break; } rr += r; - offset += r; + off += r; size -= r; } + times.atime = time( 0 ); return rr; } +/** + * Write a full block of data over the sources at the offset + */ +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 ) { + 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; + off_t max = source->to - source->from - 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; + } +#if DEBUG + fprintf( stderr, "fusefile_write_buf written %ld\n", size ); +#endif + return size; +} + +/** + * 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 %ld )\n", path, size ); +#endif + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + + if ( write_block( off, buf, size ) < 0 ) { + return -EIO; + } + return size; +} + static void fusefile_destroy(void *data) { - char *mnt = (char*) data; + char *mnt = (char*) data; // As passed to fuse_main +#if DEBUG + fprintf( stderr, "fusefile_destroy( %s )\n", mnt? mnt : "" ); +#endif if ( mnt ) { unlink( mnt ); } } +static int fusefile_flush(const char *path, struct fuse_file_info *info) { +#if DEBUG + fprintf( stderr, "fusefile_flush( %s )\n", path ); +#endif + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + return 0; +} + +static int fusefile_release(const char *path, struct fuse_file_info *fi) { +#if DEBUG + fprintf( stderr, "fusefile_release( %s, %d )\n", path, fi->flags ); +#endif + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + return 0; +} + +static int fusefile_fsync(const char *path, int x, struct fuse_file_info *fi) { +#if DEBUG + fprintf( stderr, "fusefile_fsync( %s, %d )\n", path, x ); +#endif + if ( strcmp( path, "/" ) != 0 ) { + return -ENOENT; + } + 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, + .truncate = fusefile_truncate, + //.truncate = fusefile_truncate, + //.release = fusefile_release, + //void *(*init) (struct fuse_conn_info *conn); }; static void usage() { @@ -250,6 +418,32 @@ static void usage() { exit( 1 ); } +/** + * Set up the arguments for the fuse_main call, adding our own. + */ +static int setup_argv(int argc,char ***argv) { + char *OURS[] = { + "-odefault_permissions", + (*argv)[ --argc ] // note: (*argv)[ argc-1 ] = the mount point + }; +#define OURSN ( sizeof( OURS ) / sizeof( char* ) ) + int N = argc + OURSN; // new argv-tobe size, excluding null + 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; +} + /** * Mount a concatenation of files, * [ ] ... @@ -260,6 +454,7 @@ int main(int argc, char *argv[]) int mt; int fg; int i; + int fuseargc; struct stat stbuf; int temporary = 0; // Scan past options @@ -268,27 +463,37 @@ int main(int argc, char *argv[]) break; } } - if ( i > argc - 2 ) { // At least one source + if ( i > argc - 2 ) { // At least mount point plus one source usage(); } - i++; + mnt = argv[ i++ ]; // First non-option argument is the mount pount + fuseargc = i; if ( setup_sources( argv, i, argc-i ) ) { return 1; } - mnt = argv[i-1]; if ( stat( mnt, &stbuf ) == -1 ) { int fd = open( mnt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR ); if ( fd < 0 ) { 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; } - struct fuse_args args = FUSE_ARGS_INIT( i, argv ); + + fuseargc = setup_argv( fuseargc, &argv ); + struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv ); if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) { return 1; } @@ -297,5 +502,5 @@ int main(int argc, char *argv[]) fprintf( stderr, "missing mountpoint parameter\n" ); return 1; } - return fuse_main( i, argv, &fusefile_oper, temporary? mnt : NULL ); + return fuse_main( fuseargc, argv, &fusefile_oper, temporary? mnt : NULL ); }