can mount urltypes
authorVince Darley <vincentdarley@sourceforge.net>
Wed, 29 Aug 2001 11:30:18 +0000 (11:30 +0000)
committerVince Darley <vincentdarley@sourceforge.net>
Wed, 29 Aug 2001 11:30:18 +0000 (11:30 +0000)
ChangeLog
Readme.txt
generic/vfs.c
library/httpvfs.tcl [new file with mode: 0644]
library/tclIndex
library/tclprocvfs.tcl
library/vfsUrl.tcl
library/zipvfs.tcl
win/makefile.vc

index dbe7b0a880b93fcbbd1370c6e4d994212c5957f7..8a13a035451407f1721147b33c67c6b84f5c83ea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,15 @@
+2001-08-29  Vince Darley <vincentdarley@sourceforge.net>
+       * can now mount root volumes which end in separator
+       characters (such as 'ftp://').  The code handles path
+       separation in such cases.  This means the 'urltype'
+       vfs now works (the 8-22 changes below didn't quite
+       complete the job).
+       This requires the latest 8.4a4 release from cvs.
+       
 2001-08-22  Vince Darley <vincentdarley@sourceforge.net>
        * added ability to treat entire urls as file paths, so
        we can mount 'ftp://' as a root volume and examine its
-       contents.  This requires a patch to Tcl 8.4a4 which
-       is currently available from the Tcl project (see the
-       'fs update' patch/bug).
+       contents.  This requires the latest 8.4a4 release from cvs.
        
 2001-08-13  Vince Darley <vincentdarley@sourceforge.net>
        * ftp vfs works reasonably well now; try:
index 136ff7113f1830cfd4960b72eb160c8b42daf5f0..e1a069ed9578f6bc012fe8763db1942f1f6bd7ce 100644 (file)
@@ -8,7 +8,7 @@ Introduction
 
 This is an implementation of a 'vfs' extension (and a 'vfs' package,
 including a small library of Tcl code).  The goal of this extension
