1vfs(n) Tcl-only Virtual File Systems vfs(n)
2
3
4
6 ::vfs - Commands and Procedures to create virtual filesystems
7
9 package require Tcl 8.4
10
11 package require vfs ?1.2.1?
12
13 vfs::filesystem info
14
15 vfs::filesystem mount
16
17 vfs::filesystem unmount
18
19 vfs::accessMode mode
20
21 vfs::matchDirectories types
22
23 vfs::matchFiles types
24
25 vfs::matchCorrectTypes types filelist ?inDir?
26
27
29 The ::vfs package provides commands to query, mount and unmount virtual
30 filesystems, and provides as Tcl libraries some facilities for helping
31 the writing of new virtual filesystems in Tcl. Once a virtual filesys‐
32 tem is in place, the standard Tcl file, glob, cd, pwd, open commands,
33 including all their C APIs in the Tcl library (e.g. Tcl_FSOpenFileChan‐
34 nel, Tcl_FSMatchInDirectory,...), can be used within the filesystem
35 (and indeed, properly written extensions such as Tk which may open or
36 read files will also transparently access the virtual filesystem).
37 Because all of Tcl's FS activity passes through a single layer, it can
38 all be intercepted. This package does just that. Notice that this is
39 quite different to overloading the file command in Tcl. We are actu‐
40 ally providing vfs replacements for C commands like access, stat. By
41 implementing just a handful of commands at this low level, we ensure
42 that all commands at higher levels function irrespective of what is
43 going on inside the FS layer.
44
45 Tcl's filesystem hooks operate on a per-process basis. This means
46 every Tcl interpreter in the same process/application sees the same
47 filesystem, including any virtual filesystems.
48
49 The package require vfs command should be used to access this library.
50 It automatically registers the vfs hooks into Tcl's filesystem, and
51 these will not be removed until Tcl exits (if desired, control over
52 this could be exposed to Tcl in the future). However, the vfs package
53 will at that stage not have any new filesystems mounted, so it will
54 have little effect. Note that package require vfs has two effects.
55 First of all, when it is issued in any Tcl interpreter it will ensure
56 the vfs hooks have been registered with Tcl's core just once (and if
57 any of those interpreters are later deleted, the vfs hooks will still
58 remain registered - they remain until Tcl exits). The second effect is
59 to provide the command vfs::filesystem which allows the interpreter to
60 intercept filesystem commands and handle them with Tcl code in that
61 interpreter.
62
63 There are three somewhat unsupported subcommands of vfs::filesystem,
64 fullynormalize path, posixerror int, internalerror ?script?, which are
65 used to normalize a path (including any final symlink), to register a
66 posix error code with a Tcl error, and to trap/report internal errors
67 in tclvfs implementations respectively.
68
69 vfs::filesystem mount ?-volume? path command
70 To use a virtual filesystem, it must be 'mounted'. Mounting
71 involves declaring to the vfs package that any subdirectories of
72 a given path in the filesystem should be handled by the given
73 command which should be a Tcl command or procedure in the inter‐
74 preter in which the vfs::filesystem is executed. If the ?-vol‐
75 ume? flag is given, the given mount point is also registered
76 with Tcl as a new volume (like a new drive which will appear in
77 file volumes). This is useful (and required for reasonable
78 operation) for mounts like ftp://. For paths mounted inside the
79 native filesystem, it should of course not be given. The new
80 filesystem mounts will be observed immediately in all inter‐
81 preters in the current process. If the interpreter is later
82 deleted, all mounts which are intercepted by it will be automat‐
83 ically removed (and will therefore affect the view of the
84 filesystem seen by all interpreters).
85
86 vfs::filesystem unmount path
87 This unmounts the virtual filesystem which was mounted at path
88 (hence removing it from Tcl's filesystem), or throws an error if
89 no filesystem was mounted there.
90
91 vfs::filesystem info ?path?
92 If no arguments are given, this returns a list of all filesys‐
93 tems mounted (in all interpreters). If a path argument is
94 given, then the command to be used for that path is returned, or
95 an error is thrown if no vfs is mounted for that path. There is
96 currently no facility for examining in which interpreter each
97 command will be evaluated.
98
99 vfs::filesystem fullynormalize path
100 Performs a full expansion of path, (as per 'file normalize'),
101 but including following any links in the last element of path.
102
104 The vfs package will intercept every filesystem operation which falls
105 within a given mount point, and pass the operation on to the mount
106 point's command in the interpreter which registered it. In general this
107 occurs by the C equivalent of an evaluation like this: eval $command
108 [list $subcmd $root $relative $actualpath] $args.
109
110 Here subcmd may be any of the following: access, createdirectory,
111 deletefile, fileattributes, matchindirectory, open, removedirectory,
112 stat, utime. If command takes appropriate action for each of these
113 cases, a complete, perfect virtual filesystem will be achieved, indis‐
114 tinguishable to Tcl from the native filesystem. (CAVEATS: right now I
115 don't expose to Tcl all the permission-related flags of 'glob').
116
117 The remaining arguments specify a file path on which to operate (all
118 commands operate on one of these), and any additional arguments which
119 may be required to carry out the action. The file path is specified by
120 three arguments: root is the part of the path which lies outside this
121 filesystem's mount point, relative is the part of the path which lies
122 inside this filesytem, and actualpath is the original (unnormalized)
123 name of the path which was used in the current command wherever it
124 originated (in Tcl or C). For example, if C:/foo/bar/mount.zip/xxx/yyy
125 is a path in your filesystem, where mount.zip is a zip archive which
126 has been mounted (on top of itself) and contains xxx/yyy, and the cur‐
127 rent working directory is inside xxx, and we evaluate a command like
128 file exists yyy, then rootwill be C:/foo/bar/mount.zip, relative will
129 be xxx/yyy, and actualpath will be yyy. The file separator between the
130 root and relative is omitted.
131
132 Note that most filesystem operations will only require the relative
133 argument to work correctly, but the other arguments are actually
134 required for correct operation of some subcommands.
135
136 Almost all of these commands should either return correctly (i.e. with
137 a TCL_OK result at the C level) or they should use vfs::filesystem
138 posixerror to signal the appropriate posix error code. If a Tcl error
139 is thrown, that should be considered a bug, but it will be interpreted
140 as an unknown posix error in the filesystem call. The exceptions to
141 these rules are those filesystem commands which are able to specify a
142 Tcl error message directly: open (when an interpreter is given),
143 matchindirectory and fileattributes (for a set or get operation only).
144 These three commands are allowed to throw any Tcl error message which
145 will be passed along to the caller, or they may throw a posix error
146 which will be handled appropriately.
147
148 The actual commands are as follows (where r-r-a represents the standard
149 argument triplet of root, relative and actualpath):
150
151 command access r-r-a mode
152 Return TCL_OK or throw a posix error depending on whether the
153 given access mode (which is an integer) is compatible with the
154 file.
155
156 command createdirectory r-r-a
157 Create a directory with the given name. The command can assume
158 that all sub-directories in the path exist and are valid, and
159 that the actual desired path does not yet exist (Tcl takes care
160 of all of that for us).
161
162 command deletefile r-r-a
163 Delete the given file.
164
165 command fileattributes r-r-a ?index? ?value?
166 If neither index nor value is given, then return a list of all
167 acceptable attribute names. If index is given, but no value,
168 then retrieve the value of the index'th attribute (counting in
169 order over the list returned when no argument is given) for the
170 given file. If a value is also given then set the index'th
171 attribute of the given file to that value.
172
173 command matchindirectory r-r-a pattern types
174 Return the list of files or directories in the given path (which
175 is always the name of an existing directory), which match the
176 pattern and are compatible with the types given. It is very
177 important that the command correctly handle types requests for
178 directories only (and files only), because to handle any kind of
179 recursive globbing, Tcl will actually generate requests for
180 directory-only matches from the filesystem. See vfs::matchDi‐
181 rectories below for help.
182
183 command open r-r-a mode permissions
184 For this command, mode is any of "r", "w", "a", "w+", "a+". If
185 the open involves creating a file, then permissions dictates
186 what modes to create it with. If the open operation was not
187 successful, an error should be thrown. If the open operation is
188 successful, the command should return a list of either one or
189 two items. The first item (which is obligatory) is the name of
190 the channel which has been created. The second item, if given,
191 is a Tcl-callback to be used when the channel is closed, so that
192 the vfs can clean up as appropriate. This callback will be
193 evaluated by Tcl just before the channel is closed. The channel
194 will still exist, and all available data will have been flushed
195 into it. The callback can, for example, seek to the beginning
196 of the channel, read its contents and store that contents else‐
197 where (e.g. compressed or on a remote ftp site, etc). The
198 return code or any errors returned by the callback are ignored
199 (if the callback wishes to signal an error, it must do so asyc‐
200 nhronously, with bgerror, for example), unless the 'internaler‐
201 ror' script has been specified, when they are passed to that
202 script for further action.
203
204 command removedirectory r-r-a recursive
205 Delete the given directory. recursive is either 0 or 1. If it
206 is 1 then even if the directory is non-empty, an attempt should
207 be made to recursively delete it and its contents. If it is 0
208 and the directory is non-empty, a posix error (EEXIST) should be
209 thrown.
210
211 command stat r-r-a
212 Return a list of even length containing field-name and value
213 pairs for the contents of a stat structure. The order is not
214 important. The option names are dev (long), ino (long), mode
215 (int), nlink (long), uid (long), gid (long), size (long), atime
216 (long), mtime (long), ctime (long), type (string which is either
217 "directory" or "file"), where the type of each argument is given
218 in brackets. The procedure should therefore return with some‐
219 thing like return [list dev 0 type file mtime 1234 ...].
220
221 command utime r-r-a actime mtime
222 Set the access and modification times of the given file (these
223 are read with 'stat').
224
225
227 The vfslib provides a number of Tcl procedures which can help with
228 writing command procedures to handle the above possibilities. These
229 are:
230
231 vfs::accessMode mode
232 converts an integer access mode to a somewhat more preferable
233 string, any of F X W XW R RX RW.
234
235 vfs::matchDirectories types
236 Does types want directories included?
237
238 vfs::matchFiles types
239 Does types want files included?
240
241 vfs::matchCorrectTypes types filelist ?inDir?
242 Returns that subset of the filelist (which are either absolute
243 paths or names of files in inDir) which are compatible with the
244 types given.
245
246
248 Use something like this to debug problems in your implementation:
249 vfs::filesystem internalerror report ; proc report {} { puts stderr
250 $::errorInfo }
251
252
254 There are very few limitations to the vfs code. One subtlety that you
255 may encounter is if you mount a case-sensitive virtual filesystem into
256 a case-insensitive system (e.g. the standard Windows or MacOS fs) and
257 your code relies on case-insensitivity, then it will not run properly
258 in the virtual filesystem. Of course if your code relies on case-
259 insensitivity, it wouldn't run under Tcl on Unix either, so the best
260 solution is to fix your code!
261
262 We may add link and lstat commands in the future to allow virtual
263 filesystems to support reading and writing links - this is supported by
264 the C API, but has simply not been exposed to Tcl in this extension,
265 yet.
266
267 The Tcl 'Tcl_FSMatchInDirectory' function takes a variety of type
268 information in a Tcl_GlobTypeData structure. We currently only expose
269 the 'type' field from that structure (so the 'permissions' and MacOS
270 type/creator fields are ignored).
271
273 vfs, filesystem, file
274
275
276
277
278
279Vfs 1.2.1 vfs(n)