ab97ff7f0f50c8902066075c2df1951f5c9fdb31
[rrq/fusefile.git] / fusefile.c
1 /***
2     fusefile - overlay a file path with a concatenation of parts of
3     other files.
4
5     Copyright (C) 2019-  Ralph Ronnquist
6
7     This program is free software: you can redistribute it and/or
8     modify it under the terms of the GNU General Public License as
9     published by the Free Software Foundation, either version 3 of the
10     License, or (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program. If not, see
19     <http://www.gnu.org/licenses/>.
20
21     This source was inspired by the "null.c" example of the libfuse
22     sources, which is distributed under GPL2, and copyright (C)
23     2001-2007 Miklos Szeredi <miklos@szeredi.hu>.
24 */
25
26 #define FUSE_USE_VERSION 33
27
28 #include <fuse.h>
29 #include <fuse/fuse_lowlevel.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <time.h>
35 #include <errno.h>
36 #include <sys/ioctl.h>
37 #include <linux/fs.h>
38
39 struct Region {
40     off_t beg;
41     off_t end;
42 };
43
44 #define REGIONKEEP(r) ((r,beg == r.end)?: 0 : 1)
45
46 struct Source {
47     char *filename;
48     ssize_t from;
49     ssize_t to;
50     ssize_t start; // starting position in concatenated file
51     int fd;
52     int dirty;
53 };
54
55 #define ENDSOURCE( S ) ( S.start + ( S.to - S.from ) )
56
57 static struct {
58     struct Source *array;
59     int count;
60     ssize_t size;
61 } sources;
62
63 static struct {
64     time_t atime;
65     time_t mtime;
66     time_t ctime;
67 } times;
68
69 /**
70  * Overlay
71  */
72 static struct Overlay {
73     struct Source source;
74     struct Region *table;
75     size_t count;
76     size_t limit;
77 } overlay; // The current overlay.
78
79 static void usage();
80
81 /**
82  * Find the nearest overlay.table region below pos. Returns the index,
83  * or -1 if there is none, i.e. pos < overlay.table[0].
84  */
85 static ssize_t overlay_prior_fragment(off_t pos) {
86     size_t lo = 0, hi = overlay.count;
87     while ( lo < hi ) {
88         size_t m = ( lo + hi ) / 2;
89         if ( m == lo ) {
90             return overlay.table[m].beg <= pos? m : -1;
91         }
92         if ( overlay.table[m].beg <= pos ) {
93             lo = m;
94         } else {
95             hi = m;
96         }
97     }
98     return -1;
99 }
100
101 /**
102  * Save the entry count for overlay.table as 64-bit integer
103  * immediately following the overlay content at the index
104  * corresponding to the fused file size.
105  */
106 static void overlay_save_count() {
107     lseek( overlay.source.fd, overlay.source.to, SEEK_SET );
108     size_t size = sizeof( overlay.count );
109     char *p = (char *) &overlay.count ;
110     while ( size > 0 ) {
111         size_t n = write( overlay.source.fd, p, size );
112         if ( n < 0 ) {
113             perror( overlay.source.filename );
114             exit( 1 );
115         }
116         size -= n;
117         p += n;
118     }
119     if ( overlay.source.dirty++ > 1000 ) {
120         fsync( overlay.source.fd );
121         overlay.source.dirty = 0;
122     }
123 }
124
125 /**
126  * Update the on-disk cache of overlay.table between the given
127  * indexes. The table is laid out immediately following the table
128  * count with each region saved as two 64-bit unsigned integers.
129  */
130 static void overlay_save_table(size_t lo,size_t hi) {
131     char *p = (char *) &overlay.table[ lo ];
132     size_t pos =  overlay.source.to + sizeof( overlay.count ) +
133         lo * sizeof( struct Region );
134     size_t size = ( hi - lo ) * sizeof( struct Region );
135     if ( pos != lseek( overlay.source.fd, pos, SEEK_SET ) ) {
136         fprintf( stderr, "%s: seek error\n", overlay.source.filename );
137         exit( 1 );
138     }
139     while ( size > 0 ) {
140         size_t n = write( overlay.source.fd, p, size );
141         if ( n < 0 ) {
142             perror( overlay.source.filename );
143             exit( 1 );
144         }
145         size -= n;
146         p += n;
147     }
148     if ( overlay.source.dirty++ > 1000 ) {
149         fsync( overlay.source.fd );
150         overlay.source.dirty = 0;
151     }
152 }
153
154 /**
155  * Insert a new region at index p, with previous portion [p,count]
156  * moved up to make space.
157  */
158 static void overlay_insert(size_t p,off_t beg,off_t end) {
159     size_t bytes;
160     // Grow the table if needed
161     if ( overlay.count >= overlay.limit ) {
162         overlay.limit = overlay.count + 10;
163         bytes = overlay.limit * sizeof( struct Region );
164         overlay.table = overlay.table?
165             realloc( overlay.table, bytes ) : malloc( bytes );
166     }
167     bytes = ( overlay.count++ - p ) * sizeof( struct Region );
168     if ( bytes ) {
169         memmove( (char*) &overlay.table[ p+1 ],
170                  (char*) &overlay.table[ p ],
171                  bytes );
172     }
173     overlay.table[ p ].beg = beg;
174     overlay.table[ p ].end = end;
175     overlay_save_count();
176 }
177
178 /**
179  * Delete the region entry at p by moving the portion [p+1,count]
180  * down.
181  */
182 static void overlay_delete(size_t p) {
183     size_t bytes = ( --overlay.count - p ) * sizeof( struct Region );
184     if ( bytes ) {
185         memmove( (char*) &overlay.table[ p ],
186                  (char*) &overlay.table[ p+1 ],
187                  bytes );
188     }
189 }
190
191 /**
192  * Mark the given region as updated, i.e. written to the overlay. The
193  * mark region may attach to prior marked regions or be a new,
194  * separate region. If attaching, it causes the prior regions to
195  * expand and the table adjusted by deleting any regions that become
196  * fully contained in other regions.
197  */
198 static void overlay_mark(off_t beg,off_t end) {
199 #if DEBUG
200     fprintf( stderr, "overlay_mark( %ld, %ld )\n", beg, end );
201 #endif
202     int deleted = 0;
203     ssize_t q;
204     ssize_t p = overlay_prior_fragment( beg );
205     // p is the nearest region below or at beg (or -1)
206     if ( p >= 0 && beg <= overlay.table[p].end ) {
207         // p overlaps mark region
208         if ( end <= overlay.table[p].end ) {
209             // region p covers mark region already
210 #if DEBUG
211             fprintf( stderr, "overlay covering ( %ld %ld )\n",
212                      overlay.table[p].beg, overlay.table[p].end );
213 #endif
214             return;
215         }
216         // the new mark region extends region p
217         overlay.table[p].end = end;
218         q = p+1;
219         while ( q < overlay.count &&
220                 overlay.table[q].beg <= overlay.table[p].end ) {
221             // Extended region merges with subsequent region
222             if ( overlay.table[p].end < overlay.table[q].end ) {
223                 overlay.table[p].end = overlay.table[q].end;
224             }
225             overlay_delete( q );
226             deleted++;
227         }
228         if ( deleted ) {
229             overlay_save_count();
230             q = overlay.count;
231         }
232         overlay_save_table( p, q );
233 #if DEBUG
234         fprintf( stderr, "overlay expand ( %ld %ld ) deleted %d\n",
235                  overlay.table[p].beg, overlay.table[p].end, deleted );
236 #endif
237         return;
238     }
239     // The prior region p does not expand into new mark region
240     p++; // subsequent region 
241     if ( p >= overlay.count || end < overlay.table[p].beg ) {
242         // New mark region is a separate region at p
243         overlay_insert( p, beg, end );
244 #if DEBUG
245         fprintf( stderr, "overlay new ( %ld %ld )\n",
246                  overlay.table[p].beg, overlay.table[p].end );
247 #endif
248         overlay_save_table( p, overlay.count );
249         return;
250     }
251     // New marks start before and overlap with region p => change p
252     // and handle any subsequent regions being covered
253     overlay.table[p].beg = beg;
254     q = p+1;
255     if ( overlay.table[p].end < end ) {
256         overlay.table[p].end = end;
257         while ( q < overlay.count &&
258                 overlay.table[q].beg <= overlay.table[p].end ) {
259             if ( overlay.table[p].end < overlay.table[q].end ) {
260                 overlay.table[p].end = overlay.table[q].end;
261             }
262             overlay_delete( q );
263             deleted++;
264         }
265         if ( deleted ) {
266             overlay_save_count();
267             q = overlay.count;
268         }
269     }
270     overlay_save_table( p, q );
271 #if DEBUG
272     fprintf( stderr, "overlay before ( %ld %ld ) deleted %d\n",
273              overlay.table[p].beg, overlay.table[p].end, deleted );
274 #endif
275 }
276
277 /**
278  * Capture overlay filenames for processing after source fragments.
279  */
280 static void overlay_setup(char *filenames) {
281     overlay.source.filename = filenames;
282 }
283
284 // Duplicate the source record data at the given index.
285 static void dup_source_item(int index) {
286     sources.count++;
287     sources.array = realloc(
288         sources.array, sources.count * sizeof( struct Source ) );
289     if ( sources.array == 0 ) {
290         fprintf( stderr, "** OOM when expanding frament table\n" );
291         usage();
292     }
293     memcpy( &sources.array[ index+1 ], &sources.array[ index ],
294             sizeof( struct Source ) );
295 }
296
297 #if DEBUG
298 static void print_source(struct Source *p) {
299     fprintf( stderr, "%p { %s, %ld, %ld, %ld, %d }\n",
300              p, p->filename, p->from, p->to, p->start, p-> fd );
301 }
302 #endif
303
304 static char *range;
305 static unsigned int c;
306 static int RANGE(int s,int n ) {
307     return ( s == n ) && *(range+c) == 0;
308 }
309
310 static int setup_source(struct Source *p,char *frag) {
311     struct stat filestat;
312     // Open the fragment file rw if possible, else ro
313     // First try the fragment in full, thereafter with range appendix
314     if ( stat( frag, &filestat ) == 0 ) {
315         p->filename = strdup( frag );
316         range = 0;
317     } else {
318         range = strrchr( frag, '/' ); // last '/'
319         p->filename = range? strndup( frag, range - frag ) : frag;
320     }
321     p->fd = open( p->filename, O_RDWR );
322     int rdonly = 0;
323     if ( p->fd < 0 ) {
324         rdonly = 1;
325         p->fd = open( p->filename, O_RDONLY );
326     }
327     if ( p->fd < 0 ) {
328         perror( p->filename );
329         return 1; // Error return
330     }
331     if ( ( range == 0 ) && stat( p->filename, &filestat ) ) {
332         perror( p->filename );
333         return 1; 
334     }
335     if ( rdonly ) {
336         fprintf( stderr, "** %s opened read-only\n", p->filename );
337     }
338     p->from = 0;
339     if ( S_ISBLK( filestat.st_mode ) ) {
340         // Block devices report size differently:
341         if ( ioctl( p->fd, BLKGETSIZE64, &filestat.st_size ) < 0 ) {
342             perror( p->filename );
343         }
344 #if DEBUG
345         fprintf( stderr, "block device size = %ld\n", filestat.st_size );
346 #endif
347     }
348     p->to = filestat.st_size;
349     // Process any range variation
350     if ( range && *(++range) ) {
351         long int a,b;
352         if ( 0 ) {
353         } else if ( RANGE( sscanf( range, "%ld:%ld%n", &a, &b, &c ), 2 )) {
354             p->from = ( a < 0 )? ( p->to + a ) : a;
355             p->to = ( b < 0 )? ( p->to + b ) : b;
356         } else if ( RANGE( sscanf( range, "%ld+%ld%n", &a, &b, &c ), 2 )) {
357             p->from = ( a < 0 )? ( p->to + a ) : a;
358             p->to = ( ( b < 0 )? p->to : p->from ) + b;
359         } else if ( RANGE( sscanf( range, "%ld+%n", &a, &c ), 1 )) {
360             p->from = ( a < 0 )? ( p->to + a ) : a;
361         } else if ( RANGE( sscanf( range, ":%ld%n", &b, &c ), 1 )) {
362             p->to = ( b < 0 )? ( p->to + b ) : b;
363         } else if ( RANGE( sscanf( range, "%ld:%n", &a, &c ), 1 )) {
364             p->from = ( a < 0 )? ( p->to + a ) : a;
365         } else if ( RANGE( sscanf( range, "%ld%n", &a, &c ), 1 )) {
366             if ( a >= 0 ) {
367                 p->from = a;
368             } else {
369                 p->from = p->to + a;
370             }
371         } else if ( RANGE( sscanf( range, ":%n", &c), 0 ) ) {
372             // to end from start
373         } else {
374             fprintf( stderr, "** BAD RANGE: %s\n", frag );
375             return 1;
376         }
377     }
378     if ( ( filestat.st_mode &  S_IFMT ) == S_IFCHR ) {
379         filestat.st_size = p->to; // Pretend size of character device
380     }
381     if ( p->from < 0 ) {
382         p->from = 0;
383     }
384     if ( p->to > filestat.st_size ) {
385         p->to = filestat.st_size;
386     }
387     if ( p->from >= p->to || p->from >= filestat.st_size ) {
388         fprintf( stderr, "** BAD RANGE: %s [%ld:%ld]\n",
389                  frag, p->from, p->to );
390         return 1;
391     }
392     p->start = sources.size; // the fusefile position of fragment
393     sources.size += p->to - p->from;
394     return 0;
395 }
396
397 static int setup_sources(char **argv,int i,int n) {
398     sources.array = calloc( n, sizeof( struct Source ) );
399     if ( sources.array == 0 ) {
400         return 1;
401     }
402     sources.count = n;
403     int j = 0;
404     sources.size = 0;
405     for ( ; j < n; i++, j++ ) {
406         struct Source *p = sources.array + j;
407         if ( setup_source( p, argv[i] ) ) {
408             return 1;
409         }
410 #if DEBUG
411         print_source( p );
412 #endif
413     }
414     return 0;
415 }
416
417 static int fusefile_getattr(const char *path,struct stat *stbuf) {
418 #if DEBUG
419     fprintf( stderr, "fusefile_getattr( %s )\n", path );
420 #endif
421     if ( strcmp( path, "/" ) != 0 ) {
422         return -ENOENT;
423     }
424 #if DEBUG
425     fprintf( stderr, "getattr %ld\n", sources.size );
426 #endif
427     memset( stbuf, 0, sizeof( struct stat ) );
428     stbuf->st_mode = S_IFREG | 0644; // Hmmm
429     stbuf->st_nlink = 1;
430     stbuf->st_size = sources.size;
431     stbuf->st_atime = times.atime;
432     stbuf->st_mtime = times.mtime;
433     stbuf->st_ctime = times.ctime;
434     stbuf->st_uid = getuid();
435     stbuf->st_gid = getgid();
436     return 0;
437 }
438
439 static int fusefile_chmod(const char *path,mode_t m) {
440 #if DEBUG
441     fprintf( stderr, "fusefile_chmod( %s, %d )\n", path, m );
442 #endif
443     return -1;
444 }
445
446 static int fusefile_open(const char *path,struct fuse_file_info *fi) {
447 #if DEBUG
448     fprintf( stderr, "fusefile_open( %s, %d )\n", path, fi->flags );
449     fprintf( stderr, "fixing( %d )\n", fi->flags | O_CLOEXEC );
450 #endif
451     if ( strcmp( path, "/" ) != 0 ) {
452         return -ENOENT;
453     }
454     // set O-CLOEXEC  for this opening?
455     times.atime = time( 0 );
456     return 0;
457 }
458
459 static int find_source(off_t offset) {
460     int lo = 0;
461     int hi = sources.count;
462     if ( offset >= sources.size ) {
463         return -1;
464     }
465 #if DEBUG
466     fprintf( stderr, "find_source( %ld )\n", offset );
467 #endif
468     while ( lo + 1 < hi ) {
469         int m = ( lo + hi ) / 2;
470         if ( offset < sources.array[ m ].start ) {
471 #if DEBUG
472             fprintf( stderr, "  offset < [%d].start: %ld\n",
473                      m, sources.array[ m ].start );
474 #endif
475             hi = m;
476         } else {
477 #if DEBUG
478             fprintf( stderr, "  offset >= [%d].start: %ld\n",
479                      m, sources.array[ m ].start );
480 #endif
481             lo = m;
482         }
483     }
484 #if DEBUG
485     fprintf( stderr, "found %d\n", lo );
486 #endif
487     return lo;
488 }
489
490 static int overlay_merge(char *buf,off_t beg,off_t end) {
491 #if DEBUG
492     fprintf( stderr, "merge %ld %ld\n", beg, end );
493 #endif
494     // Find nearest overlay data before or at beg
495     ssize_t p = overlay_prior_fragment( beg );
496     if ( p < 0 ) {
497         p = 0;
498     }
499     for ( ; p < overlay.count && overlay.table[p].beg < end; p++ ) {
500         if ( overlay.table[p].end < beg ) {
501             continue;
502         }
503         if ( overlay.table[p].beg > beg ) {
504             size_t delta = overlay.table[p].beg - beg;
505             buf += delta;
506             beg += delta;
507         }
508         size_t size = ( overlay.table[p].end <= end )?
509             ( overlay.table[p].end - beg ) : ( end - beg ); 
510         lseek( overlay.source.fd, beg, SEEK_SET );
511         while ( size > 0 ) {
512             size_t n = read( overlay.source.fd, buf, size );
513             size -= n;
514             buf += n;
515             beg += n; //
516         }
517     }
518     return 0;
519 }
520
521 // Read <size> bytes from <offset> in file
522 static int fusefile_read(const char *path, char *buf, size_t size,
523                          off_t off, struct fuse_file_info *fi)
524 {
525 #if DEBUG
526     fprintf( stderr, "fusefile_read( %s )\n", path );
527 #endif
528     if( strcmp( path, "/" ) != 0 ) {
529         return -ENOENT;
530     }
531 #if DEBUG
532     fprintf( stderr, "read %ld %ld\n", off, size );
533 #endif
534     size_t rr = 0; // total reading
535     while ( size > 0 ) {
536 #if DEBUG
537         fprintf( stderr, "  find_source %ld %ld\n", off, size );
538 #endif
539         int i = find_source( off );
540         if ( i < 0 ) {
541             return ( off == sources.size )? rr : -ENOENT;
542         }
543         if ( sources.array[i].fd < 0 ) {
544             return -ENOENT;
545         }
546 #if DEBUG
547         print_source( &sources.array[i] );
548 #endif
549         times.atime = time( 0 );
550         size_t b = off - sources.array[i].start + sources.array[i].from;
551         size_t n = sources.array[i].to - b;
552         if ( n > size ) {
553             n = size;
554         }
555         if ( sources.array[i].dirty ) {
556             fsync( sources.array[i].fd );
557             sources.array[i].dirty = 0;
558         }
559 #if DEBUG
560         fprintf( stderr, "  seek fd=%d to %ld\n", sources.array[i].fd, b );
561 #endif
562         if ( lseek( sources.array[i].fd, b, SEEK_SET ) < 0 ) {
563             perror( sources.array[i].filename );
564             return -ENOENT;
565         }
566 #if DEBUG
567         fprintf( stderr, "  now read %ld from fd=%d\n",
568                  n, sources.array[i].fd );
569 #endif
570         ssize_t r = read( sources.array[i].fd, buf + rr, n );
571 #if DEBUG
572         fprintf( stderr, "  got %ld bytes\n", r );
573 #endif
574         if ( r < 0 ) {
575             perror( sources.array[i].filename );
576             return -ENOENT;
577         }
578         if ( r == 0 ) {
579             break;
580         }
581         if ( overlay.source.filename ) {
582             if ( overlay.source.dirty ) {
583                 fsync( overlay.source.fd );
584                 overlay.source.dirty = 0;
585             }
586             int x = overlay_merge( buf + rr, off + rr, off + rr + r );
587             if ( x ) {
588                 return x;
589             }
590         }
591         rr += r;
592         off += r;
593         size -= r;
594     }
595 #if DEBUG
596     fprintf( stderr, "  total reading %ld bytes\n", rr );
597 #endif
598     return rr;
599 }
600
601 /**
602  * Poll for IO readiness.
603  */
604 int fusefile_poll(const char *path, struct fuse_file_info *fi,
605                    struct fuse_pollhandle *ph, unsigned *reventsp )
606 {
607 #if DEBUG
608     fprintf( stderr, "fusefile_poll( %s ) %p %d\n", path, ph, *reventsp );
609 #endif
610     if( strcmp( path, "/" ) != 0 ) {
611         return -ENOENT;
612     }
613     if ( ph ) {
614         return fuse_notify_poll( ph );
615     }
616     return 0;
617 }
618
619 static void overlay_load() {
620     lseek( overlay.source.fd, overlay.source.to, SEEK_SET );
621     size_t x = 0;
622     size_t size = sizeof( overlay.count );
623     if ( read( overlay.source.fd, &x, size ) != size ) {
624         return;
625     }
626 #if DEBUG
627     fprintf( stderr, "overlay: %s with %ld regions\n",
628              overlay.source.filename, x );
629 #endif
630     struct Region f = { 0, 0 };
631     size = sizeof( struct Region );
632     while ( x-- > 0 ) {
633         if ( read( overlay.source.fd, &f, size ) != size ) {
634             fprintf( stderr, "%s: bad meta data\n", overlay.source.filename );
635             exit( 1 );
636         }
637 #if DEBUG
638         fprintf( stderr, "overlay region: %ld %ld\n", f.beg, f.end );
639 #endif
640         overlay_mark( f.beg, f.end );
641     }
642 }
643
644 /**
645  * Inject an overlay fragment into the source table, end return the
646  * end of the injected fragment.
647  */
648 static off_t overlay_inject_from_region(off_t beg,off_t end) {
649     int index = find_source( beg );
650     if ( index < 0 ) {
651         fprintf( stderr, "** Injecting %s at %ld failed\n",
652                  overlay.source.filename, beg );
653         usage();
654     }
655     if ( end > ENDSOURCE( sources.array[ index ] ) ) {
656         end = ENDSOURCE( sources.array[ index ] );
657     }
658     struct Region frags[3] = {
659         { sources.array[ index ].start, beg },
660         { beg, ENDSOURCE( sources.array[ index ] ) },
661         { ENDSOURCE( sources.array[ index ] ), end } };
662     ssize_t size = frags[0].end - frags[0].beg;
663     if ( size ) {
664         // "Duplicate" the indexed source data, copying the filename
665         dup_source_item( index );
666         sources.array[ index ].to = sources.array[ index ].from + size;
667         index++;
668         sources.array[ index ].start = beg;
669         sources.array[ index ].from = sources.array[ index-1 ].to;
670     }
671     size = frags[2].end - frags[2].beg;
672     if ( size ) {
673         dup_source_item( index );
674         sources.array[ index+1 ].start = frags[2].beg;
675         sources.array[ index+1 ].from = sources.array[ index+1 ].to -size;
676     }
677     // Replace the [index] fragment
678     sources.array[ index ].filename = overlay.source.filename;
679     sources.array[ index ].start = beg;
680     sources.array[ index ].from = beg;
681     sources.array[ index ].to = end;
682     sources.array[ index ].fd = overlay.source.fd; //?
683     return end;
684 }
685
686 /**
687  * Inject the current (unopened) overlay into the source list.
688  */
689 static void overlay_inject() {
690     overlay.source.fd = open( overlay.source.filename, O_RDONLY );
691     if ( overlay.source.fd < 0 ) {
692         perror( overlay.source.filename );
693         usage();
694     }
695     
696     if ( lseek( overlay.source.fd, overlay.source.to, SEEK_SET ) < 0 ) {
697         perror( overlay.source.filename );
698         usage();
699     }
700     size_t count = 0;
701     size_t size = sizeof( overlay.count );
702     if ( read( overlay.source.fd, &count, size ) != size ) {
703         fprintf( stderr, "** error injecting %s\n", overlay.source.filename );
704         usage();
705     }
706     if ( count == 0 ) {
707         close( overlay.source.fd );
708         return;
709     }
710     size = count * sizeof( struct Region );
711     overlay.table = calloc( sizeof( struct Region ), count );
712     if ( read( overlay.source.fd, overlay.table, size ) != size ) {
713         fprintf( stderr, "** error injecting %s\n", overlay.source.filename );
714         usage();
715     }
716     size_t i;
717     for ( i = 0; i < count; i++ ) {
718         off_t beg = overlay.table[i].beg;
719         while ( beg < overlay.table[i].end ) {
720             beg = overlay_inject_from_region( beg, overlay.table[i].end );
721         }
722     }
723     free( overlay.table );
724     overlay.table = 0;
725     close( overlay.source.fd );
726 }
727
728 /**
729  * Each stacked overlay file is nested into to source list
730  */
731 static void overlay_post_setup() {
732     char *end;
733     while ( ( end = strchr( overlay.source.filename, ':' ) ) ) {
734         *end = 0; //  
735         overlay_inject();
736         overlay.source.filename = end + 1;
737     }
738     if ( *overlay.source.filename ) {
739         overlay.source.fd = open( overlay.source.filename,
740                                   O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
741         if ( overlay.source.fd < 0 ) {
742             perror( overlay.source.filename );
743             usage();
744         }
745         overlay_load();
746     }
747 }
748
749 /**
750  * Write a full block of data over the sources at the offset
751  */
752 static int write_block(off_t off,const char *buf,size_t size) {
753 #if DEBUG
754     fprintf( stderr, "write_block( %ld, ?, %ld )\n", off, size );
755 #endif
756     if ( overlay.source.filename ) {
757         overlay_mark( off, off + size ); // Mark region as written
758     }
759     while ( size > 0 ) {
760         int index = find_source( off ); // index of source file
761         if ( index < 0 ) {
762             return -EIO; // past EOF
763         }
764         struct Source *source = overlay.source.filename?
765             &overlay.source :  &sources.array[ index ];
766         off_t from = off - source->start + source->from;
767         off_t max = source->to - from;
768         if ( lseek( source->fd, from, SEEK_SET ) < 0 ) {
769             return -EIO;
770         }
771         ssize_t todo = ( size < max )? size : max;
772         while ( todo > 0 ) {
773             times.mtime = time( 0 );
774             ssize_t n = write( source->fd, buf, todo );
775             if ( n <= 0 ) {
776                 return -EIO; // Something wrong
777             }
778             buf += n;
779             todo -= n;
780             size -= n;
781             off += n;
782         }
783         if ( source->dirty++ >= 1000 ) {
784             fsync( source->fd );
785             source->dirty = 0;
786         }
787     }
788     return 0;
789 }
790
791 static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf,
792                               off_t off, struct fuse_file_info *fi) {
793 #if DEBUG
794     fprintf( stderr, "fusefile_write_buf( %s )\n", path );
795 #endif
796     if ( strcmp( path, "/" ) != 0 ) {
797         return -ENOENT;
798     }
799
800     size_t size = 0;
801     int i;
802     for ( i = 0; i < buf->count; i++ ) {
803         struct fuse_buf *p = &buf->buf[i];
804         if ( p->flags & FUSE_BUF_IS_FD ) {
805 #if DEBUG
806             fprintf( stderr, "Content held in a file ... HELP!!\n" );
807 #endif
808             return -EIO;
809         }
810         if ( write_block( off, (char*) p->mem, p->size ) < 0 ) {
811             return -EIO;
812         }
813         size += p->size;
814     }
815 #if DEBUG
816     fprintf( stderr, "fusefile_write_buf written %ld\n", size );
817 #endif
818     return size;
819 }
820
821 /**
822  * Write a fragment at <off>. This overwrites files.
823  */
824 static int fusefile_write(const char *path, const char *buf, size_t size,
825                           off_t off, struct fuse_file_info *fi)
826 {
827 #if DEBUG
828     fprintf( stderr, "fusefile_write( %s %ld )\n", path, size );
829 #endif
830     if ( strcmp( path, "/" ) != 0 ) {
831         return -ENOENT;
832     }
833
834     if ( write_block( off, buf, size ) < 0 ) {
835         return -EIO;
836     }
837     return size;
838 }
839
840 #define PUSHBUF 104857600
841 /**
842  * Write data from overlay to source.
843  */
844 static void push_oly(off_t beg, off_t end) {
845     static char * buffer = 0;
846     // Pretend that there isn't an overlay
847     char *filename = overlay.source.filename;
848     if ( buffer == 0 ) {
849         buffer = malloc( PUSHBUF );
850         if ( buffer == 0 ) {
851             fprintf( stderr, "** OOM!!\n" );
852             exit( 1 );
853         }
854     }
855     overlay.source.filename = 0;
856     while ( beg < end ) {
857         off_t size = end - beg;
858         if ( size > PUSHBUF ) {
859             size = PUSHBUF;
860         }
861         if ( lseek( overlay.source.fd, beg, SEEK_SET ) < 0 ) {
862             fprintf( stderr, "** Cannot seek overlay at %ld\n", beg );
863             break;
864         }
865         size = read( overlay.source.fd, buffer, size );
866         if ( write_block( beg, buffer, size ) < 0 ) {
867             fprintf( stderr, "** Cannot push %ld bytes at %ld\n", size, beg );
868         }
869         beg += size;
870     }
871     overlay.source.filename = filename;
872 }
873
874 static void fusefile_destroy(void *data) {
875     char *mnt = (char*) data; // As passed to fuse_main
876 #if DEBUG
877     fprintf( stderr, "fusefile_destroy( %s )\n", mnt? mnt : "" );
878 #endif
879     if ( mnt ) {
880         unlink( mnt );
881     }
882 }
883
884 static void fsync_all_dirty() {
885     int i = 0;
886     for ( ; i < sources.count; i++ ) {
887         if ( sources.array[i].dirty ) {
888             fsync( sources.array[i].fd );
889             sources.array[i].dirty = 0;
890         }
891     }
892     if ( overlay.source.filename && overlay.source.dirty ) {
893         fsync( overlay.source.fd );
894         overlay.source.dirty = 0;
895     }
896 }
897
898 static int fusefile_flush(const char *path, struct fuse_file_info *info) {
899 #if DEBUG
900     fprintf( stderr, "fusefile_flush( %s )\n", path );
901 #endif
902     if ( strcmp( path, "/" ) != 0 ) {
903         return -ENOENT;
904     }
905     fsync_all_dirty();
906     return 0;
907 }
908
909 static int fusefile_release(const char *path, struct fuse_file_info *fi) {
910 #if DEBUG
911     fprintf( stderr, "fusefile_release( %s, %d )\n", path, fi->flags );
912 #endif
913     if ( strcmp( path, "/" ) != 0 ) {
914         return -ENOENT;
915     }
916     return 0;
917 }
918
919 static int fusefile_fsync(const char *path, int x, struct fuse_file_info *fi) {
920 #if DEBUG
921     fprintf( stderr, "fusefile_fsync( %s, %d )\n", path, x );
922 #endif
923     if ( strcmp( path, "/" ) != 0 ) {
924         return -ENOENT;
925     }
926     fsync_all_dirty();
927     return 0;
928 }
929
930 /**
931  * 
932  */
933 static int fusefile_truncate(const char *path, off_t len) {
934 #if DEBUG
935     fprintf( stderr, "fusefile_truncate( %s, %ld )\n", path, len );
936 #endif
937     if ( strcmp( path, "/" ) != 0 ) {
938         return -ENOENT;
939     }
940     return -EIO;
941 }
942
943 void *fusefile_init(struct fuse_conn_info *fci) {
944 #if DEBUG
945     fprintf( stderr, "fusefile_init( %d, %d )\n", fci->async_read, fci->want );
946 #endif
947     // Disable asynchronous reading
948     fci->async_read = 0;
949     fci->want &= ~FUSE_CAP_ASYNC_READ;
950 #if DEBUG
951     fprintf( stderr, "fusefile_init( %d, %d )\n", fci->async_read, fci->want );
952 #endif
953     return 0;
954 }
955
956 /**
957  * Dump the current fragmentation to stdout.
958  */
959 static int dump_fragments(int push) {
960     int oly = 0;
961     int src = 0;
962     size_t pos = 0;
963     while ( src < sources.count ) {
964         size_t x = ( oly < overlay.count )?
965             overlay.table[ oly ].beg : sources.size;
966         for ( ; src < sources.count && 
967                   ENDSOURCE( sources.array[ src ] ) <= x; src++ ) {
968             // Dump sources.array[src] in full
969             if ( !push ) {
970                 fprintf( stdout, "%s/%ld:%ld\n",
971                          sources.array[ src ].filename,
972                          pos - sources.array[ src ].start,
973                          sources.array[ src ].to );
974             }
975             pos = ENDSOURCE( sources.array[ src ] );
976         }
977         if ( ( src < sources.count ) && ( sources.array[ src ].start < x ) ) {
978             // Dump sources.array[src] up to x;
979             if ( !push ) {
980                 fprintf( stdout, "%s/%ld:%ld\n",
981                          sources.array[ src ].filename,
982                          pos - sources.array[ src ].start,
983                          x - sources.array[ src ].start );
984             }
985             pos = ENDSOURCE( sources.array[ src ] );
986         }
987         if ( oly < overlay.count ) {
988             if ( !push ) {
989                 fprintf( stdout, "%s/%ld:%ld\n",
990                          overlay.source.filename,
991                          overlay.table[ oly ].beg,
992                          overlay.table[ oly ].end );
993             } else {
994                 push_oly( overlay.table[ oly ].beg, overlay.table[ oly ].end );
995             }
996             pos = overlay.table[ oly++ ].end;
997         }
998         for ( ; src < sources.count &&
999                   ENDSOURCE( sources.array[ src ] ) <= pos; src++ ) {
1000             // Just skip these fragments.
1001         }
1002     }
1003     return( 0 );
1004 }
1005
1006 static struct fuse_operations fusefile_oper = {
1007     .getattr = fusefile_getattr,
1008     // NYI .fgetattr = fusefile_fgetattr,
1009     .chmod = fusefile_chmod,
1010     .open = fusefile_open,
1011     .read = fusefile_read,
1012     .poll = fusefile_poll,
1013     .write = fusefile_write,
1014     .write_buf = fusefile_write_buf,
1015     .destroy = fusefile_destroy,
1016     // NYI .access = fusefile_access,
1017     .flush = fusefile_flush,
1018     .release = fusefile_release,
1019     .fsync = fusefile_fsync,
1020     // NYI .ftruncate = fusefile_ftruncate,
1021     .truncate = fusefile_truncate,
1022     //.truncate = fusefile_truncate,
1023     //.release = fusefile_release,
1024     .init = fusefile_init,
1025 };
1026
1027 static void usage() {
1028     char *usage =
1029 "Usage: fusefile [ <fuse options> ] <mount> <file/from-to> ... \n"
1030 "Mounts a virtual, file that is a concatenation of file fragments\n"
1031         ;
1032     fprintf( stderr, "%s", usage );
1033     exit( 1 );
1034 }
1035
1036 /**
1037  * Set up the arguments for the fuse_main call, adding our own.
1038  * argv[argc] is the mount point argument
1039  */
1040 static int setup_argv(int argc,char ***argv) {
1041     // note: (*argv)[ argc ] is the mount point argument
1042     char *OURS[] = {
1043         "-odefault_permissions",
1044         (*argv)[ argc ]
1045     };
1046 #define OURSN ( sizeof( OURS ) / sizeof( char* ) )
1047     int N = argc + OURSN;
1048     // Allocate new arg array plus terminating null pointer
1049     char **out = malloc( ( N + 1 ) * sizeof( char* ) ); 
1050     int i;
1051     for ( i = 0; i < argc; i++ ) {
1052         out[ i ] = (*argv)[i];
1053         //fprintf( stderr, " %s", out[ i ] );
1054     }
1055     for ( i = 0; i < OURSN; i++ ) {
1056         out[ argc + i ] = OURS[i];
1057         //fprintf( stderr, " %s", out[ i ] );
1058     }
1059     out[ N ] = 0;
1060     //fprintf( stderr, "\n" );
1061     (*argv) = out;
1062     return N; // Don't include the terminating null pointer
1063 }
1064
1065 /**
1066  * Mount a concatenation of files,
1067  * [ <fuse options> ] <mount> <file/from-to> ...
1068  */
1069 int main(int argc, char *argv[])
1070 {
1071     char *mnt;
1072     int mt;
1073     int fg;
1074     int i;
1075     int fuseargc;
1076     struct stat stbuf;
1077     int temporary = 0;
1078     // Scan past options
1079     for ( i = 1; i < argc; i++ ) {
1080         if ( *argv[i] != '-' ) {
1081             break;
1082         }
1083     }
1084     if ( i > argc - 2 ) { // At least mount point plus one source
1085         usage();
1086     }
1087     fuseargc = i;
1088     mnt = argv[ i++ ]; // First non-option argument is the mount pount
1089     #define OVERLAYTAG "-overlay:"
1090     if ( strncmp( argv[i], OVERLAYTAG, strlen( OVERLAYTAG ) ) == 0 ) {
1091         // consume "-overlay:filename[,filename]*"
1092         overlay_setup( argv[i++] + strlen( OVERLAYTAG ) );
1093         if ( i >= argc ) {
1094             usage();
1095         }
1096     }
1097     if ( setup_sources( argv, i, argc-i ) ) {
1098         return 1;
1099     }
1100     if ( overlay.source.filename ) {
1101         overlay.source.to = sources.size; // Register total size.
1102         overlay_post_setup();
1103     }
1104     if ( stat( mnt, &stbuf ) == -1 ) {
1105         int fd = open( mnt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
1106         if ( fd < 0 ) {
1107             perror( mnt );
1108             return 1;
1109         }
1110         time_t now = time( 0 );
1111         times.atime = now;
1112         times.mtime = now;
1113         times.ctime = now;
1114         temporary = 1;
1115         close( fd );
1116     } else if ( ! S_ISREG( stbuf.st_mode ) ) {
1117         fprintf( stderr, "mountpoint is not a regular file\n" );
1118         return 1;
1119     } else {
1120         times.atime = stbuf.st_atime;
1121         times.mtime = stbuf.st_mtime;
1122         times.ctime = stbuf.st_ctime;
1123     }
1124
1125     {
1126         int fd = open( mnt, O_RDWR, S_IRUSR | S_IWUSR );
1127         if ( fd < 0 ) {
1128             perror( mnt );
1129             return 1;
1130         }
1131         if ( lseek( fd, sources.size, SEEK_SET ) < 0 ) {
1132             return -EIO;
1133         }
1134     }
1135     fuseargc = setup_argv( fuseargc, &argv );
1136     if ( strcmp( "-dump", argv[ 1 ] ) == 0 ) {
1137         return dump_fragments( 0 );
1138     }
1139     if ( strcmp( "-push", argv[ 1 ] ) == 0 ) {
1140         return dump_fragments( 1 );
1141     }
1142     struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv );
1143     if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) {
1144         return 1;
1145     }
1146     fuse_opt_free_args( &args );
1147     if ( ! mnt ) {
1148         fprintf( stderr, "missing mountpoint parameter\n" );
1149         return 1;
1150     }
1151     return fuse_main( fuseargc, argv, &fusefile_oper, temporary? mnt : NULL );
1152 }