-is to expose Tcl 8.4a3's new filesystem C API to the Tcl level.
+is to expose Tcl 8.4's new filesystem C API to the Tcl level.
 
 Since 8.4 is still in alpha, the APIs on which this extension depends may of
 course change (although this isn't too likely).  If that happens, it will of
@@ -44,13 +44,14 @@ which involves opening files.
 The vfs's currently available are:
 
 --------+-----------------------------------------------------------------
-vfs     |  mount command                       
+vfs     |  example mount command                       
 --------+-----------------------------------------------------------------
 zip     |  vfs::zip::Mount my.zip local
 ftp     |  vfs::ftp::Mount ftp://user:pass@ftp.foo.com/dir/name/ local
 mk4     |  vfs::mk4::Mount myMk4database local
 test    |  vfs::test::Mount ...
-tclproc |  vfs::tclproc::Mount ::tcl local
+ns      |  vfs::ns::Mount ::tcl local
+urltype |  vfs::urltype::Mount ftp
 --------+-----------------------------------------------------------------
 
 For file-systems which make use of a local file (e.g. mounting zip or mk4
@@ -62,20 +63,16 @@ to create a dummy file/directory called 'local' before mounting.
 Limitations
 -----------
 
-We can't currently mount a file protocol.  For example it would be nice to 
-tell Tcl that we understand 'ftp://' as meaning an absolute path to be
-handled by our ftp-vfs system.  Then we could so something like
+None yet.
 
-    file copy ftp://ftp.foo.com/pub/readme.txt ~/readme.txt
+Helping!
+--------
 
-and our ftp-vfs system can deal with it.  This is really a limitation in
-Tcl's current understanding of file paths (and not any problem in this
-extension per se).
+Any help is much appreciated!  The current code has very much _evolved_
+which means it isn't necessarily even particular well thought out, so if
+you wish to contribute a single line of code or a complete re-write, I'd be
+very happy!
 
-Of course what we can do is mount any specific ftp address to somewhere in 
-the filesystem.  For example, we can mount 'ftp://ftp.foo.com/ to
-/ftp.foo.com/ and proceed from there.
-    
 Future thoughts
 ---------------
 
@@ -90,5 +87,8 @@ what changes will be needed in Tcl's core to support it).  Obvious things
 which come to mind are asynchronicity: 'file copy' from a mounted remote
 site (ftp or http) is going to be very slow and simply block the
 application.  Commands like that should have new asynchronous versions which
-can be used when desired (e.g. 'file copy from to -callback foo').
+can be used when desired (for example, 'file copy from to -callback foo'
+would be one approach to handling this).
 
+Bugs in Tcl vfs's are hard to track down, since error messages can't
+necessarily propagate to the toplevel.  Could add a debugging command.
index d6a89158bd727124c43054cdd626e724a2d727c9..ff411e3cb5408d7884ea141fa1cfcfb26efcb46a 100644 (file)
@@ -333,6 +333,7 @@ int
 VfsInFilesystem(Tcl_Obj *pathPtr, ClientData *clientDataPtr) {
     Tcl_Obj *normedObj;
     int len, splitPosition;
+    char remember;
     char *normed;
     Tcl_Interp* interp;
     VfsNativeRep *nativeRep;
@@ -379,10 +380,31 @@ VfsInFilesystem(Tcl_Obj *pathPtr, ClientData *clientDataPtr) {
               && (normed[--splitPosition] != VFS_SEPARATOR)) {
            /* Do nothing */
        }
+       /* 
+        * We now know that normed[splitPosition] is a separator.
+        * However, we might have mounted a root filesystem with a
+        * strange name (for example 'ftp://')
+        */
+       if ((splitPosition > 0) && (splitPosition != len)) {
+           remember = normed[splitPosition + 1];
+           normed[splitPosition+1] = '\0';
+           mountCmd = Tcl_GetVar2Ex(interp, "vfs::mount", normed,
+                                    TCL_GLOBAL_ONLY);
+                                    
+           if (mountCmd != NULL) {
+               splitPosition++;
+               break;
+           }
+           normed[splitPosition+1] = remember;
+       }
+       
+       /* Otherwise continue as before */
+       
        /* Terminate the string there */
        if (splitPosition == 0) {
            break;
        }
+       remember = VFS_SEPARATOR;
        normed[splitPosition] = 0;
     }
     
@@ -394,7 +416,7 @@ VfsInFilesystem(Tcl_Obj *pathPtr, ClientData *clientDataPtr) {
        return -1;
     }
     if (splitPosition != len) {
-       normed[splitPosition] = VFS_SEPARATOR;
+       normed[splitPosition] = remember;
     }
     nativeRep = (VfsNativeRep*) ckalloc(sizeof(VfsNativeRep));
     nativeRep->splitPosition = splitPosition;
@@ -1143,6 +1165,10 @@ VfsCommand(Tcl_Interp* interp, CONST char* cmd, Tcl_Obj * pathPtr) {
     } else {
        Tcl_ListObjAppendElement(interp, mountCmd, 
                Tcl_NewStringObj(normedString,splitPosition));
+       if (normedString[splitPosition] != VFS_SEPARATOR) {
+           /* This will occur if we mount 'ftp://' */
+           splitPosition--;
+       }
        Tcl_ListObjAppendElement(interp, mountCmd, 
                Tcl_NewStringObj(normedString+splitPosition+1,
                                 len-splitPosition-1));
diff --git a/library/httpvfs.tcl b/library/httpvfs.tcl
new file mode 100644 (file)
index 0000000..4aad329
--- /dev/null
@@ -0,0 +1,212 @@
+
+package require vfs 1.0
+package require http
+
+# THIS DOES NOT WORK!
+
+# It's currently a copy of ftpvfs.tcl where there has basically been
+# a global replacement of 'ftp' by 'http'.
+
+namespace eval vfs::http {}
+
+proc vfs::http::Mount {dirurl local} {
+    if {[string range $dirurl 0 5] == "http://"} {
+       set dirurl [string range $dirurl 6 end]
+    }
+    if {![regexp {(([^:]*)(:([^@]*))?@)?([^/]*)/(.*/)?([^/]*)$} $dirurl \
+      junk junk user junk pass host path file]} {
+       return -code error "Sorry I didn't understand\
+         the url address \"$dirurl\""
+    }
+    
+    if {[string length $file]} {
+       return -code error "Can only mount directories, not\
+         files (perhaps you need a trailing '/')"
+    }
+    
+    if {![string length $user]} {
+       set user anonymous
+    }
+    
+    set fd [::http::Open $host $user $pass $path]
+    if {$fd == -1} {
+       error "Mount failed"
+    }
+    if {[catch {
+       ::http::Cd $fd $path
+    } err]} {
+       http::Close $fd
+       error "Opened http connection, but then received error: $err"
+    }
+    
+    ::vfs::log "http $host, $path mounted at $fd"
+    vfs::filesystem mount $local [list vfs::http::handler $fd $path]
+    # Register command to unmount
+    vfs::RegisterMount $local [list ::vfs::http::Unmount $fd]
+    return $fd
+}
+
+proc vfs::http::Unmount {fd local} {
+    vfs::filesystem unmount $local
+    ::http::Close $fd
+}
+
+proc vfs::http::handler {fd path cmd root relative actualpath args} {
+    if {$cmd == "matchindirectory"} {
+       eval [list $cmd $fd $relative $actualpath] $args
+    } else {
+       eval [list $cmd $fd $relative] $args
+    }
+}
+
+# If we implement the commands below, we will have a perfect
+# virtual file system for remote http sites.
+
+proc vfs::http::stat {fd name} {
+    ::vfs::log "stat $name"
+    if {$name == ""} {
+       return [list type directory mtime 0 size 0 mode 0777 ino -1 \
+         depth 0 name "" dev -1 uid -1 gid -1 nlink 1]
+    }
+    
+    # get information on the type of this file
+    set httpInfo [_findHttpInfo $fd $name]
+    if {$httpInfo == ""} { error "Couldn't find file info" }
+    ::vfs::log $httpInfo
+    set perms [lindex $httpInfo 0]
+    if {[string index $perms 0] == "d"} {
+       lappend res type directory
+       set mtime 0
+    } else {
+       lappend res type file
+       set mtime [http::ModTime $fd $name]
+    }
+    lappend res dev -1 uid -1 gid -1 nlink 1 depth 0 \
+      atime $mtime ctime $mtime mtime $mtime mode 0777
+    return $res
+}
+
+proc vfs::http::access {fd name mode} {
+    ::vfs::log "access $name $mode"
+    if {$name == ""} { return 1 }
+    set info [vfs::http::_findHttpInfo $fd $name]
+    if {[string length $info]} {
+       return 1
+    } else {
+       error "No such file"
+    }
+}
+
+# We've chosen to implement these channels by using a memchan.
+# The alternative would be to use temporary files.
+proc vfs::http::open {fd name mode permissions} {
+    ::vfs::log "open $name $mode $permissions"
+    # return a list of two elements:
+    # 1. first element is the Tcl channel name which has been opened
+    # 2. second element (optional) is a command to evaluate when
+    #    the channel is closed.
+    switch -glob -- $mode {
+       "" -
+       "r" {
+           http::Get $fd $name -variable tmp
+           package require Memchan
+
+           set filed [memchan]
+           fconfigure $filed -translation binary
+           puts -nonewline $filed $tmp
+
+           fconfigure $filed -translation auto
+           seek $filed 0
+           return [list $filed]
+       }
+       "a" -
+       "w*" {
+           # Try to write an empty file
+           error "Can't open $name for writing"
+       }
+       default {
+           return -code error "illegal access mode \"$mode\""
+       }
+    }
+}
+
+proc vfs::http::_findHttpInfo {fd name} {
+    ::vfs::log "findHttpInfo $fd $name"
+    set httpList [http::List $fd [file dirname $name]]
+    foreach p $httpList {
+       regsub -all "\[ \t\]+" $p " " p
+       set items [split $p " "]
+       set pname [lindex $items end]
+       if {$pname == [file tail $name]} {
+           return $items
+       }
+    }
+    return ""
+}
+
+proc vfs::http::matchindirectory {fd path actualpath pattern type} {
+    ::vfs::log "matchindirectory $path $pattern $type"
+    set httpList [http::List $fd $path]
+    ::vfs::log "httpList: $httpList"
+    set res [list]
+
+    foreach p $httpList {
+       regsub -all "\[ \t\]+" $p " " p
+       set items [split $p " "]
+       set name [lindex $items end]
+       set perms [lindex $items 0]
+       if {[::vfs::matchDirectories $type]} {
+           if {[string index $perms 0] == "d"} {
+               lappend res "$actualpath$name"
+           }
+       }
+       if {[::vfs::matchFiles $type]} {
+           if {[string index $perms 0] != "d"} {
+               lappend res "$actualpath$name"
+           }
+       }
+       
+    }
+    return $res
+}
+
+proc vfs::http::createdirectory {fd name} {
+    ::vfs::log "createdirectory $name"
+    error "read-only"
+}
+
+proc vfs::http::removedirectory {fd name} {
+    ::vfs::log "removedirectory $name"
+    error "read-only"
+}
+
+proc vfs::http::deletefile {fd name} {
+    ::vfs::log "deletefile $name"
+    error "read-only"
+}
+
+proc vfs::http::fileattributes {fd path args} {
+    ::vfs::log "fileattributes $args"
+    switch -- [llength $args] {
+       0 {
+           # list strings
+           return [list]
+       }
+       1 {
+           # get value
+           set index [lindex $args 0]
+       }
+       2 {
+           # set value
+           set index [lindex $args 0]
+           set val [lindex $args 1]
+           error "read-only"
+       }
+    }
+}
+
+proc vfs::http::utime {fd path actime mtime} {
+    error "Can't set utime"
+}
+
index f00f3c108135983800fea7aa09080d12ba765a0e..60f8b56ab620edaedf0d0a89551a5e8c1c0b9233 100644 (file)
@@ -20,6 +20,19 @@ set auto_index(::vfs::ftp::removedirectory) [list source [file join $dir ftpvfs.
 set auto_index(::vfs::ftp::deletefile) [list source [file join $dir ftpvfs.tcl]]
 set auto_index(::vfs::ftp::fileattributes) [list source [file join $dir ftpvfs.tcl]]
 set auto_index(::vfs::ftp::utime) [list source [file join $dir ftpvfs.tcl]]
+set auto_index(::vfs::http::Mount) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::Unmount) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::handler) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::stat) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::access) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::open) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::_findHttpInfo) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::matchindirectory) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::createdirectory) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::removedirectory) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::deletefile) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::fileattributes) [list source [file join $dir httpvfs.tcl]]
+set auto_index(::vfs::http::utime) [list source [file join $dir httpvfs.tcl]]
 set auto_index(::vfs::mk4::Mount) [list source [file join $dir mk4vfs.tcl]]
 set auto_index(::vfs::mk4::Unmount) [list source [file join $dir mk4vfs.tcl]]
 set auto_index(::vfs::mk4::handler) [list source [file join $dir mk4vfs.tcl]]
