|
1 | 1 | (import lua/basic (set-idx!)) |
2 | 2 | (import vfs/ccfs ccfs) |
3 | 3 | (import vfs/tmpfs tmpfs) |
| 4 | +(import util (log!)) |
4 | 5 |
|
5 | 6 | (defun create-vfs (vfs-mounts) |
6 | 7 | (let* [(mounts {}) |
7 | 8 | (wrap-fun (lambda (function) |
8 | 9 | (lambda (path &rest) |
9 | 10 | (with ((mount local-path) (mount-path mounts path)) |
10 | | - ((.> mount function) local-path (splice rest)))))) |
11 | | - (dir-list (lambda (x) |
12 | | - (let* [(path (canonicalise x)) |
13 | | - (entries ((wrap-fun :list) path))] |
14 | | - (for-each mount-path (keys mounts) |
15 | | - (with (mount-path-parts (string/split mount-path "%/")) |
16 | | - (when (and (= path (string/concat (init mount-path-parts) "/")) (/= mount-path "") |
17 | | - (not (elem? (last mount-path-parts) (values entries)))) |
18 | | - (set-idx! entries (+ (len# entries) 1) (last mount-path-parts))))) |
19 | | - entries)))] |
| 11 | + ((.> mount function) local-path (splice rest))))))] |
| 12 | + ; TODO: if the mount point is not /, check if the mount point is a directory in the existing vfs. |
20 | 13 | (for-each vfs-mount vfs-mounts |
21 | 14 | (let* [(mount-args (string/split vfs-mount "%:")) |
22 | 15 | (attributes (string/split (car mount-args) "")) |
23 | 16 | (mount-point (canonicalise (cadr mount-args))) |
24 | | - (dir (canonicalise (caddr mount-args) false)) |
| 17 | + (dir (canonicalise (caddr mount-args))) |
25 | 18 | (fs-type (cond |
26 | 19 | [(elem? "r" attributes) 'realfs ] |
27 | 20 | [(elem? "t" attributes) 'tmpfs ] |
|
32 | 25 | [tmpfs (.<! mounts mount-point (tmpfs/create dir))] |
33 | 26 | [else (error! "unimplemented.")]))) |
34 | 27 |
|
35 | | - { :list dir-list |
36 | | - :exists (wrap-fun :exists) |
37 | | - :isDir (wrap-fun :isDir) |
38 | | - :isReadOnly (wrap-fun :isReadOnly) |
39 | | - :getName (lambda (path) |
40 | | - (with (name (last (string/split (canonicalise path) "%/"))) |
41 | | - (if (= name "") "root" name))) |
42 | | - :getDrive (lambda (path) "hdd") |
43 | | - :getSize (wrap-fun :getSize) |
44 | | - :getFreeSpace (wrap-fun :getFreeSpace) |
45 | | - :makeDir (wrap-fun :makeDir) |
46 | | - :move (lambda (from-path to-path) |
47 | | - (if (or ((wrap-fun :isReadOnly) from-path) |
48 | | - ((wrap-fun :isReadOnly) to-path)) |
49 | | - (error! "permission denied.") |
50 | | - (let* [((mount-from local-path-from) (mount-path mounts from-path)) |
51 | | - ((mount-to local-path-to) (mount-path mounts to-path))] |
52 | | - (if (/= mount-from mount-to) |
53 | | - (error! "copying across mounts is currently not implemented.") |
54 | | - ((.> mount-from :move) local-path-from local-path-to))))) |
55 | | - :copy (lambda (from-path to-path) |
56 | | - (if ((wrap-fun :isReadOnly) to-path) |
57 | | - (error! "permission denied.") |
58 | | - (let* [((mount-from local-path-from) (mount-path mounts from-path)) |
59 | | - ((mount-to local-path-to) (mount-path mounts to-path))] |
60 | | - (if (/= mount-from mount-to) |
61 | | - (error! "copying across mounts is currently not implemented.") |
62 | | - ((.> mount-from :copy) local-path-from local-path-to))))) |
63 | | - :delete (wrap-fun :delete) |
64 | | - :combine (lambda (path child-path) |
65 | | - (canonicalise (.. path "/" child-path))) |
66 | | - :open (wrap-fun :open) |
67 | | - :find (lambda (wildcard) |
68 | | - (if ((wrap-fun :exists) wildcard) |
69 | | - (list wildcard) |
70 | | - '())) |
71 | | - :getDir (lambda (path) |
72 | | - (with (parts (string/split (canonicalise path) "%/")) |
73 | | - (cond [(= (car parts) "") ".."] |
74 | | - [(= (n parts) 1) ""] |
75 | | - [else (cadr (reverse parts))]))) |
76 | | - :complete (lambda (partial-name path include-files include-slashes) |
77 | | - (if (not ((wrap-fun :isDir))) |
78 | | - {} |
79 | | - (with (names (dir-list path)) |
80 | | - (filter |
81 | | - (lambda (x) (= x "nil")) |
82 | | - (map (lambda (name) |
83 | | - (if (= (string/sub name 1 (n partial-name)) partial-name) |
84 | | - name "nil"))))))) })) |
| 28 | + (with (vfs |
| 29 | + { :list (wrap-fun :list) |
| 30 | + :exists (wrap-fun :exists) |
| 31 | + :isDir (wrap-fun :isDir) |
| 32 | + ; TODO: make the VFS prevent writing to read-only mounts. |
| 33 | + :isReadOnly (wrap-fun :isReadOnly) |
| 34 | + :getName (lambda (path) |
| 35 | + (with (name (last (string/split (canonicalise path) "%/"))) |
| 36 | + (if (= name "") "root" name))) |
| 37 | + :getDrive (lambda (path) "hdd") |
| 38 | + :getSize (wrap-fun :getSize) |
| 39 | + :getFreeSpace (wrap-fun :getFreeSpace) |
| 40 | + :makeDir (wrap-fun :makeDir) |
| 41 | + :delete (wrap-fun :delete) |
| 42 | + :combine (lambda (path child-path) |
| 43 | + (canonicalise (.. path "/" child-path))) |
| 44 | + :open (wrap-fun :open) |
| 45 | + ; TODO: proper wildcard support. |
| 46 | + :find (lambda (wildcard) |
| 47 | + (if ((wrap-fun :exists) wildcard) |
| 48 | + (list wildcard) |
| 49 | + '())) |
| 50 | + :getDir (lambda (path) |
| 51 | + (with (parts (string/split (canonicalise path) "%/")) |
| 52 | + (cond [(= (car parts) "") ".."] |
| 53 | + [(= (n parts) 1) ""] |
| 54 | + [else (cadr (reverse parts))]))) |
| 55 | + :complete (lambda (partial-name path include-files include-slashes) |
| 56 | + (if (not ((wrap-fun :isDir))) |
| 57 | + {} |
| 58 | + (with (names ((wrap-fun :list) path)) |
| 59 | + (filter |
| 60 | + (lambda (x) (= x "nil")) |
| 61 | + (map (lambda (name) |
| 62 | + (if (= (string/sub name 1 (n partial-name)) partial-name) |
| 63 | + name "nil"))))))) }) |
| 64 | + ; Copy and move need to be done manually in order to support copying across mounts. |
| 65 | + (.<! vfs :copy |
| 66 | + (lambda (raw-from-path raw-to-path) |
| 67 | + (let* [(from-path (canonicalise raw-from-path)) |
| 68 | + (to-path (canonicalise raw-to-path))] |
| 69 | + (if (not ((.> vfs :exists) from-path)) |
| 70 | + (error! "No such file") |
| 71 | + (if ((.> vfs :exists) to-path) |
| 72 | + (error! "File exists") |
| 73 | + (letrec [(copy-path (lambda (from to) |
| 74 | + (log! (.. "copying " from " to " to)) |
| 75 | + (if ((.> vfs :isDir) from) |
| 76 | + (progn |
| 77 | + ((.> vfs :makeDir) to) |
| 78 | + (do [(path (struct->list ((.> vfs :list) from)))] |
| 79 | + (copy-path (.. from "/" path) (.. to "/" path)))) |
| 80 | + (let* [(read-handle ((.> vfs :open) from "r")) |
| 81 | + (write-handle ((.> vfs :open) to "w"))] |
| 82 | + ((.> write-handle :write) ((.> read-handle :readAll))) |
| 83 | + ((.> read-handle :close)) |
| 84 | + ((.> write-handle :close))))))] |
| 85 | + (copy-path from-path to-path))))))) |
| 86 | + |
| 87 | + (.<! vfs :move (lambda (from-path to-path) |
| 88 | + ((.> vfs :copy) from-path to-path) |
| 89 | + ((.> vfs :delete) from-path))) |
| 90 | + vfs))) |
85 | 91 |
|
86 | 92 | (defun mount-path (mounts path) |
87 | 93 | (let* [(abs-path (canonicalise path)) |
|
93 | 99 | (splice (list (.> mounts mount-name) |
94 | 100 | (canonicalise (string/sub abs-path (+ 1 (n mount-name)))))))) |
95 | 101 |
|
96 | | -(defun canonicalise (path abs) |
| 102 | +(defun canonicalise (path) |
97 | 103 | (let* [(parts (string/split path "%/")) |
98 | 104 | (i 1)] |
99 | 105 | (while (<= i (n parts)) |
|
0 commit comments