'\" '\" Copyright (c) 2001-2003 Vince Darley '\" Copyright (c) 2003 Andreas Kupries '\" '\" The definitions below are for supplemental macros used in Tcl/Tk '\" manual entries. '\" '\" .AP type name in/out ?indent? '\" Start paragraph describing an argument to a library procedure. '\" type is type of argument (int, etc.), in/out is either "in", "out", '\" or "in/out" to describe whether procedure reads or modifies arg, '\" and indent is equivalent to second arg of .IP (shouldn't ever be '\" needed; use .AS below instead) '\" '\" .AS ?type? ?name? '\" Give maximum sizes of arguments for setting tab stops. Type and '\" name are examples of largest possible arguments that will be passed '\" to .AP later. If args are omitted, default tab stops are used. '\" '\" .BS '\" Start box enclosure. From here until next .BE, everything will be '\" enclosed in one large box. '\" '\" .BE '\" End of box enclosure. '\" '\" .CS '\" Begin code excerpt. '\" '\" .CE '\" End code excerpt. '\" '\" .VS ?version? ?br? '\" Begin vertical sidebar, for use in marking newly-changed parts '\" of man pages. The first argument is ignored and used for recording '\" the version when the .VS was added, so that the sidebars can be '\" found and removed when they reach a certain age. If another argument '\" is present, then a line break is forced before starting the sidebar. '\" '\" .VE '\" End of vertical sidebar. '\" '\" .DS '\" Begin an indented unfilled display. '\" '\" .DE '\" End of indented unfilled display. '\" '\" .SO '\" Start of list of standard options for a Tk widget. The '\" options follow on successive lines, in four columns separated '\" by tabs. '\" '\" .SE '\" End of list of standard options for a Tk widget. '\" '\" .OP cmdName dbName dbClass '\" Start of description of a specific option. cmdName gives the '\" option's name as specified in the class command, dbName gives '\" the option's name in the option database, and dbClass gives '\" the option's class in the option database. '\" '\" .UL arg1 arg2 '\" Print arg1 underlined, then print arg2 normally. '\" '\" RCS: @(#) $Id: man.macros,v 1.1 2009/01/30 04:56:47 andreas_kupries Exp $ '\" '\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. '\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out '\" # BS - start boxed text '\" # ^y = starting y location '\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. '\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. '\" # Special macro to handle page bottom: finish off current '\" # box/sidebar if in box/sidebar mode, then invoked standard '\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. '\" # DS - begin display .de DS .RS .nf .sp .. '\" # DE - end display .de DE .fi .RE .sp .. '\" # SO - start of list of standard options .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 4c 8c 12c .ft B .. '\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. '\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. '\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. '\" # CE - end code excerpt .de CE .fi .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. .TH "vfs-fsapi" n 1.0 "Tcl-level Virtual Filesystems" .BS .SH NAME vfs-fsapi \- API for the implementation of a filesystem in Tcl .SH SYNOPSIS package require \fBTcl 8.4\fR .sp package require \fBvfs ?1.2.1?\fR .sp \fBvfshandler\fR \fIsubcmd\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIargs\fR... .sp \fBvfshandler\fR \fBaccess\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fImode\fR .sp \fBvfshandler\fR \fBcreatedirectory\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR .sp \fBvfshandler\fR \fBdeletefile\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR .sp \fBvfshandler\fR \fBfileattributes\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR ?\fIindex\fR? ?\fIvalue\fR? .sp \fBvfshandler\fR \fBmatchindirectory\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIpattern\fR \fItypes\fR .sp \fBvfshandler\fR \fBopen\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fImode\fR \fIpermissions\fR .sp \fBvfshandler\fR \fBremovedirectory\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIrecursive\fR .sp \fBvfshandler\fR \fBstat\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR .sp \fBvfshandler\fR \fButime\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIactime\fR \fImtime\fR .sp \fBvfs::accessMode\fR \fImode\fR .sp \fBvfs::matchDirectories\fR \fItypes\fR .sp \fBvfs::matchFiles\fR \fItypes\fR .sp \fBvfs::matchCorrectTypes\fR \fItypes\fR \fIfilelist\fR ?\fIinDir\fR? .sp .BE .SH DESCRIPTION This document explains the API used by the package \fBvfs\fR to communicate with filesystem implementations written in tcl. .SH "HANDLER OVERVIEW" The package \fBvfs\fR intercepts every filesystem operation which falls within a given mount point, and passes the operation on to the mount point's \fBvfshandler\fR command in the interpreter which registered it. .PP 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 \fBvfs\fR does not expose to Tcl all the permission-related flags of \fBglob\fR). .PP .TP \fBvfshandler\fR \fIsubcmd\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIargs\fR... 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. .sp To demonstrate the treatment of a path by the generic layer we use "\fIC:/foo/bar/mount.zip/xxx/yyy\fR" as an example and additionally assume that the following conditions are true: .RS .IP [1] "\fImount.zip\fR" is a zip archive which has been mounted on top of itself, .IP [2] said zip archive contains a file with path "\fIxxx/yyy\fR", .IP [3] the current working directory of the application is inside of directory "\fIxxx\fR", .IP [4] and the command executed is \fBfile exists yyy\fR. .RE .sp The file separator between \fIroot\fR and \fIrelative\fR is omitted. Most filesystem operations need only the \fIrelative\fR argument for their correct operation, but some actually require the other parts of the path. .RS .TP \fIsubcmd\fR This argument of the handler can be one of the following \fBaccess\fR, \fBcreatedirectory\fR, \fBdeletefile\fR, \fBfileattributes\fR, \fBmatchindirectory\fR, \fBopen\fR, \fBremovedirectory\fR, \fBstat\fR, or \fButime\fR. .sp The generic layer expects that the subcommands of a handler signal error conditions by calling \fBvfs::filesystem posixerror\fR 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. .sp There are three exceptions to the rule above: If any of \fBopen\fR (when an interpreter is given), \fBmatchindirectory\fR, and \fBfileattributes\fR (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 \fBvfs::filesystem posixerror\fR to report more regular filesystem errors. .TP \fIroot\fR 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 "\fIC:/foo/bar/mount.zip\fR". .TP \fIrelative\fR 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 "\fIxxx/yyy\fR". .TP \fIactualpath\fR 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 "\fIyyy\fR". .RE .PP .SH "HANDLER METHODS" .TP \fBvfshandler\fR \fBaccess\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fImode\fR Signal a posix error if the specified access \fImode\fR (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. .sp The command \fBvfs::accessMode\fR (see section \fBHANDLER ENVIRONMENT\fR) can be used to convert the integer \fImode\fR into an easier to check string value. .TP \fBvfshandler\fR \fBcreatedirectory\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR 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). .TP \fBvfshandler\fR \fBdeletefile\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR Delete the given file. .TP \fBvfshandler\fR \fBfileattributes\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR ?\fIindex\fR? ?\fIvalue\fR? The command has to return a list containing the names of all acceptable attributes, if neither \fIindex\fR nor \fIvalue\fR were specified. .sp The command has to return the value of the \fIindex\fR'th attribute if the \fIindex\fR is specified, but not the \fIvalue\fR. The attributes are counted in the same order as their names appear in the list returned by a call where neither \fIindex\fR nor \fIvalue\fR were specified. The first attribute is has the index \fB0\fR. .sp The command has to set the value of the \fIindex\fR'th attribute to \fIvalue\fR if both \fIindex\fR and \fIvalue\fR were specified for the call. .TP \fBvfshandler\fR \fBmatchindirectory\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIpattern\fR \fItypes\fR Return the list of files or directories in the given path which match the glob \fIpattern\fR and are compatible with the specified list of \fItypes\fR. The specified path is always the name of an existing directory. .sp \fINote:\fR 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. .sp The commands \fBvfs::matchDirectories\fR and \fBvfs::matchFiles\fR (see section \fBHANDLER ENVIRONMENT\fR) can aid the implementation greatly in this task. .TP \fBvfshandler\fR \fBopen\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fImode\fR \fIpermissions\fR Either returns a list describing the successfully opened file, or throws an error describing how the operation failed. .sp 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. .sp 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 \fBopen\fR. .sp If present the specified callback will be evaluated just before the channel is closed \fIby the generic filesystem layer\fR. The callback itself \fImust not\fR call \fBclose\fR. .sp The channel however is live enough to allow \fBseek\fR and \fBread\fR 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. .sp 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 \fBbgerror\fR. However if, through a call of the subcommand \fBinternalerror\fR, an error handling script has been specified for the file system, all errors thrown here will be passed to that script for further action. .RS .TP \fImode\fR can be any of \fBr\fR, \fBw\fR, \fBa\fR, \fBw+\fR, or \fBa+\fR. .TP \fIpermissions\fR determines the native mode the openend file is created with. Relevant only of the open \fImode\fR actually requests the creation of a non-existing file, i.e. is not \fBr\fR. .RE .sp .TP \fBvfshandler\fR \fBremovedirectory\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIrecursive\fR Delete the given directory. Argument \fIrecursive\fR is a boolean. If the specified value is \fBtrue\fR 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 \fBfalse\fR and the directory is non-empty, a posix error (\fBEEXIST\fR) has to be thrown. .TP \fBvfshandler\fR \fBstat\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR The result has to be a list of keys and values, in a format acceptable to the builtin command \fBarray set\fR. It describes the contents of a stat structure. The order of the keys in the list is not important. .sp Given this the subcommand should use something like .nf return [list dev 0 type file mtime 1234 ...]. .fi as the last command of its implementation. .sp The following keys and their values have to be supplied by the filesystem: .RS .TP \fBdev\fR A long integer number, the device number of the path stat was called for. .TP \fBino\fR 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. .sp 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. .TP \fBmode\fR An integer number, the access mode of the path. It is this mode which is checked by the subcommand \fBaccess\fR. .TP \fBnlink\fR A long integer number, the number of hard links to the specified path. .TP \fBuid\fR A long integer number, the id of the user owning the virtual path. .TP \fBgid\fR A long integer number, the id of the user group the virtual path belongs to. .TP \fBsize\fR A long integer number, the true size of the virtual path, in bytes. .TP \fBatime\fR 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 \fBclock format\fR. .TP \fBmtime\fR 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 \fBclock format\fR. .TP \fBctime\fR 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 \fBclock format\fR. .TP \fBtype\fR A string, either \fBdirectory\fR, or \fBfile\fR, describing the type of the given path. .RE .sp .TP \fBvfshandler\fR \fButime\fR \fIroot\fR \fIrelative\fR \fIactualpath\fR \fIactime\fR \fImtime\fR Set the access and modification times of the given file (these are read with \fBstat\fR). .PP .SH "HANDLER ENVIRONMENT" The implementation of a filesystem handler can rely on the existence of the following utility commands: .TP \fBvfs::accessMode\fR \fImode\fR This commands converts an access \fImode\fR given as integer into a string, one of \fBF\fR, \fBX\fR, \fBW\fR, \fBXW\fR, \fBR\fR, \fBRX\fR, and \fBRW\fR. .TP \fBvfs::matchDirectories\fR \fItypes\fR Checks if the glob types specification ask for the inclusion of directories. Returns a boolean result. \fBtrue\fR is returned if types does ask for directories, else \fBfalse\fR. .TP \fBvfs::matchFiles\fR \fItypes\fR Checks if the glob types specification ask for the inclusion of files. Returns a boolean result. \fBtrue\fR is returned if types does ask for directories, else \fBfalse\fR. .TP \fBvfs::matchCorrectTypes\fR \fItypes\fR \fIfilelist\fR ?\fIinDir\fR? Returns that subset of the \fIfilelist\fR which are compatible with the \fItypes\fR given. The elements of \fIfilelist\fR are either absolute paths, or names of files in the directory \fIindir\fR. The latter interpretation is taken if and only if the argument \fIindir\fR is specified. .PP .SH "FILESYSTEM DEBUGGING" To debug a problem in the implementation of a filesystem use code as shown below. This registers the command \fBreport\fR as the error handler for the filesystem, which in turn prints out the error stack provided by tcl. .PP .nf vfs::filesystem internalerror report proc report {} { puts stderr $::errorInfo } .fi .SH "SEE ALSO" vfs, vfs-filesystems .SH KEYWORDS file, filesystem, vfs .SH COPYRIGHT .nf Copyright (c) 2001-2003 Vince Darley Copyright (c) 2003 Andreas Kupries .fi