1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
#!/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: <fusefile> <overlay>
;
; 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.
|