@@ -47,20 +60,20 @@ set auto_index(::mk4vfs::find/file) [list source [file join $dir mk4vfs.tcl]]
 set auto_index(::mk4vfs::find/dir) [list source [file join $dir mk4vfs.tcl]]
 set auto_index(::scripdoc::init) [list source [file join $dir scripdoc.tcl]]
 set auto_index(::scripdoc::extendPath) [list source [file join $dir scripdoc.tcl]]
-set auto_index(::vfs::tclproc::Mount) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::Unmount) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::handler) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::stat) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::access) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::exists) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::open) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::_generate) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::matchindirectory) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::createdirectory) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::removedirectory) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::deletefile) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::fileattributes) [list source [file join $dir tclprocvfs.tcl]]
-set auto_index(::vfs::tclproc::utime) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::Mount) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::Unmount) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::handler) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::stat) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::access) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::exists) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::open) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::_generate) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::matchindirectory) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::createdirectory) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::removedirectory) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::deletefile) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::fileattributes) [list source [file join $dir tclprocvfs.tcl]]
+set auto_index(::vfs::ns::utime) [list source [file join $dir tclprocvfs.tcl]]
 set auto_index(::vfs::test::Mount) [list source [file join $dir testvfs.tcl]]
 set auto_index(::vfs::test::Unmount) [list source [file join $dir testvfs.tcl]]
 set auto_index(::vfs::test::handler) [list source [file join $dir testvfs.tcl]]
