Updated 2012-01-06 02:14:02 by RLE

WK The following is a sample code that uses memchan to mount a VFS that saves everything in RAM. I wrote this because some code (like tclcompiler) needs to write to a file, so it's easier to put it on a dummy VFS than in a temporary file. Enjoy.

DAS - also see vfs::inmem
 package provide vfs::ram 0.5
 
 # This works for basic operations, but has not been very debugged.
 
 namespace eval vfs::ram {}
 
 proc vfs::ram::Mount {domain local} {
    if {![catch {vfs::filesystem info $domain}]} {
        vfs::unmount $domain
    }
    # register the mount
    eval [concat [list vfs::filesystem mount] $args \
        [list $local [list vfs::ram::handler $domain]]]
    # Register command to unmount
    vfs::RegisterMount $local [list ::vfs::ram::Unmount $domain]
    return $domain
 }
 
 proc vfs::ram::Unmount {domain local} {
    vfs::filesystem unmount $local
 }
 
 proc vfs::ram::handler {dirurl cmd root relative actualpath args} {
    if {$cmd == "matchindirectory"} {
        eval [list $cmd $dirurl $relative $actualpath] $args
    } else {
        eval [list $cmd $dirurl $relative] $args
    }
 }
 
 # If we implement the commands below, we will have a perfect
 # virtual file system for remote http sites.
 
 proc vfs::ram::stat {dirurl name} {
    ::vfs::log "stat $name"
    if {[catch {_file_size $dirurl$name} size]} {
      vfs::filesystem posixerror $::vfs::posix(ENOENT)
      return
    }
    lappend res type file
    set mtime 0
    lappend res dev -1 uid -1 gid -1 nlink 1 depth 0 \
      atime $mtime ctime $mtime mtime $mtime mode 0777 size $size
    return $res
 }
 
 proc vfs::ram::access {dirurl 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::ram::open {dirurl 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.
    set filed [vfs::memchan]
    vfs::ram::_onopen $mode $dirurl$name $filed
    return [list $filed [list vfs::ram::_onclose $mode $dirurl$name $filed]]
 }
 
 proc vfs::ram::matchindirectory {dirurl path actualpath pattern type} {
    ::vfs::log "matchindirectory $path $pattern $type"
    set res [list]
    return $res
 }
 
 proc vfs::ram::createdirectory {dirurl name} {
    ::vfs::log "createdirectory $name"
    vfs::filesystem posixerror $::vfs::posix(EROFS)
 }
 
 proc vfs::ram::removedirectory {dirurl name recursive} {
    ::vfs::log "removedirectory $name"
    vfs::filesystem posixerror $::vfs::posix(EROFS)
 }
 
 proc vfs::ram::deletefile {dirurl name} {
    ::vfs::log "deletefile $dirurl$name"
    if {[catch {_delete $dirurl$name}]} {
        vfs::filesystem posixerror $::vfs::posix(ENOENT)
    }
 }
 
 proc vfs::ram::fileattributes {dirurl 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::ram::utime {dirurl path actime mtime} {
    vfs::filesystem posixerror $::vfs::posix(EROFS)
 }
 
 proc vfs::ram::_onopen {mode filename filed} {
    if {![catch {_file_get $filename} data]} {
        fconfigure $filed -translation binary
        puts -nonewline $filed $data
        seek $filed 0
        fconfigure $filed -translation auto
    }
 }
 proc vfs::ram::_onclose {mode filename filed} {
    variable filedata
    fconfigure $filed -translation binary
    seek $filed 0
    set data [read $filed]
    _file_set $filename $data
 }
 if {[info exists ::tcl_platform(threaded)]&&$::tcl_platform(threaded)} {
    package require Thread
    proc vfs::ram::_delete {filename} {
        tsv::unset VfsRam $filename
    }
    proc vfs::ram::_file_get {filename} {
        variable filedata
        return [tsv::get VfsRam $filename]
    }
    proc vfs::ram::_file_set {filename data} {
        variable filedata
        tsv::set VfsRam $filename $data
    }
 }  else  {
    proc vfs::ram::_delete {filename} {
        variable filedata
        unset filedata($filename)
    }
    proc vfs::ram::_file_get {filename} {
        variable filedata
        return $filedata($filename)
    }
    proc vfs::ram::_file_set {filename data} {
        variable filedata
        set filedata($filename) $data
    }
 }
 
 proc vfs::ram::_file_size {filename} {
    variable filedata
    return [string length [_file_get $filename]]
 }