#!/usr/bin/newlisp ; Utility to copy from a previous overlay file onto a current ; fusefile. This would typically be done so as to "merge down" an ; overlay in an old fusefile overlay stack after having retired that ; stack. (There is an illustration example at the end of this file) ; ; Arguments: ; ; Technically this uitility merely "replays" the writes (in order of ; increasing position rather than their actual time order) that have ; been collated into an overlay file. It writes this into a file or ; fusefile that represents what the basis was when the writes ; happened. ; (die ...) - function to drop a note to stderr and exit with 1. (define (die) (write-line 2 (join (map string (args)) " ")) (exit 1)) ; (read-uint64 FD N) - function to read N consequtive unsigned long from ; file descriptor FD. Return them as a list in order (define (read-uint64 FD N) (let ((B (* N 8)) (BUFFER nil) (HEAD "") (OUT '())) ;; B = number of bytes to read ;; BUFFER = input buffer symbol ;; HEAD = prefix of bytes read but not processed ;; OUT = list of unsigned long to return ;; ;; Note that (read..) might return fewer bytes than asked for so ;; it needs a loop. (while (and (> B) (> (read FD BUFFER B))) (dec B (length BUFFER)) (extend HEAD BUFFER) (let ((I (/ (length HEAD) 8))) (when (> I) (extend OUT (unpack (dup "Lu" ) HEAD)) (setf HEAD ((* 8 I) HEAD))))) (when (> B) (die "Cannot read" N "unsigned long.")) OUT)) ; (copy-data AT SIZE) - copy the data block of SIZE bytes at position ; AT from OL.fd to FF.fd. (define (copy-data AT SIZE) ; FUSEFILE FF.fd OVERLAY OL.fd (let ((BUFFER nil) (N 0)) ;; BUFEER = transfer buffer symbol ;; N = number of bytes written upon each (write...) (when (null? (seek FF.fd AT)) (die "Cannot seek" FUSEFILE AT)) (when (null? (seek OL.fd AT)) (die "Cannot seek" OVERLAY AT)) (while (> SIZE) (when (<= (read OL.fd BUFFER SIZE)) (die "Failed reading" SIZE "bytes")) (dec SIZE (length BUFFER)) (while (and (> (length BUFFER)) (setf N (write FF.fd BUFFER (length BUFFER)))) (setf BUFFER (N BUFFER))) (when (> (length BUFFER)) (die "Failed writing" AT SIZE )) ))) ;=== Main program ; Require 2 command line arguments, afterinterpreter and script file. (when (!= (length (main-args)) 4) (die "Requires arguments: fusefile overlay")) ; Set up globals (setf FUSEFILE (main-args -2) FF.fd (if (open FUSEFILE "u") $it (die "Cannot open" FUSEFILE)) FF.end (file-info FUSEFILE 0) OVERLAY (main-args -1) OL.fd (if (open OVERLAY "r") $it (die "Cannot open" OVERLAY)) OL.end (file-info OVERLAY 0) OL.N (if (seek OL.fd FF.end) (if (read-uint64 OL.fd 1) ($it 0) (die "Cannot read" OVERLAY "table count.")) (die "Cannot seek" OVERLY "to" FF.end)) ) ; Confirm expected file size for overlay (unless (= OL.end (+ FF.end 8 (* OL.N 16))) (die OVERLAY "should be" OL.end "bytes")) ; Load the overlay table and copy data according to its entries (dolist (ENTRY (explode (if (read-uint64 OL.fd (* 2 OL.N)) $it (die "Cannot read overlay table from" OVERLAY)) 2)) ;; ENTRY = (begin end) for data block (println (format "copy %s/%d:%d" (cons OVERLAY ENTRY))) (copy-data (ENTRY 0) (- (ENTRY 1) (ENTRY 0)))) (exit 0) "dumpoverlay.lsp" ; E.g., consider a fusefile stack D:A:B:C with overlays A:B:C over D. ; That stack would have been built in a succession of first using ; stack D:A where changes are collated into overlay A, as in the ; following setup: ; ; $ fusefile E -overlay:A D ; ... writes to E (= D:A) goes into A ; $ fusermount -u E ; ; Note that the "D" part might in reality be a more complex ; composition of several file fragments, but in these examples we ; refer to it simply as "D". ; ; Continuing the example, the new stack D:A:B is used for collating ; further changes into B, as in the following setup: ; ; $ fusefile E -overlay:A:B D ; ... writes to E (= D:A:B) actually goes into B ; $ fusermount -u E ; ; Later again, the stack D:A:B:C is used for collating changes into C, ; as in the following setup: ; ; $ fusefile E -overlay:A:B:C D ; ... writes to E (= D:A:B:C) actually goes into C ; ... ; $ fusermount -u D ; ; At that point, one may decide to merge down the overlay C onto a ; D:A:B fusefile and thereby add the C changes over B. ; ; $ fusefile E -overlay:A:B D ; $ merge-overlay E C ; $ rm C ; $ fusermount -u E ; ; Or alternatively, one may decide to merge down the B changes without ; C onto a D:A fusefile and thereby add B to A. ; ; $ fusefile E -overlay:A D ; $ merge-overlay E B ; $ rm B ; $ fusermount -u E ; ; In the latter case the updated overlay A includes the writes ; collated in B and thus now the stack D:A:C would be the same as the ; previous stack D:A:B:C. ; ; End of example.