Ticket UUID: | da7c079978cb3183731147d2e6a555794416a5b | |||
Title: | FS strips root '/' from FS root volume "zvfs:/" | |||
Type: | Bug | Version: | 8.6.6 | |
Submitter: | anonymous | Created on: | 2017-06-08 02:32:33 | |
Subsystem: | 37. File System | Assigned To: | nobody | |
Priority: | 5 Medium | Severity: | Important | |
Status: | Open | Last Modified: | 2017-06-19 20:22:33 | |
Resolution: | None | Closed By: | nobody | |
Closed on: | ||||
Description: |
I've been attempting to create a vfs which is totally isolated from the native fs. I've set the Tcl_Filesystem to "zvfs" and, following the example in tclTest.c, my FSListVolumesProc returns a single Tcl_Obj "zvfs:/". Using a minimal Tcl_Filesystem with only ListVolumes, Chdir and PathInFilesystem (which always returns TCL_OK unless the path is a windows path), I find that Tcl is stripping the root '/' from what it considers the cwd. % cd zvfs:/ % cd dir % pwd zvfs:/dir % cd .. % pwd zvfs: Tcl handles windows paths correctly -- the '/' is not stripped from, say, "C:/". The routine TclFSNormalizeAbsolutePath in tclPathObj.c is the culprit. It is taking "zvfs:/dir/.." and: /* * Have '..' so need to skip previous directory. */ if (retVal == NULL) { const char *path = TclGetString(pathPtr); retVal = Tcl_NewStringObj(path, dirSep - path); Tcl_IncrRefCount(retVal); } removes the '/' leaving "zvfs:". Toward the bottom of the function there is specific windows code to restore the '/': /* * Ensure a windows drive like C:/ has a trailing separator. */ if (tclPlatform == TCL_PLATFORM_WINDOWS) { int len; const char *path = Tcl_GetStringFromObj(retVal, &len); if (len == 2 && path[0] != 0 && path[1] == ':') { if (Tcl_IsShared(retVal)) { TclDecrRefCount(retVal); retVal = Tcl_DuplicateObj(retVal); Tcl_IncrRefCount(retVal); } Tcl_AppendToObj(retVal, "/", 1); } } Either: a) I don't understand what FSListVolumesProc is supposed to return b) If "zvfs:/" is OK, then perhaps it's not meant to be equivalent to a windows "drive" even though TclpObjListVolumes() in win/tclWinFCmd.c returns "C:/", etc. c) Tcl does not consider fs volumes other than windows I don't know if this is a bug or what. How is a fs supposed to tell Tcl about a volume prefix? Must a fs "mount" its directory structure somewhere within '/' for both unix and windows? I wish there was a reference fs or the documentation were more detailed. | |||
User Comments: |
dgp added on 2017-06-19 20:22:33:
Have you tried comparing what you're doing with trofs? http://math.nist.gov/~DPorter/tcltk/trofs/ Sorry to say I've not yet dug into all the detail you are reporting. Don't know when I will have time. anonymous added on 2017-06-19 20:08:46: I've now hit an absolute roadblock so I'm dead in the water, but enough of the analogies. I tried implementing FSRenameFileProc but Tcl fails to recognize "zvfs:/newfile" as belonging to the zvfs fs. It tries to stat the native fs with a utf name and fails since windows filenames cannot have an embedded ':'. Therefore Tcl never calls my FSRenameFileProc at all. I don't see any way around this bug. anonymous added on 2017-06-18 00:15:59: I am continuing with my zvfs: fs and I found another bug. Again, it is an instance of Tcl not handling VOLUME_RELATIVE fs correctly and doing a "windows" thing just because I happen to be developing on windows. After: % cd zvfs: % pwd zvfs:/ % cd / "cd /" attempts to cd to "zv/" Tcl_FSGetNormalizedPath() in tclPathObj.c around line 1946: Tcl_PathType type = Tcl_FSGetPathType(absolutePath); Variable "type" is now set to TCL_PATH_VOLUME_RELATIVE (which is actually correct even though my fs is not windows) A few lines later: #ifdef _WIN32 } else if (type == TCL_PATH_VOLUME_RELATIVE) { /* * Only Windows has volume-relative paths. */ If TCL_PATH_VOLUME_RELATIVE is only for windows, then Tcl_FSGetPathType() has a bug. Otherwise, the comment "Only Windows has volume..." is false. Since TclWinVolumeRelativeNormalize() is called, it makes the incorrect assumption that the cwd is of the form "D:..." (<drive>:) and proceeds to take the "D:" and append the "/". Thus the bogus result "zv/". That path is passed to FSPathInFilesystemProc where it is rejected. anonymous (claiming to be [email protected]) added on 2017-06-11 02:02:11: There seems to be many places in generic/ which address windows peculiarities. The volume relative stuff is one of them. I'm guessing that Tcl has not considered other volume relative fs' I have an extremely bare-boned test code for this prob. I found that I am able to use FSNormalizePathProc() to detect and, it look like, fix the bogus path. In the hope it could be useful, you can find the code here: https://chiselapp.com/user/iamdave/repository/Testing/index I think my "fix" is a kludge -- if Tcl accepts "fs:/" from FSListVolumesProc() then Tcl should handle them properly. Perhaps TclFSNormalizeAbsolutePath in tclPathObj.c should check the volume prefix against all fs' registered and not have a special case for windows. Otherwise, please make the documentation more clear. If the current Tcl behavior is correct, then Tcl should force a fs to "mount" itself within Tcl's unix type fs rooted at '/'. Again, a reference implementation of a full Tcl vfs would be very, very helpful. |