+ struct Source source;
+ struct Region *table;
+ size_t count;
+ size_t limit;
+} overlay;
+
+static void usage();
+
+/**
+ * Find the nearest overlay.table region below pos. Returns the index,
+ * or -1 if there is none, i.e. pos < overlay.table[0].
+ */
+static ssize_t overlay_prior_fragment(off_t pos) {
+ size_t lo = 0, hi = overlay.count;
+ while ( lo < hi ) {
+ size_t m = ( lo + hi ) / 2;
+ if ( m == lo ) {
+ return overlay.table[m].beg <= pos? m : -1;
+ }
+ if ( overlay.table[m].beg <= pos ) {
+ lo = m;
+ } else {
+ hi = m;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Save the entry count for overlay.table as 64-bit integer
+ * immediately following the overlay content at the index
+ * corresponding to the fused file size.
+ */
+static void overlay_save_count() {
+ lseek( overlay.source.fd, overlay.source.to, SEEK_SET );
+ size_t size = sizeof( overlay.count );
+ char *p = (char *) &overlay.count ;
+ while ( size > 0 ) {
+ size_t n = write( overlay.source.fd, p, size );
+ if ( n < 0 ) {
+ perror( overlay.source.filename );
+ exit( 1 );
+ }
+ size -= n;
+ p += n;
+ }
+ if ( overlay.source.dirty++ > 1000 ) {
+ fsync( overlay.source.fd );
+ overlay.source.dirty = 0;
+ }
+}
+
+/**
+ * Update the on-disk cache of overlay.table between the given
+ * indexes. The table is laid out immediately following the table
+ * count with each region saved as two 64-bit unsigned integers.
+ */
+static void overlay_save_table(size_t lo,size_t hi) {
+ char *p = (char *) &overlay.table[ lo ];
+ size_t pos = overlay.source.to + sizeof( overlay.count ) +
+ lo * sizeof( struct Region );
+ size_t size = ( hi - lo ) * sizeof( struct Region );
+ if ( pos != lseek( overlay.source.fd, pos, SEEK_SET ) ) {
+ fprintf( stderr, "%s: seek error\n", overlay.source.filename );
+ exit( 1 );
+ }
+ while ( size > 0 ) {
+ size_t n = write( overlay.source.fd, p, size );
+ if ( n < 0 ) {
+ perror( overlay.source.filename );
+ exit( 1 );
+ }
+ size -= n;
+ p += n;
+ }
+ if ( overlay.source.dirty++ > 1000 ) {
+ fsync( overlay.source.fd );
+ overlay.source.dirty = 0;
+ }
+}
+
+/**
+ * Insert a new region at index p, with previous portion [p,count]
+ * moved up to make space.
+ */
+static void overlay_insert(size_t p,off_t beg,off_t end) {
+ size_t bytes;
+ // Grow the table if needed
+ if ( overlay.count >= overlay.limit ) {
+ overlay.limit = overlay.count + 10;
+ bytes = overlay.limit * sizeof( struct Region );
+ overlay.table = overlay.table?
+ realloc( overlay.table, bytes ) : malloc( bytes );
+ }
+ bytes = ( overlay.count++ - p ) * sizeof( struct Region );
+ if ( bytes ) {
+ memmove( (char*) &overlay.table[ p+1 ],
+ (char*) &overlay.table[ p ],
+ bytes );
+ }
+ overlay.table[ p ].beg = beg;
+ overlay.table[ p ].end = end;
+ overlay_save_count();
+}