@@ -74,8 +87,16 @@ set auto_index(::vfs::test::deletefile) [list source [file join $dir testvfs.tcl
 set auto_index(::vfs::test::fileattributes) [list source [file join $dir testvfs.tcl]]
 set auto_index(::vfs::test::utime) [list source [file join $dir testvfs.tcl]]
 set auto_index(::vfs::debug) [list source [file join $dir vfs.tcl]]
-set auto_index(::vfs::url::Mount) [list source [file join $dir vfsUrl.tcl]]
-set auto_index(::vfs::url::handler) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::Mount) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::handler) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::stat) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::access) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::matchindirectory) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::createdirectory) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::removedirectory) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::deletefile) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::fileattributes) [list source [file join $dir vfsUrl.tcl]]
+set auto_index(::vfs::urltype::utime) [list source [file join $dir vfsUrl.tcl]]
 set auto_index(::vfs::listVolumes) [list source [file join $dir vfsUtils.tcl]]
 set auto_index(::vfs::addVolume) [list source [file join $dir vfsUtils.tcl]]
 set auto_index(::vfs::removeVolume) [list source [file join $dir vfsUtils.tcl]]
index aea4c624d474ee9b276532ac9073acf89045aae6..84677b6a2f4ac5633ab4b323c29b76ca190edc0d 100644 (file)
@@ -7,22 +7,22 @@ package require vfs 1.0
 # procedures with the same name as a namespace, which are hidden in
 # a filesystem representation.
 
