package provide vfs::map 0.5
package require vfs 1.0
# This works for basic operations, but has not been very debugged.
namespace eval vfs::map {}
proc vfs::map::Mount {args} {
set command [lindex $args end-1]
set local [lindex $args end]
if {![catch {vfs::filesystem info $command}]} {
vfs::unmount $command
}
eval [concat [list vfs::filesystem mount] [lrange $args 0 end-2] [list $local [list vfs::map::handler $command]]]
# Register command to unmount
vfs::RegisterMount $local [list ::vfs::map::Unmount $command]
return $local
}
proc vfs::map::Unmount {command local} {
vfs::filesystem unmount $local
}
proc vfs::map::handler {command cmd root relative actualpath args} {
if {$cmd == "matchindirectory"} {
eval [list $cmd $command $relative $actualpath] $args
} else {
eval [list $cmd $command $relative] $args
}
}
# If we implement the commands below, we will have a perfect
# virtual file system for remote http sites.
proc vfs::map::getFileName {name} {
upvar mapcommand mapcommand
return [eval [concat $mapcommand] [list $name]]
}
proc vfs::map::stat {mapcommand name} {
::vfs::log "stat $name"
file stat [getFileName $name] a
return [array get a]
}
proc vfs::map::access {mapcommand name mode} {
::vfs::log "access $name $mode"
vfs::filesystem posixerror $::vfs::posix(EROFS)
return 1
}
# We've chosen to implement these channels by using a memchan.
# The alternative would be to use temporary files.
proc vfs::map::open {mapcommand name mode permissions} {
set permissions [format 0%03o $permissions]
if {$mode == ""} {set mode "r"}
::vfs::log "open $name $mode $permissions"
set filed [::open [getFileName $name] $mode $permissions]
return [list $filed [list vfs::map::_onclose $mode $mapcommand $filed]]
}
proc vfs::map::matchindirectory {mapcommand path actualpath pattern type} {
::vfs::log "matchindirectory $path $pattern $type"
set rc [list]
foreach res [vfs::matchCorrectTypes $type [glob -tails -nocomplain -directory [getFileName $path] $pattern]] {
lappend rc [file join $actualpath $res]
}
return $rc
}
proc vfs::map::createdirectory {mapcommand name} {
::vfs::log "createdirectory $name"
file mkdir [getFileName $name]
}
proc vfs::map::removedirectory {mapcommand name recursive} {
::vfs::log "removedirectory $name"
vfs::filesystem posixerror $::vfs::posix(EROFS)
file delete [getFileName $name]
}
proc vfs::map::deletefile {mapcommand name} {
::vfs::log "deletefile $mapcommand$name"
file delete [getFileName $name]
}
proc vfs::map::fileattributes {mapcommand path args} {
::vfs::log "fileattributes $args"
switch -- [llength $args] {
0 {
# list strings
return [list]
}
1 {
# get value
vfs::filesystem posixerror $::vfs::posix(EROFS)
}
2 {
# set value
vfs::filesystem posixerror $::vfs::posix(EROFS)
}
}
}
proc vfs::map::utime {mapcommand path actime mtime} {
vfs::filesystem posixerror $::vfs::posix(EROFS)
}
proc vfs::map::_onclose {mapcommand filename filed} {
}
# handlers
proc vfs::map::handleMultidir {args} {
set dirs [::lrange $args 0 end-1]
set relativename [::lindex $args end]
set split [::file split $relativename]
set rc [file join [lindex $dirs 0] $relativename]
for {set i 0} {$i < [llength $split]} {incr i} {
foreach dir $dirs {
set rname [eval [concat [list ::file join $dir] [lrange $split 0 $i]]]
if {[file exists $rname]} {
set rc [eval [concat [list ::file join $rname] [lrange $split [expr {$i+1}] end]]]
}
}
}
return $rc
}For example on Windows:vfs::map::Mount -volume [concat [list vfs::map::handleMultidir] [split $::env(PATH) \;]] PATH:and on UNIX:
vfs::map::Mount -volume [concat [list vfs::map::handleMultidir] [split $::env(PATH) :]] PATH:Creates a virtual mapping by which you can easily do:
if {![file exists PATH:dqkit.exe]} {
puts "dqkit.exe not in PATH."
}It can also be used to map multiple directories to one virtual directory. Note that globbing does not work as one would expect - it should actually join globs, but it does not. This idea is based on Symbian's ?: virtual mapping.escargo 22 Mar 2006 - Could you give a little more explanation of what is mapped to what?WK The idea is simple - you can write a procedure that will translate names relative to vfs root (ie PATH: above) to names either native or on a different VFS.vfs::map::handleMultidir is a proc that looks for a specific file in multiple directories - so you can for example have your application's data on CD and updated files on your harddrive and you just access appdata:data/myfile.dat, without actually looking for those files in multiple directories manually.SEH 2006Mar24 -- See A collate/broadcast virtual filesystem

