+2003-02-20 Vince Darley <vincentdarley@sourceforge.net>
+
+ * generic/vfs.c: completed use of internalerror and posix handling
+ for all functions.
+ * doc/vfs.n:
+ * doc/vfslib.n: more documentation regarding handling of errors
+ and use of the 'internalerror' feature.
+
+ Around the time Tcl 8.4.2 is released we should increment tclvfs's
+ version to 1.3 and make a proper release. In the meantime,
+ improvements to all .tcl implementations (esp. proper error
+ handling) would be greatly appreciated.
+
2003-02-20 Andreas Kupries <andreask@activestate.com>
* library/mk4vfs.tcl: Switching to canceling the stored after id
the interpreter to intercept filesystem commands and handle them with
Tcl code in that interpreter.
.PP
-There are two unsupported subcommands of \fBvfs::filesystem\fR,
-\fBfullynormalize path\fR and \fBposixerror int\fR, which are used to
-normalize a path (including any final symlink) and to register a posix
-error code with a Tcl error, respectively.
+There are three somewhat unsupported subcommands of
+\fBvfs::filesystem\fR, \fBfullynormalize path\fR, \fBposixerror int\fR,
+\fBinternalerror ?script?\fR, which are used to normalize a path
+(including any final symlink), to register a posix error code with a Tcl
+error, and to trap/report internal errors in tclvfs implementations
+respectively.
.TP
\fBvfs::filesystem\fR \fImount\fR \fI?-volume?\fR \fIpath\fR \fIcommand\fR
To use a virtual filesystem, it must be 'mounted'. Mounting involves
\fIrelative\fR argument to work correctly, but the other arguments are
actually required for correct operation of some subcommands.
.PP
+Almost all of these commands should either return correctly (i.e. with a
+TCL_OK result at the C level) or they should use vfs::filesystem
+posixerror to signal the appropriate posix error code. If a Tcl error is
+thrown, that should be considered a bug, but it will be interpreted as an
+unknown posix error in the filesystem call. The exceptions to these
+rules are those filesystem commands which are able to specify a Tcl error
+message directly: open (when an interpreter is given), matchindirectory
+and fileattributes (for a set or get operation only). These three
+commands are allowed to throw any Tcl error message which will be passed
+along to the caller, or they may throw a posix error which will be
+handled appropriately.
+.PP
The actual commands are as follows (where \fIr-r-a\fR represents the
standard argument triplet of \fIroot\fR, \fIrelative\fR and
\fIactualpath\fR):
.TP
\fIcommand\fR \fIaccess\fR \fIr-r-a\fR \fImode\fR
-Return 1 or throw an error depending on whether the given access mode (which
-is an integer) is compatible with the file.
+Return TCL_OK or throw a posix error depending on whether the given
+access mode (which is an integer) is compatible with the file.
.TP
\fIcommand\fR \fIcreatedirectory\fR \fIr-r-a\fR
Create a directory with the given name.
store that contents elsewhere (e.g. compressed or on a remote ftp
site, etc). The return code or any errors returned by the callback
are ignored (if the callback wishes to signal an error, it must do so
-asycnhronously, with bgerror, for example).
+asycnhronously, with bgerror, for example), unless the 'internalerror'
+script has been specified, when they are passed to that script for
+further action.
.TP
\fIcommand\fR \fIremovedirectory\fR \fIr-r-a\fR
Delete the given directory.
paths or names of files in \fIinDir\fR) which are compatible with the
\fItypes\fR given.
+.SH VFS DEBUGGING
+.PP
+Use something like this to debug problems in your implementation:
+vfs::filesystem internalerror report ; proc report {} { puts
+stderr $::errorInfo }
+
.SH LIMITATIONS
.PP
There are very few limitations to the vfs code. One subtlety that you
/* Handle an error thrown by a tcl vfs implementation */
static void
VfsInternalError(Tcl_Interp* interp) {
- Tcl_MutexLock(&internalErrorMutex);
- if (internalErrorScript != NULL) {
- Tcl_EvalObjEx(interp, internalErrorScript,
- TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
+ if (interp != NULL) {
+ Tcl_MutexLock(&internalErrorMutex);
+ if (internalErrorScript != NULL) {
+ Tcl_EvalObjEx(interp, internalErrorScript,
+ TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
+ }
+ Tcl_MutexUnlock(&internalErrorMutex);
}
- Tcl_MutexUnlock(&internalErrorMutex);
}
\f
/* Return fully normalized path owned by the caller */
Tcl_ResetResult(cmdInterp);
Tcl_AppendResult(cmdInterp, "couldn't open \"",
Tcl_GetString(pathPtr), "\": ",
- Tcl_PosixError(interp), (char *) NULL);
+ Tcl_PosixError(cmdInterp), (char *) NULL);
} else {
Tcl_Obj* error = Tcl_GetObjResult(interp);
/*
*/
Tcl_SetObjResult(cmdInterp, Tcl_DuplicateObj(error));
}
+ } else {
+ /* Report any error, since otherwise it is lost */
+ if (returnVal != -1) {
+ VfsInternalError(interp);
+ }
}
if (interp == cmdInterp) {
/*
Tcl_SetObjResult(cmdInterp, *objPtrRef);
*objPtrRef = NULL;
}
+ } else {
+ Tcl_ResetResult(cmdInterp);
+ Tcl_AppendResult(cmdInterp, "couldn't read attributes for \"",
+ Tcl_GetString(pathPtr), "\": ",
+ Tcl_PosixError(cmdInterp), (char *) NULL);
}
return returnVal;
Tcl_RestoreResult(interp, &savedResult);
Tcl_DecrRefCount(mountCmd);
- if (errorPtr != NULL) {
+ if (returnVal == -1) {
+ Tcl_ResetResult(cmdInterp);
+ Tcl_AppendResult(cmdInterp, "couldn't set attributes for \"",
+ Tcl_GetString(pathPtr), "\": ",
+ Tcl_PosixError(cmdInterp), (char *) NULL);
+ } else if (errorPtr != NULL) {
/*
* Leave error message in correct interp, errorPtr was
* duplicated above, in case of threading issues.