vfs-fsapi -
API for the implementation of a filesystem in Tcl
package require Tcl 8.4
package require vfs ? 1.2.1 ?
vfshandler subcmd root relative actualpath args...
vfshandler access root relative actualpath mode
vfshandler createdirectory root relative actualpath
vfshandler deletefile root relative actualpath
vfshandler fileattributes root relative actualpath ? index ? ? value ?
vfshandler matchindirectory root relative actualpath pattern types
vfshandler open root relative actualpath mode permissions
vfshandler removedirectory root relative actualpath recursive
vfshandler stat root relative actualpath
vfshandler utime root relative actualpath actime mtime
vfs::accessMode mode
vfs::matchDirectories types
vfs::matchFiles types
vfs::matchCorrectTypes types filelist ? inDir ?
This document explains the API used by the package
vfs
to communicate with filesystem implementations written in tcl.
The package
vfs intercepts every filesystem operation which
falls within a given mount point, and passes the operation on to the
mount point's
vfshandler command in the interpreter which
registered it.
If the handler takes appropriate action for each of the cases it is
called for, a complete, perfect virtual filesystem will be achieved,
indistinguishable to Tcl from the native filesystem.
(CAVEATS: Right now vfs does not expose to Tcl all the
permission-related flags of glob).
- vfshandler subcmd root relative actualpath args...
-
The first argument specifies the operation to perform on behalf of the
filesystem code in the tcl core, the remainder specify the file path
on which to operate, in different forms, and parts, and any additional
arguments which may be required to carry out the action.
To demonstrate the treatment of a path by the generic layer we use
C:/foo/bar/mount.zip/xxx/yyy as an example and additionally
assume that the following conditions are true:
-
mount.zip is a zip archive which has been mounted on top of
itself,
-
said zip archive contains a file with path xxx/yyy,
-
the current working directory of the application is inside of
directory xxx,
-
and the command executed is file exists yyy.
The file separator between root and relative is omitted.
Most filesystem operations need only the relative argument for
their correct operation, but some actually require the other parts of
the path.
- subcmd
-
This argument of the handler can be one of the following
access, createdirectory, deletefile,
fileattributes, matchindirectory, open,
removedirectory, stat, or utime.
The generic layer expects that the subcommands of a handler signal
error conditions by calling vfs::filesystem posixerror with
the appropriate posix error code instead of throwing a tcl error. If
the latter is done nevertheless it will be treated as an unknown posix
error.
There are three exceptions to the rule above: If any of open
(when an interpreter is given), matchindirectory, and
fileattributes (for a set or get operation only) throw a tcl
error, this error will be passed up to the caller of the filesystem
command which invoked the handler. Note that this does not preclude
the ability of these subcommands to use the command
vfs::filesystem posixerror to report more regular filesystem
errors.
- root
-
Part of the specification of the path to operate upon. It contains the
part of the path which lies outside this filesystem's mount point. For
example outlined above its value will be C:/foo/bar/mount.zip.
- relative
-
Part of the specification of the path to operate upon. It contains the
part of the path which lies inside this filesystem. For example
outlined above its value will be xxx/yyy.
- actualpath
-
Part of the specification of the path to operate upon. It contains the
original (unnormalized) name of the path which was used in the current
command wherever it originated (in Tcl or C). For example outlined
above its value will be yyy.
- vfshandler access root relative actualpath mode
-
Signal a posix error if the specified access mode (an integer
number) is not compatible with the file or directory described by the
path. The generic layer will ignore any non-empty return value.
The command vfs::accessMode (see section
HANDLER ENVIRONMENT) can be used to convert the integer
mode into an easier to check string value.
- vfshandler createdirectory root relative actualpath
-
Create a directory with the given name. The command can assume that
all sub-directories in the path exist and are valid, and that the
actual desired path does not yet exist (Tcl takes care of all of that
for us).
- vfshandler deletefile root relative actualpath
-
Delete the given file.
- vfshandler fileattributes root relative actualpath ? index ? ? value ?
-
The command has to return a list containing the names of all
acceptable attributes, if neither index nor value were
specified.
The command has to return the value of the index'th attribute if
the index is specified, but not the value. The attributes
are counted in the same order as their names appear in the list
returned by a call where neither index nor value were
specified. The first attribute is has the index 0.
The command has to set the value of the index'th attribute to
value if both index and value were specified for the
call.
- vfshandler matchindirectory root relative actualpath pattern types
-
Return the list of files or directories in the given path which match
the glob pattern and are compatible with the specified list of
types. The specified path is always the name of an existing
directory.
Note: As Tcl generates requests for directory-only matches from
the filesystems involved when performing any type of recursive
globbing this subcommand absolutely has to handle such (and file-only)
requests correctly or bad things (TM) will happen.
The commands vfs::matchDirectories and vfs::matchFiles
(see section HANDLER ENVIRONMENT) can aid the
implementation greatly in this task.
- vfshandler open root relative actualpath mode permissions
-
Either returns a list describing the successfully opened file, or
throws an error describing how the operation failed.
The list returned upon success contains at least one and at most two
elements. The first, obligatory, element is always the handle of the
channel which was created to allow access to the contents of the
file.
If specified the second element will be interpreted as a callback,
i.e. a command prefix. This prefix will always be executed as is,
i.e. without additional arguments. Any required arguments have to be
returned as part of the result of the call to open.
If present the specified callback will be evaluated just before the
channel is closed by the generic filesystem layer. The
callback itself must not call close.
The channel however is live enough to allow seek and read
operations. In addition all available data will have been flushed into
it already. This means, for example, that the callback can seek to the
beginning of the said channel, read its contents and then store the
gathered data elsewhere. In other words, this callback is not only
crucial to the cleanup of any resources associated with an opened
file, but also for the ability to implement a filesystem which can be
written to.
Under normal circumstances return code and any errors thrown by the
callback itself are ignored. In that case errors have to be signaled
asychronously, for example by calling bgerror.
However if, through a call of the subcommand internalerror,
an error handling script has been specified for the file system, all
errors thrown here will be passed to that script for further action.
- mode
-
can be any of r, w, a, w+, or a+.
- permissions
-
determines the native mode the openend file is created with. Relevant
only of the open mode actually requests the creation of a
non-existing file, i.e. is not r.
- vfshandler removedirectory root relative actualpath recursive
-
Delete the given directory. Argument recursive is a boolean. If
the specified value is true then even if the directory is
non-empty, an attempt has to be made to recursively delete it and its
contents. If the spcified value is false and the directory is
non-empty, a posix error (EEXIST) has to be thrown.
- vfshandler stat root relative actualpath
-
The result has to be a list of keys and values, in a format acceptable
to the builtin command array set. It describes the contents of
a stat structure. The order of the keys in the list is not important.
Given this the subcommand should use something like
return [list dev 0 type file mtime 1234 ...].
as the last command of its implementation.
The following keys and their values have to be supplied by the
filesystem:
- dev
-
A long integer number, the device number of the path stat was called for.
- ino
-
A long integer number, the inode number of the path stat was called for.
Each path handled by the filesystem should be uniquely identified by
the combination of device and inode number. Violating this principle
will cause higher-level algorithms which(have to) keep track of device
and inode information to fail in all manners possible.
An example of such an algorithm would be a directory walker using
device/inode information to keep itself out of infinite loops
generated through symbolic links. Returning non-unique device/inode
information will most likely cause such a walker to skip over paths
under the wrong assumption of having them seen already.
- mode
-
An integer number, the access mode of the path. It is this mode which
is checked by the subcommand access.
- nlink
-
A long integer number, the number of hard links to the specified path.
- uid
-
A long integer number, the id of the user owning the virtual path.
- gid
-
A long integer number, the id of the user group the virtual path
belongs to.
- size
-
A long integer number, the true size of the virtual path, in bytes.
- atime
-
A long integer number, the time of the latest access to the path, in
seconds since the epoch. Convertible into a readable date/time by the
command clock format.
- mtime
-
A long integer number, the time of the latest modification of the
path, in seconds since the epoch. Convertible into a readable
date/time by the command clock format.
- ctime
-
A long integer number, the time of the path was created, in seconds
since the epoch. Convertible into a readable date/time by the command
clock format.
- type
-
A string, either directory, or file, describing the
type of the given path.
- vfshandler utime root relative actualpath actime mtime
-
Set the access and modification times of the given file (these are
read with stat).
The implementation of a filesystem handler can rely on the
existence of the following utility commands:
- vfs::accessMode mode
-
This commands converts an access mode given as integer into a
string, one of F, X, W, XW, R,
RX, and RW.
- vfs::matchDirectories types
-
Checks if the glob types specification ask for the inclusion of
directories. Returns a boolean result. true is returned if
types does ask for directories, else false.
- vfs::matchFiles types
-
Checks if the glob types specification ask for the inclusion of
files. Returns a boolean result. true is returned if types
does ask for directories, else false.
- vfs::matchCorrectTypes types filelist ? inDir ?
-
Returns that subset of the filelist which are compatible with
the types given. The elements of filelist are either
absolute paths, or names of files in the directory indir. The
latter interpretation is taken if and only if the argument indir
is specified.
To debug a problem in the implementation of a filesystem use code as
shown below. This registers the command
report as the error
handler for the filesystem, which in turn prints out the error stack
provided by tcl.
vfs::filesystem internalerror report
proc report {} {
puts stderr $::errorInfo
}
vfs, vfs-filesystems
vfs, filesystem, file