+/**
+ * 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;
+}
+
+static void overlay_load() {
+ lseek( overlay.source.fd, overlay.source.to, SEEK_SET );
+ size_t x = 0;
+ size_t size = sizeof( overlay.count );
+ if ( read( overlay.source.fd, &x, size ) != size ) {
+ return;
+ }
+#if DEBUG
+ fprintf( stderr, "overlay: %s with %ld regions\n",
+ overlay.source.filename, x );
+#endif
+ struct Region f = { 0, 0 };
+ size = sizeof( struct Region );
+ while ( x-- > 0 ) {
+ if ( read( overlay.source.fd, &f, size ) != size ) {
+ fprintf( stderr, "%s: bad meta data\n", overlay.source.filename );
+ exit( 1 );
+ }
+#if DEBUG
+ fprintf( stderr, "overlay region: %ld %ld\n", f.beg, f.end );
+#endif
+ overlay_mark( f.beg, f.end );
+ }
+}
+
+/**
+ * Inject an overlay fragment into the source table, end return the
+ * end of the injected fragment.
+ */
+static off_t overlay_inject_from_region(off_t beg,off_t end) {
+ int index = find_source( beg );
+ if ( index < 0 ) {
+ fprintf( stderr, "** Injecting %s at %ld failed\n",
+ overlay.source.filename, beg );
+ usage();
+ }
+ if ( end > ENDSOURCE( sources.array[ index ] ) ) {
+ end = ENDSOURCE( sources.array[ index ] );
+ }
+ struct Region frags[3] = {
+ { sources.array[ index ].start, beg },
+ { beg, ENDSOURCE( sources.array[ index ] ) },
+ { ENDSOURCE( sources.array[ index ] ), end } };
+ ssize_t size = frags[0].end - frags[0].beg;
+ if ( size ) {
+ // "Duplicate" the indexed source data, copying the filename
+ dup_source_item( index );
+ sources.array[ index ].to = sources.array[ index ].from + size;
+ index++;
+ sources.array[ index ].start = beg;
+ sources.array[ index ].from = sources.array[ index-1 ].to;
+ }
+ size = frags[2].end - frags[2].beg;
+ if ( size ) {
+ dup_source_item( index );
+ sources.array[ index+1 ].start = frags[2].beg;
+ sources.array[ index+1 ].from = sources.array[ index+1 ].to -size;
+ }
+ // Replace the [index] fragment
+ sources.array[ index ].filename = overlay.source.filename;
+ sources.array[ index ].start = beg;
+ sources.array[ index ].from = beg;
+ sources.array[ index ].to = end;
+ sources.array[ index ].fd = overlay.source.fd; //?
+ return end;
+}
+
+/**
+ * Inject the current (unopened) overlay into the source list.
+ */
+static void overlay_inject() {
+ overlay.source.fd = open( overlay.source.filename, O_RDONLY );
+ if ( overlay.source.fd < 0 ) {
+ perror( overlay.source.filename );
+ usage();
+ }
+
+ if ( lseek( overlay.source.fd, overlay.source.to, SEEK_SET ) < 0 ) {
+ perror( overlay.source.filename );
+ usage();
+ }
+ size_t count = 0;
+ size_t size = sizeof( overlay.count );
+ if ( read( overlay.source.fd, &count, size ) != size ) {
+ fprintf( stderr, "** error injecting %s\n", overlay.source.filename );
+ usage();
+ }
+ if ( count == 0 ) {
+ close( overlay.source.fd );
+ return;
+ }
+ size = count * sizeof( struct Region );
+ overlay.table = calloc( sizeof( struct Region ), count );
+ if ( read( overlay.source.fd, overlay.table, size ) != size ) {
+ fprintf( stderr, "** error injecting %s\n", overlay.source.filename );
+ usage();
+ }
+ size_t i;
+ for ( i = 0; i < count; i++ ) {
+ off_t beg = overlay.table[i].beg;
+ while ( beg < overlay.table[i].end ) {
+ beg = overlay_inject_from_region( beg, overlay.table[i].end );
+ }
+ }
+ free( overlay.table );
+ overlay.table = 0;
+ close( overlay.source.fd );
+}
+
+/**
+ * Each stacked overlay file is nested into to source list
+ */
+static void overlay_post_setup() {
+ char *end;
+ while ( ( end = strchr( overlay.source.filename, ':' ) ) ) {
+ *end = 0; //
+ overlay_inject();
+ overlay.source.filename = end + 1;
+ }
+ if ( *overlay.source.filename ) {
+ overlay.source.fd = open( overlay.source.filename,
+ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
+ if ( overlay.source.fd < 0 ) {
+ perror( overlay.source.filename );
+ usage();
+ }
+ overlay_load();
+ }
+}
+
+/**
+ * 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
+ if ( overlay.source.filename ) {
+ overlay_mark( off, off + size ); // Mark region as written
+ }
+ while ( size > 0 ) {
+ int index = find_source( off ); // index of source file
+ if ( index < 0 ) {
+ return -EIO; // past EOF
+ }
+ struct Source *source = overlay.source.filename?
+ &overlay.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;
+ }
+ if ( source->dirty++ >= 1000 ) {
+ fsync( source->fd );
+ source->dirty = 0;
+ }
+ }
+ 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 <off>. 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;
+}
+
+#define PUSHBUF 104857600
+/**
+ * Write data from overlay to source.
+ */
+static void push_oly(off_t beg, off_t end) {
+ static char * buffer = 0;
+ // Pretend that there isn't an overlay
+ char *filename = overlay.source.filename;
+ if ( buffer == 0 ) {
+ buffer = malloc( PUSHBUF );
+ if ( buffer == 0 ) {
+ fprintf( stderr, "** OOM!!\n" );
+ exit( 1 );
+ }
+ }
+ overlay.source.filename = 0;
+ while ( beg < end ) {
+ off_t size = end - beg;
+ if ( size > PUSHBUF ) {
+ size = PUSHBUF;
+ }
+ if ( lseek( overlay.source.fd, beg, SEEK_SET ) < 0 ) {
+ fprintf( stderr, "** Cannot seek overlay at %ld\n", beg );
+ break;
+ }
+ size = read( overlay.source.fd, buffer, size );
+ if ( write_block( beg, buffer, size ) < 0 ) {
+ fprintf( stderr, "** Cannot push %ld bytes at %ld\n", size, beg );
+ }
+ beg += size;
+ }
+ overlay.source.filename = filename;
+}
+