Corrected the "-dump" report of fragment start position.
[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     // copy elements from [index] to [count-1] one element down
294     size_t size = ( sources.count - index - 1 ) * sizeof( struct Source ); 
295     memmove( &sources.array[ index+1 ], &sources.array[ index ], size );
296 }
297
298 #if DEBUG
299 static void print_source(struct Source *p) {
300     fprintf( stderr, "%p { %s, %ld, %ld, %ld, %d }\n",
301              p, p->filename, p->from, p->to, p->start, p-> fd );
302 }
303 #endif
304
305 static char *range;
306 static unsigned int c;
307 static int RANGE(int s,int n ) {
308     return ( s == n ) && *(range+c) == 0;
309 }
310
311 static int setup_source(struct Source *p,char *frag) {
312     struct stat filestat;
313     // Open the fragment file rw if possible, else ro
314     // First try the fragment in full, thereafter with range appendix
315     if ( stat( frag, &filestat ) == 0 ) {
316         p->filename = strdup( frag );
317         range = 0;
318     } else {
319         range = strrchr( frag, '/' ); // last '/'
320         p->filename = range? strndup( frag, range - frag ) : frag;
321     }
322     p->fd = open( p->filename, O_RDWR );
323     int rdonly = 0;
324     if ( p->fd < 0 ) {
325         rdonly = 1;
326         p->fd = open( p->filename, O_RDONLY );
327     }
328     if ( p->fd < 0 ) {
329         perror( p->filename );
330         return 1; // Error return
331     }
332     if ( ( range != 0 ) && stat( p->filename, &filestat ) ) {
333         perror( p->filename );
334         return 1; 
335     }
336     if ( rdonly ) {
337         fprintf( stderr, "** %s opened read-only\n", p->filename );
338     }
339     p->from = 0;
340     if ( S_ISBLK( filestat.st_mode ) ) {
341         // Block devices report size differently:
342         if ( ioctl( p->fd, BLKGETSIZE64, &filestat.st_size ) < 0 ) {
343             perror( p->filename );
344         }
345 #if DEBUG
346         fprintf( stderr, "block device size = %ld\n", filestat.st_size );
347 #endif
348     }
349     p->to = filestat.st_size;
350     // Process any range variation
351     if ( range && *(++range) ) {
352         long int a,b;
353         if ( 0 ) {
354         } else if ( RANGE( sscanf( range, "%ld:%ld%n", &a, &b, &c ), 2 )) {
355             p->from = ( a < 0 )? ( p->to + a ) : a;
356             p->to = ( b < 0 )? ( p->to + b ) : b;
357         } else if ( RANGE( sscanf( range, "%ld+%ld%n", &a, &b, &c ), 2 )) {
358             p->from = ( a < 0 )? ( p->to + a ) : a;
359             p->to = ( ( b < 0 )? p->to : p->from ) + b;
360         } else if ( RANGE( sscanf( range, "%ld+%n", &a, &c ), 1 )) {
361             p->from = ( a < 0 )? ( p->to + a ) : a;
362         } else if ( RANGE( sscanf( range, ":%ld%n", &b, &c ), 1 )) {
363             p->to = ( b < 0 )? ( p->to + b ) : b;
364         } else if ( RANGE( sscanf( range, "%ld:%n", &a, &c ), 1 )) {
365             p->from = ( a < 0 )? ( p->to + a ) : a;
366         } else if ( RANGE( sscanf( range, "%ld%n", &a, &c ), 1 )) {
367             if ( a >= 0 ) {
368                 p->from = a;
369             } else {
370                 p->from = p->to + a;
371             }
372         } else if ( RANGE( sscanf( range, ":%n", &c), 0 ) ) {
373             // to end from start
374         } else {
375             fprintf( stderr, "** BAD RANGE: %s\n", frag );
376             return 1;
377         }
378     }
379     if ( ( filestat.st_mode &  S_IFMT ) == S_IFCHR ) {
380         filestat.st_size = p->to; // Pretend size of character device
381     }
382     if ( p->from < 0 ) {
383         p->from = 0;
384     }
385     if ( p->to > filestat.st_size ) {
386         p->to = filestat.st_size;
387     }
388     if ( p->from >= p->to || p->from >= filestat.st_size ) {
389         fprintf( stderr, "** BAD RANGE: %s [%ld:%ld]\n",
390                  frag, p->from, p->to );
391         return 1;
392     }
393     p->start = sources.size; // the fusefile position of fragment
394     sources.size += p->to - p->from;
395     return 0;
396 }
397
398 static int setup_sources(char **argv,int i,int n) {
399     sources.array = calloc( n, sizeof( struct Source ) );
400     if ( sources.array == 0 ) {
401         return 1;
402     }
403     sources.count = n;
404     int j = 0;
405     sources.size = 0;
406     for ( ; j < n; i++, j++ ) {
407         struct Source *p = sources.array + j;
408         if ( setup_source( p, argv[i] ) ) {
409             return 1;
410         }
411 #if DEBUG
412         print_source( p );
413 #endif
414     }
415     return 0;
416 }
417
418 static int fusefile_getattr(const char *path,struct stat *stbuf) {
419 #if DEBUG
420     fprintf( stderr, "fusefile_getattr( %s )\n", path );
421 #endif
422     if ( strcmp( path, "/" ) != 0 ) {
423         return -ENOENT;
424     }
425 #if DEBUG
426     fprintf( stderr, "getattr %ld\n", sources.size );
427 #endif
428     memset( stbuf, 0, sizeof( struct stat ) );
429     stbuf->st_mode = S_IFREG | 0644; // Hmmm
430     stbuf->st_nlink = 1;
431     stbuf->st_size = sources.size;
432     stbuf->st_atime = times.atime;
433     stbuf->st_mtime = times.mtime;
434     stbuf->st_ctime = times.ctime;
435     stbuf->st_uid = getuid();
436     stbuf->st_gid = getgid();
437     return 0;
438 }
439
440 static int fusefile_chmod(const char *path,mode_t m) {
441 #if DEBUG
442     fprintf( stderr, "fusefile_chmod( %s, %d )\n", path, m );
443 #endif
444     return -1;
445 }
446
447 static int fusefile_open(const char *path,struct fuse_file_info *fi) {
448 #if DEBUG
449     fprintf( stderr, "fusefile_open( %s, %d )\n", path, fi->flags );
450     fprintf( stderr, "fixing( %d )\n", fi->flags | O_CLOEXEC );
451 #endif
452     if ( strcmp( path, "/" ) != 0 ) {
453         return -ENOENT;
454     }
455     // set O-CLOEXEC  for this opening?
456     times.atime = time( 0 );
457     return 0;
458 }
459
460 static int find_source(off_t offset) {
461     int lo = 0;
462     int hi = sources.count;
463     if ( offset >= sources.size ) {
464         return -1;
465     }
466     while ( lo + 1 < hi ) {
467         int m = ( lo + hi ) / 2;
468         if ( offset < sources.array[ m ].start ) {
469             hi = m;
470         } else {
471             lo = m;
472         }
473     }
474     return lo;
475 }
476
477 static int overlay_merge(char *buf,off_t beg,off_t end) {
478 #if DEBUG
479     fprintf( stderr, "merge %ld %ld\n", beg, end );
480 #endif
481     // Find nearest overlay data before or at beg
482     ssize_t p = overlay_prior_fragment( beg );
483     if ( p < 0 ) {
484         p = 0;
485     }
486     for ( ; p < overlay.count && overlay.table[p].beg < end; p++ ) {
487         if ( overlay.table[p].end < beg ) {
488             continue;
489         }
490         if ( overlay.table[p].beg > beg ) {
491             size_t delta = overlay.table[p].beg - beg;
492             buf += delta;
493             beg += delta;
494         }
495         size_t size = ( overlay.table[p].end <= end )?
496             ( overlay.table[p].end - beg ) : ( end - beg ); 
497         lseek( overlay.source.fd, beg, SEEK_SET );
498         while ( size > 0 ) {
499             size_t n = read( overlay.source.fd, buf, size );
500             size -= n;
501             buf += n;
502             beg += n; //
503         }
504     }
505     return 0;
506 }
507
508 // Read <size> bytes from <offset> in file
509 static int fusefile_read(const char *path, char *buf, size_t size,
510                          off_t off, struct fuse_file_info *fi)
511 {
512     if( strcmp( path, "/" ) != 0 ) {
513         return -ENOENT;
514     }
515     size_t rr = 0; // total reading
516 #if DEBUG
517     fprintf( stderr, "fusefile_read %ld + %ld\n", off, size );
518 #endif
519     while ( size > 0 ) {
520         int i = find_source( off );
521         if ( i < 0 ) {
522             return ( off == sources.size )? rr : -ENOENT;
523         }
524 #if DEBUG
525         fprintf( stderr, " item: %d ", i );
526         print_source(& sources.array[i] );
527 #endif
528         if ( sources.array[i].fd < 0 ) {
529             return -ENOENT;
530         }
531         times.atime = time( 0 );
532         size_t b = off - sources.array[i].start + sources.array[i].from;
533         size_t n = sources.array[i].to - b;
534         if ( n > size ) {
535             n = size;
536         }
537         if ( sources.array[i].dirty ) {
538             fsync( sources.array[i].fd );
539             sources.array[i].dirty = 0;
540         }
541         if ( lseek( sources.array[i].fd, b, SEEK_SET ) < 0 ) {
542             perror( sources.array[i].filename );
543             return -ENOENT;
544         }
545         ssize_t r = read( sources.array[i].fd, buf + rr, n );
546 #if DEBUG
547         fprintf( stderr, " got: %ld bytes of %ld at %ld\n", r, n, rr );
548 #endif
549         if ( r < 0 ) {
550             perror( sources.array[i].filename );
551             return -ENOENT;
552         }
553         if ( r == 0 ) {
554             break;
555         }
556         if ( overlay.source.filename ) {
557             if ( overlay.source.dirty ) {
558                 fsync( overlay.source.fd );
559                 overlay.source.dirty = 0;
560             }
561             int x = overlay_merge( buf + rr, off + rr, off + rr + r );
562             if ( x ) {
563                 return x;
564             }
565         }
566         rr += r;
567         off += r;
568         size -= r;
569     }
570 #if DEBUG
571     fprintf( stderr, "  total reading %ld bytes\n", rr );
572 #endif
573     return rr;
574 }
575
576 /**
577  * Poll for IO readiness.
578  */
579 int fusefile_poll(const char *path, struct fuse_file_info *fi,
580                    struct fuse_pollhandle *ph, unsigned *reventsp )
581 {
582 #if DEBUG
583     fprintf( stderr, "fusefile_poll( %s ) %p %d\n", path, ph, *reventsp );
584 #endif
585     if( strcmp( path, "/" ) != 0 ) {
586         return -ENOENT;
587     }
588     if ( ph ) {
589         return fuse_notify_poll( ph );
590     }
591     return 0;
592 }
593
594 static void overlay_load() {
595     lseek( overlay.source.fd, overlay.source.to, SEEK_SET );
596     size_t x = 0;
597     size_t size = sizeof( overlay.count );
598     if ( read( overlay.source.fd, &x, size ) != size ) {
599         return;
600     }
601 #if DEBUG
602     fprintf( stderr, "overlay: %s with %ld regions\n",
603              overlay.source.filename, x );
604 #endif
605     struct Region f = { 0, 0 };
606     size = sizeof( struct Region );
607     while ( x-- > 0 ) {
608         if ( read( overlay.source.fd, &f, size ) != size ) {
609             fprintf( stderr, "%s: bad meta data\n", overlay.source.filename );
610             exit( 1 );
611         }
612 #if DEBUG
613         fprintf( stderr, "overlay region: %ld %ld\n", f.beg, f.end );
614 #endif
615         overlay_mark( f.beg, f.end );
616     }
617 }
618
619 /**
620  * Inject an overlay fragment into the source table, end return the
621  * end of the injected fragment.
622  */
623 static off_t overlay_inject_from_region(off_t beg,off_t end) {
624     int index = find_source( beg );
625     if ( index < 0 ) {
626         fprintf( stderr, "** Injecting %s at %ld failed\n",
627                  overlay.source.filename, beg );
628         usage();
629     }
630     if ( end > ENDSOURCE( sources.array[ index ] ) ) {
631         end = ENDSOURCE( sources.array[ index ] );
632     }
633     struct Region frags[3] = {
634         { sources.array[ index ].start, beg },
635         { beg, end },
636         { end, ENDSOURCE( sources.array[ index ] ) } };
637 #if DEBUG
638     int i;
639     for ( i = 0; i < 3; i++ ) {
640         fprintf( stderr, "frags[%d] = (%ld, %ld)\n",
641                  i, frags[i].beg, frags[i].end );
642     }
643 #endif
644     ssize_t size = frags[0].end - frags[0].beg;
645     if ( size ) {
646         // Handle any portion before injection point.
647         dup_source_item( index );
648         off_t point = sources.array[ index ].from + size;
649         sources.array[ index ].to = point;
650 #if DEBUG
651         fprintf( stderr, "item %d ", index );
652         print_source( &sources.array[ index ] );
653 #endif
654         // Adjust item after injection point
655         index++;
656         sources.array[ index ].start = beg;
657         sources.array[ index ].from = point;
658 #if DEBUG
659         fprintf( stderr, "item %d adjust ", index );
660         print_source( &sources.array[ index ] );
661 #endif
662     }
663     size = frags[2].end - frags[2].beg;
664     if ( size ) {
665         // Handle any remaining portion following injection fragment
666         dup_source_item( index );
667         sources.array[ index+1 ].start = frags[2].beg;
668         sources.array[ index+1 ].from += frags[1].end - frags[1].beg;
669 #if DEBUG
670         fprintf( stderr, "item %d ", index+1 );
671         print_source( &sources.array[ index+1 ] );
672 #endif
673     }
674     // Set up the injection fragment
675     sources.array[ index ].filename = overlay.source.filename;
676     sources.array[ index ].from = beg;
677     sources.array[ index ].to = end;
678     sources.array[ index ].fd = overlay.source.fd;
679 #if DEBUG
680         fprintf( stderr, "item %d ", index );
681         print_source( &sources.array[ index ] );
682 #endif
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     size_t n;
703     if ( ( n = read( overlay.source.fd, &count, size ) ) != size ) {
704         if ( n != 0 ) {
705             fprintf( stderr, "** error injecting %s\n",
706                      overlay.source.filename );
707             usage();
708         }
709         fprintf( stderr, "** ignoring empty %s\n", overlay.source.filename );
710     }
711     if ( count == 0 ) {
712         close( overlay.source.fd );
713         return;
714     }
715     size = count * sizeof( struct Region );
716     overlay.table = calloc( sizeof( struct Region ), count );
717     if ( read( overlay.source.fd, overlay.table, size ) != size ) {
718         fprintf( stderr, "** error injecting %s\n", overlay.source.filename );
719         usage();
720     }
721     size_t i;
722     for ( i = 0; i < count; i++ ) {
723         off_t beg = overlay.table[i].beg;
724         while ( beg < overlay.table[i].end ) {
725 #if DEBUG
726             fprintf( stderr, "inject [%ld,%ld] ", beg, overlay.table[i].end );
727             print_source( &overlay.source );
728 #endif
729             
730             beg = overlay_inject_from_region( beg, overlay.table[i].end );
731         }
732     }
733     free( overlay.table );
734     overlay.table = 0;
735 }
736
737 /**
738  * Each stacked overlay file is nested into to source list
739  */
740 static void overlay_post_setup() {
741     char *end;
742     while ( ( end = strchr( overlay.source.filename, ':' ) ) ) {
743         *end = 0; //
744         overlay_inject();
745         overlay.source.filename = end + 1;
746     }
747     if ( *overlay.source.filename ) {
748         overlay.source.fd = open( overlay.source.filename,
749                                   O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
750         if ( overlay.source.fd < 0 ) {
751             perror( overlay.source.filename );
752             usage();
753         }
754         overlay_load();
755     }
756 }
757
758 /**
759  * Write a full block of data over the sources at the offset
760  */
761 static int write_block(off_t off,const char *buf,size_t size) {
762 #if DEBUG
763     fprintf( stderr, "write_block( %ld, ?, %ld )\n", off, size );
764 #endif
765     if ( overlay.source.filename ) {
766         overlay_mark( off, off + size ); // Mark region as written
767     }
768     while ( size > 0 ) {
769         int index = find_source( off ); // index of source file
770         if ( index < 0 ) {
771             return -EIO; // past EOF
772         }
773         struct Source *source = overlay.source.filename?
774             &overlay.source :  &sources.array[ index ];
775         off_t from = off - source->start + source->from;
776         off_t max = source->to - from;
777         if ( lseek( source->fd, from, SEEK_SET ) < 0 ) {
778             return -EIO;
779         }
780         ssize_t todo = ( size < max )? size : max;
781         while ( todo > 0 ) {
782             times.mtime = time( 0 );
783             ssize_t n = write( source->fd, buf, todo );
784             if ( n <= 0 ) {
785                 return -EIO; // Something wrong
786             }
787             buf += n;
788             todo -= n;
789             size -= n;
790             off += n;
791         }
792         if ( source->dirty++ >= 1000 ) {
793             fsync( source->fd );
794             source->dirty = 0;
795         }
796     }
797     return 0;
798 }
799
800 static int fusefile_write_buf(const char *path, struct fuse_bufvec *buf,
801                               off_t off, struct fuse_file_info *fi) {
802 #if DEBUG
803     fprintf( stderr, "fusefile_write_buf( %s )\n", path );
804 #endif
805     if ( strcmp( path, "/" ) != 0 ) {
806         return -ENOENT;
807     }
808     size_t size = 0;
809     int i;
810     for ( i = 0; i < buf->count; i++ ) {
811         struct fuse_buf *p = &buf->buf[i];
812         if ( p->flags & FUSE_BUF_IS_FD ) {
813 #if DEBUG
814             fprintf( stderr, "Content held in a file ... HELP!!\n" );
815 #endif
816             return -EIO;
817         }
818         if ( write_block( off, (char*) p->mem, p->size ) < 0 ) {
819             return -EIO;
820         }
821         size += p->size;
822     }
823 #if DEBUG
824     fprintf( stderr, "fusefile_write_buf written %ld\n", size );
825 #endif
826     return size;
827 }
828
829 /**
830  * Write a fragment at <off>. This overwrites files.
831  */
832 static int fusefile_write(const char *path, const char *buf, size_t size,
833                           off_t off, struct fuse_file_info *fi)
834 {
835 #if DEBUG
836     fprintf( stderr, "fusefile_write( %s %ld )\n", path, size );
837 #endif
838     if ( strcmp( path, "/" ) != 0 ) {
839         return -ENOENT;
840     }
841
842     if ( write_block( off, buf, size ) < 0 ) {
843         return -EIO;
844     }
845     return size;
846 }
847
848 #define PUSHBUF 104857600
849 /**
850  * Write data from overlay to source.
851  */
852 static void push_oly(off_t beg, off_t end) {
853     static char * buffer = 0;
854     // Pretend that there isn't an overlay
855     char *filename = overlay.source.filename;
856     if ( buffer == 0 ) {
857         buffer = malloc( PUSHBUF );
858         if ( buffer == 0 ) {
859             fprintf( stderr, "** OOM!!\n" );
860             exit( 1 );
861         }
862     }
863     overlay.source.filename = 0;
864     while ( beg < end ) {
865         off_t size = end - beg;
866         if ( size > PUSHBUF ) {
867             size = PUSHBUF;
868         }
869         if ( lseek( overlay.source.fd, beg, SEEK_SET ) < 0 ) {
870             fprintf( stderr, "** Cannot seek overlay at %ld\n", beg );
871             break;
872         }
873         size = read( overlay.source.fd, buffer, size );
874         if ( write_block( beg, buffer, size ) < 0 ) {
875             fprintf( stderr, "** Cannot push %ld bytes at %ld\n", size, beg );
876         }
877         beg += size;
878     }
879     overlay.source.filename = filename;
880 }
881
882 static void fusefile_destroy(void *data) {
883     char *mnt = (char*) data; // As passed to fuse_main
884 #if DEBUG
885     fprintf( stderr, "fusefile_destroy( %s )\n", mnt? mnt : "" );
886 #endif
887     if ( mnt ) {
888         unlink( mnt );
889     }
890 }
891
892 static void fsync_all_dirty() {
893     int i = 0;
894     for ( ; i < sources.count; i++ ) {
895         if ( sources.array[i].dirty ) {
896             fsync( sources.array[i].fd );
897             sources.array[i].dirty = 0;
898         }
899     }
900     if ( overlay.source.filename && overlay.source.dirty ) {
901         fsync( overlay.source.fd );
902         overlay.source.dirty = 0;
903     }
904 }
905
906 static int fusefile_flush(const char *path, struct fuse_file_info *info) {
907 #if DEBUG
908     fprintf( stderr, "fusefile_flush( %s )\n", path );
909 #endif
910     if ( strcmp( path, "/" ) != 0 ) {
911         return -ENOENT;
912     }
913     fsync_all_dirty();
914     return 0;
915 }
916
917 static int fusefile_release(const char *path, struct fuse_file_info *fi) {
918 #if DEBUG
919     fprintf( stderr, "fusefile_release( %s, %d )\n", path, fi->flags );
920 #endif
921     if ( strcmp( path, "/" ) != 0 ) {
922         return -ENOENT;
923     }
924     return 0;
925 }
926
927 static int fusefile_fsync(const char *path, int x, struct fuse_file_info *fi) {
928 #if DEBUG
929     fprintf( stderr, "fusefile_fsync( %s, %d )\n", path, x );
930 #endif
931     if ( strcmp( path, "/" ) != 0 ) {
932         return -ENOENT;
933     }
934     fsync_all_dirty();
935     return 0;
936 }
937
938 /**
939  * 
940  */
941 static int fusefile_truncate(const char *path, off_t len) {
942 #if DEBUG
943     fprintf( stderr, "fusefile_truncate( %s, %ld )\n", path, len );
944 #endif
945     if ( strcmp( path, "/" ) != 0 ) {
946         return -ENOENT;
947     }
948     return -EIO;
949 }
950
951 void *fusefile_init(struct fuse_conn_info *fci) {
952 #if DEBUG
953     fprintf( stderr, "fusefile_init( %d, %d )\n", fci->async_read, fci->want );
954 #endif
955     // Disable asynchronous reading
956     fci->async_read = 0;
957     fci->want &= ~FUSE_CAP_ASYNC_READ;
958 #if DEBUG
959     fprintf( stderr, "fusefile_init( %d, %d )\n", fci->async_read, fci->want );
960 #endif
961     return 0;
962 }
963
964 /**
965  * Dump the current fragmentation to stdout.
966  */
967 static int dump_fragments(int push) {
968     int oly = 0;
969     int src = 0;
970     size_t pos = 0;
971     while ( src < sources.count ) {
972         size_t x = ( oly < overlay.count )?
973             overlay.table[ oly ].beg : sources.size;
974         for ( ; src < sources.count && 
975                   ENDSOURCE( sources.array[ src ] ) <= x; src++ ) {
976             // Dump sources.array[src] in full
977             if ( !push ) {
978                 fprintf( stdout, "%s/%ld:%ld\n",
979                          sources.array[ src ].filename,
980                          pos - sources.array[ src ].start +
981                          sources.array[ src ].from,
982                          sources.array[ src ].to );
983             }
984             pos = ENDSOURCE( sources.array[ src ] );
985         }
986         if ( ( src < sources.count ) && ( sources.array[ src ].start < x ) ) {
987             // Dump sources.array[src] up to x;
988             if ( !push ) {
989                 fprintf( stdout, "%s/%ld:%ld\n",
990                          sources.array[ src ].filename,
991                          sources.array[ src ].from +
992                          pos - sources.array[ src ].start,
993                          x - sources.array[ src ].start +
994                          sources.array[ src ].from
995                          );
996             }
997             pos = ENDSOURCE( sources.array[ src ] );
998         }
999         if ( oly < overlay.count ) {
1000             if ( !push ) {
1001                 fprintf( stdout, "%s/%ld:%ld\n",
1002                          overlay.source.filename,
1003                          overlay.table[ oly ].beg,
1004                          overlay.table[ oly ].end );
1005             } else {
1006                 push_oly( overlay.table[ oly ].beg, overlay.table[ oly ].end );
1007             }
1008             pos = overlay.table[ oly++ ].end;
1009         }
1010         for ( ; src < sources.count &&
1011                   ENDSOURCE( sources.array[ src ] ) <= pos; src++ ) {
1012             // Just skip these fragments.
1013         }
1014     }
1015     return( 0 );
1016 }
1017
1018 static struct fuse_operations fusefile_oper = {
1019     .getattr = fusefile_getattr,
1020     // NYI .fgetattr = fusefile_fgetattr,
1021     .chmod = fusefile_chmod,
1022     .open = fusefile_open,
1023     .read = fusefile_read,
1024     .poll = fusefile_poll,
1025     .write = fusefile_write,
1026     .write_buf = fusefile_write_buf,
1027     .destroy = fusefile_destroy,
1028     // NYI .access = fusefile_access,
1029     .flush = fusefile_flush,
1030     .release = fusefile_release,
1031     .fsync = fusefile_fsync,
1032     // NYI .ftruncate = fusefile_ftruncate,
1033     .truncate = fusefile_truncate,
1034     //.truncate = fusefile_truncate,
1035     //.release = fusefile_release,
1036     .init = fusefile_init,
1037 };
1038
1039 static void usage() {
1040     char *usage =
1041 "Usage: fusefile [ <fuse options> ] <mount> <file/from-to> ... \n"
1042 "Mounts a virtual, file that is a concatenation of file fragments\n"
1043         ;
1044     fprintf( stderr, "%s", usage );
1045     exit( 1 );
1046 }
1047
1048 /**
1049  * Set up the arguments for the fuse_main call, adding our own.
1050  * argv[argc] is the mount point argument
1051  */
1052 static int setup_argv(int argc,char ***argv) {
1053     // note: (*argv)[ argc ] is the mount point argument
1054     char *OURS[] = {
1055         "-odefault_permissions",
1056         //"-s", // Forced single-threading
1057         (*argv)[ argc ]
1058     };
1059 #define OURSN ( sizeof( OURS ) / sizeof( char* ) )
1060     int N = argc + OURSN;
1061     // Allocate new arg array plus terminating null pointer
1062     char **out = malloc( ( N + 1 ) * sizeof( char* ) ); 
1063     int i;
1064     for ( i = 0; i < argc; i++ ) {
1065         out[ i ] = (*argv)[i];
1066         //fprintf( stderr, " %s", out[ i ] );
1067     }
1068     for ( i = 0; i < OURSN; i++ ) {
1069         out[ argc + i ] = OURS[i];
1070         //fprintf( stderr, " %s", out[ i ] );
1071     }
1072     out[ N ] = 0;
1073     //fprintf( stderr, "\n" );
1074     (*argv) = out;
1075     return N; // Don't include the terminating null pointer
1076 }
1077
1078 /**
1079  * Mount a concatenation of files,
1080  * [ <fuse options> ] <mount> <file/from-to> ...
1081  */
1082 int main(int argc, char *argv[])
1083 {
1084     char *mnt;
1085     int mt;
1086     int fg;
1087     int i;
1088     int fuseargc;
1089     struct stat stbuf;
1090     int temporary = 0;
1091     // Scan past options
1092     for ( i = 1; i < argc; i++ ) {
1093         if ( *argv[i] != '-' ) {
1094             break;
1095         }
1096     }
1097     if ( i > argc - 2 ) { // At least mount point plus one source
1098         usage();
1099     }
1100     fuseargc = i;
1101     mnt = argv[ i++ ]; // First non-option argument is the mount pount
1102     #define OVERLAYTAG "-overlay:"
1103     if ( strncmp( argv[i], OVERLAYTAG, strlen( OVERLAYTAG ) ) == 0 ) {
1104         // consume "-overlay:filename[,filename]*"
1105         overlay_setup( argv[i++] + strlen( OVERLAYTAG ) );
1106         if ( i >= argc ) {
1107             usage();
1108         }
1109     }
1110     if ( setup_sources( argv, i, argc-i ) ) {
1111         return 1;
1112     }
1113     if ( overlay.source.filename ) {
1114         overlay.source.to = sources.size; // Register total size.
1115         overlay_post_setup();
1116     }
1117     if ( stat( mnt, &stbuf ) == -1 ) {
1118         int fd = open( mnt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );
1119         if ( fd < 0 ) {
1120             perror( mnt );
1121             return 1;
1122         }
1123         time_t now = time( 0 );
1124         times.atime = now;
1125         times.mtime = now;
1126         times.ctime = now;
1127         temporary = 1;
1128         close( fd );
1129     } else if ( ! S_ISREG( stbuf.st_mode ) ) {
1130         fprintf( stderr, "mountpoint is not a regular file\n" );
1131         return 1;
1132     } else {
1133         times.atime = stbuf.st_atime;
1134         times.mtime = stbuf.st_mtime;
1135         times.ctime = stbuf.st_ctime;
1136     }
1137
1138     {
1139         int fd = open( mnt, O_RDWR, S_IRUSR | S_IWUSR );
1140         if ( fd < 0 ) {
1141             perror( mnt );
1142             return 1;
1143         }
1144         if ( lseek( fd, sources.size, SEEK_SET ) < 0 ) {
1145             return -EIO;
1146         }
1147     }
1148     fuseargc = setup_argv( fuseargc, &argv );
1149     if ( strcmp( "-dump", argv[ 1 ] ) == 0 ) {
1150         return dump_fragments( 0 );
1151     }
1152     if ( strcmp( "-push", argv[ 1 ] ) == 0 ) {
1153         return dump_fragments( 1 );
1154     }
1155     struct fuse_args args = FUSE_ARGS_INIT( fuseargc, argv );
1156     if ( fuse_parse_cmdline( &args, &mnt, &mt, &fg ) ) {
1157         return 1;
1158     }
1159     fuse_opt_free_args( &args );
1160     if ( ! mnt ) {
1161         fprintf( stderr, "missing mountpoint parameter\n" );
1162         return 1;
1163     }
1164     return fuse_main( fuseargc, argv, &fusefile_oper, temporary? mnt : NULL );
1165 }