--- /dev/null
+/***
+ fusefile-merge - merge a fusefile overlay into its underling
+
+ Copyright (C) 2023- Ralph Ronnquist
+
+ This program is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/**
+ * An overlay file consists of a data block followed by a count of
+ * struct Region elements plus that many elements.
+ */
+struct Region {
+ off_t beg;
+ off_t end;
+};
+
+/**
+ * Table head
+ */
+struct Table {
+ size_t count;
+ struct Region regions[];
+};
+
+struct FileInfo {
+ char *name;
+ size_t size;
+};
+
+struct FileInfo basefile, olyfile;
+
+/**
+ *
+ */
+static struct Table *loadtable() {
+ if ( basefile.size >= olyfile.size ) {
+#if DEBUG
+ fprintf( stderr, "basefile.size >= olyfile.size\n" );
+#endif
+ return 0;
+ }
+ size_t tbl = ( olyfile.size - basefile.size );
+ if ( ( tbl % sizeof( off_t ) ) != 0 ) {
+#if DEBUG
+ fprintf( stderr, "( tbl %% sizeof( off_t ) ) != 0\n" );
+#endif
+ return 0;
+ }
+ size_t count = tbl / sizeof( off_t );
+ if ( ( count & 1 ) == 0 ) { // Needs an odd number of off_t values
+#if DEBUG
+ fprintf( stderr, "( count & 1 ) == 0\n" );
+#endif
+ return 0;
+ }
+ count = ( count - 1 ) / 2;
+ int fd = open( olyfile.name, O_RDONLY );
+ if ( fd < 0 ) {
+ perror( olyfile.name );
+ return 0;
+ }
+ struct Table *ptr =
+ mmap( 0, tbl, PROT_READ, MAP_PRIVATE, fd, basefile.size );
+ return ( ptr->count != count )? 0 : ptr;
+}
+
+static void usage() {
+ fprintf( stderr, "Usage: basefile overlayfile\n" );
+ exit( 1 );
+}
+
+/**
+ * Application entry. This program dumps the overlay table as a
+ * fusefile fragments sequence, with newline?
+ */
+int main(int argc,char **argv) {
+ static struct stat info;
+
+ if ( argc != 3 ) {
+ usage();
+ }
+ basefile.name = argv[1];
+ if ( stat( basefile.name, &info ) ) {
+ perror( basefile.name );
+ exit( 1 );
+ }
+ basefile.size = info.st_size;
+
+ olyfile.name = argv[2];
+ if ( stat( olyfile.name, &info ) ) {
+ perror( olyfile.name );
+ exit( 1 );
+ }
+ olyfile.size = info.st_size;
+
+ struct Table *table = loadtable();
+ if ( table == 0 ) {
+ fprintf( stderr, "%s is not onverlay for %s\n",
+ olyfile.name, basefile.name );
+ fprintf( stderr, " %s: %ld\n", basefile.name, basefile.size );
+ fprintf( stderr, " %s: %ld\n", olyfile.name, olyfile.size );
+ exit( 1 );
+ }
+ int i;
+ size_t pos = 0;
+ for ( i = 0; i < table->count; i++ ) {
+ struct Region *r = &(table->regions[i]);
+ if ( pos < r->beg ) {
+ fprintf( stdout, "%s/%ld:%ld\n", basefile.name, pos, r->beg );
+ }
+ fprintf( stdout, "%s/%ld:%ld\n", olyfile.name, r->beg, r->end );
+ pos = r->end;
+ }
+ if ( pos < basefile.size ) {
+ fprintf( stdout, "%s/%ld:%ld\n", basefile.name, pos, basefile.size );
+ }
+ return( 0 );
+}