-namespace eval vfs::tclproc {}
+namespace eval vfs::ns {}
 
-proc vfs::tclproc::Mount {ns local} {
+proc vfs::ns::Mount {ns local} {
     if {![namespace exists ::$ns]} {
        error "No such namespace"
     }
-    ::vfs::log "tclproc $ns mounted at $local"
-    vfs::filesystem mount $local [list vfs::tclproc::handler $ns]
-    vfs::RegisterMount $local [list vfs::tclproc::Unmount]
+    ::vfs::log "ns $ns mounted at $local"
+    vfs::filesystem mount $local [list vfs::ns::handler $ns]
+    vfs::RegisterMount $local [list vfs::ns::Unmount]
 }
 
-proc vfs::tclproc::Unmount {local} {
+proc vfs::ns::Unmount {local} {
     vfs::filesystem unmount $local
 }
 
-proc vfs::tclproc::handler {ns cmd root relative actualpath args} {
+proc vfs::ns::handler {ns cmd root relative actualpath args} {
     regsub -all / $relative :: relative
     if {$cmd == "matchindirectory"} {
        eval [list $cmd $ns $relative $actualpath] $args
@@ -32,9 +32,9 @@ proc vfs::tclproc::handler {ns cmd root relative actualpath args} {
 }
 
 # If we implement the commands below, we will have a perfect
-# virtual file system for remote tclproc sites.
+# virtual file system for namespaces.
 
-proc vfs::tclproc::stat {ns name} {
+proc vfs::ns::stat {ns name} {
     ::vfs::log "stat $name"
     if {[namespace exists ::${ns}::${name}]} {
        return [list type directory size 0 mode 0777 \
@@ -47,7 +47,7 @@ proc vfs::tclproc::stat {ns name} {
     }
 }
 
-proc vfs::tclproc::access {ns name mode} {
+proc vfs::ns::access {ns name mode} {
     ::vfs::log "access $name $mode"
     if {[namespace exists ::${ns}::${name}]} {
        return 1
@@ -61,7 +61,7 @@ proc vfs::tclproc::access {ns name mode} {
     }
 }
 
-proc vfs::tclproc::exists {ns name} {
+proc vfs::ns::exists {ns name} {
     if {[namespace exists ::${ns}::${name}]} {
        return 1
     } elseif {[llength [info procs ::${ns}::${name}]]} {
@@ -71,7 +71,7 @@ proc vfs::tclproc::exists {ns name} {
     }
 }
 
-proc vfs::tclproc::open {ns name mode permissions} {
+proc vfs::ns::open {ns name mode permissions} {
     ::vfs::log "open $name $mode $permissions"
     # return a list of two elements:
     # 1. first element is the Tcl channel name which has been opened
@@ -95,7 +95,7 @@ proc vfs::tclproc::open {ns name mode permissions} {
     }
 }
 
-proc vfs::tclproc::_generate {p} {
+proc vfs::ns::_generate {p} {
     lappend a proc $p
     set argslist [list]
     foreach arg [info args $p] {
@@ -108,7 +108,7 @@ proc vfs::tclproc::_generate {p} {
     lappend a $argslist [info body $p]
 }
 
-proc vfs::tclproc::matchindirectory {ns path actualpath pattern type} {
+proc vfs::ns::matchindirectory {ns path actualpath pattern type} {
     ::vfs::log "matchindirectory $path $actualpath $pattern $type"
     set res [list]
 
@@ -131,22 +131,22 @@ proc vfs::tclproc::matchindirectory {ns path actualpath pattern type} {
     return $realres
 }
 
-proc vfs::tclproc::createdirectory {ns name} {
+proc vfs::ns::createdirectory {ns name} {
     ::vfs::log "createdirectory $name"
     namespace eval ::${ns}::${name} {}
 }
 
-proc vfs::tclproc::removedirectory {ns name} {
+proc vfs::ns::removedirectory {ns name} {
     ::vfs::log "removedirectory $name"
     namespace delete ::${ns}::${name}
 }
 
-proc vfs::tclproc::deletefile {ns name} {
+proc vfs::ns::deletefile {ns name} {
     ::vfs::log "deletefile $name"
     rename ::${ns}::${name} {}
 }
 
-proc vfs::tclproc::fileattributes {ns name args} {
+proc vfs::ns::fileattributes {ns name args} {
     ::vfs::log "fileattributes $args"
     switch -- [llength $args] {
        0 {
@@ -181,7 +181,7 @@ proc vfs::tclproc::fileattributes {ns name args} {
     }
 }
 
-proc vfs::tclproc::utime {what name actime mtime} {
+proc vfs::ns::utime {what name actime mtime} {
     ::vfs::log "utime $name"
     error ""
 }
index 2b22bcdb0cac81d94e9be8ec1b51c4bbeb75afe6..18a8303809ffe3b162d9cbd9edbcde22f29c1cb4 100644 (file)
+# The idea here is that we can mount 'ftp' or 'http' or 'file' types
+# of urls and that (provided we have separate vfs types for them) we
+# can then treat 'ftp://' as a mount point for ftp services.  For
+# example, we can do:
+#
+# % vfs::urltype::Mount ftp
+# Mounted at "ftp://"
+# % cd ftp://
+# % cd ftp.ucsd.edu   (or 'cd user:pass@ftp.foo.com')
+# (This now creates an ordinary ftp-vfs for the remote site)
+# ...
+#
+# Or all in one go:
+# 
+# % file copy ftp://ftp.ucsd.edu/pub/alpha/Readme .
 
+namespace eval ::vfs::urltype {}
 
-namespace eval ::vfs::url {}
-
-proc vfs::url::Mount {type} {
+proc vfs::urltype::Mount {type} {
     # This requires Tcl 8.4a4.
-    set volume "${type}://"
+    set mountPoint "${type}://"
     if {$type == "file"} {
-       append volume "/"
+       append mountPoint "/"
     }
-    ::vfs::addVolume $volume
-    ::vfs::filesystem mount $volume [list vfs::url::handler $type]
+    ::vfs::addVolume "${mountPoint}"
+    ::vfs::filesystem mount $mountPoint [list vfs::urltype::handler $type]
+    return "Mounted at \"${mountPoint}\""
 }
 
-proc vfs::url::handler {type cmd root relative actualpath args} {
+proc vfs::urltype::handler {type cmd root relative actualpath args} {
     puts stderr [list $type $cmd $root $relative $actualpath $args]
+    if {$cmd == "matchindirectory"} {
+       eval [list $cmd $type $relative $actualpath] $args
+    } else {
+       eval [list $cmd $type $relative] $args
+    }
+}
+
+# Stuff below not very well implemented.
+
+proc vfs::urltype::stat {ns name} {
+    ::vfs::log "stat $name"
+    if {![string length $name]} {
+       return [list type directory size 0 mode 0777 \
+         ino -1 depth 0 name $name atime 0 ctime 0 mtime 0 dev -1 \
+         uid -1 gid -1 nlink 1]
+    } elseif {1} {
+       return [list type file]
+    } else {
+       return -code error "could not read \"$name\": no such file or directory"
+    }
+}
+
+proc vfs::urltype::access {ns name mode} {
+    ::vfs::log "access $name $mode"
+    if {![string length $name]} {
+       return 1
+    } elseif {1} {
+       if {$mode & 2} {
+           error "read-only"
+       }
+       return 1
+    } else {
+       error "No such file"
+    }
+}
+
+proc vfs::urltype::matchindirectory {ns path actualpath pattern type} {
+    ::vfs::log "matchindirectory $path $actualpath $pattern $type"
+    set res [list]
+
+    return $res
+}
+
+proc vfs::urltype::createdirectory {ns name} {
+    ::vfs::log "createdirectory $name"
+    error ""
+}
+
+proc vfs::urltype::removedirectory {ns name} {
+    ::vfs::log "removedirectory $name"
     error ""
 }
 
-proc vfs::url::handler {args} {
-    puts stderr $args
+proc vfs::urltype::deletefile {ns name} {
+    ::vfs::log "deletefile $name"
     error ""
 }
 
+proc vfs::urltype::fileattributes {fd path args} {
+    ::vfs::log "fileattributes $args"
+    switch -- [llength $args] {
+       0 {
+           # list strings
+           return [list]
+       }
+       1 {
+           # get value
+           set index [lindex $args 0]
+       }
+       2 {
+           # set value
+           set index [lindex $args 0]
+           set val [lindex $args 1]
+       }
+    }
+}
+
+proc vfs::urltype::utime {what name actime mtime} {
+    ::vfs::log "utime $name"
+    error ""
+}
index d698081a756ac66805937028355b036190e18b3d..121301fc5525b4ef9c3336d289d667972a8123a1 100644 (file)
@@ -2,7 +2,8 @@
 package require vfs 1.0
 
 # Using the vfs, memchan and Trf extensions, we ought to be able
-# to write a Tcl-only zip virtual filesystem.
+# to write a Tcl-only zip virtual filesystem.  What we have below
+# is basically that.
 
 namespace eval vfs::zip {}
 
index 12fb8a0afa9bdfe669e5fd831fb1ab97edb1e5c0..9c1cb7bd23b398b1ddcf34d4ffe5e02e041f1031 100644 (file)
@@ -13,7 +13,7 @@ VFS_VERSION = 1.0
 DLL_VERSION = 10
 
 # comment the following line to compile with symbols
-NODEBUG=0
+NODEBUG=1
 
 !IF "$(NODEBUG)" == "1"
 DEBUGDEFINES =