mk4vfs fix
authorJean-Claude Wippler <jcw@equi4.com>
Sat, 22 Jun 2002 12:23:52 +0000 (12:23 +0000)
committerJean-Claude Wippler <jcw@equi4.com>
Sat, 22 Jun 2002 12:23:52 +0000 (12:23 +0000)
ChangeLog
library/mk4vfs.tcl
library/pkgIndex.tcl
mac/pkgIndex_mac.tcl

index 8b635d68a4da822f52e50fac58bdb2d4ce9c3e44..7877a6b7db9cf60d27adad9141663897d48143ea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2002-06-22  Jean-Claude Wippler <jcw@equi4.com>
+       * mac/pkgIndex_mac.tcl:
+       * library/pkgIndex.tcl:
+       * library/mk4vfs.in: fix recursive file deletion, bump to 1.5
+
 2002-05-29  Jean-Claude Wippler <jcw@equi4.com>
        * Makefile.in: moved the definition of $(OBJEXT) up so the
        definition of vfs_OBJECTS works with more make's
index 0caec3197d3c534f9db33711099321e27da56fcb..176353434583979aaebba7fe5e00476ab91afbcb 100644 (file)
 #                              privatized memchan_handler
 #                              added zip, crc back in
 # 1.4 jcw      28-04-2002      reorged memchan and pkg dependencies
+# 1.5 jcw      22-06-2002      fixed recursive dir deletion
 
-package provide mk4vfs 1.4
+package provide mk4vfs 1.5
 package require Mk4tcl
 package require vfs
 
+# need this so init failure in interactive mode does not mess up errorInfo
+if {[info exists env(VFS_DEBUG)] && [info commands history] == ""} {
+  proc history {args} {}
+}
+
 # things that can no longer really be left out (but this is the wrong spot!)
 # be as non-invasive as possible, using these definitions as last resort
 
- if {![info exists auto_index(lassign)] && [info commands lassign] == ""} {
-   set auto_index(lassign) {
-     proc lassign {l args} {
-       foreach v $l a $args { uplevel 1 [list set $a $v] }
-     }
-   }
- }
 if {![info exists auto_index(lassign)] && [info commands lassign] == ""} {
+    set auto_index(lassign) {
+      proc lassign {l args} {
+       foreach v $l a $args { uplevel 1 [list set $a $v] }
+      }
+    }
 }
 
 namespace eval vfs::mk4 {
 
- proc Mount {mkfile local args} {
-   set db [eval [list ::mk4vfs::_mount $local $mkfile] $args]
-   ::vfs::filesystem mount $local [list ::vfs::mk4::handler $db]
-   ::vfs::RegisterMount $local [list ::vfs::mk4::Unmount $db]
-   return $db
- }
-
- proc Unmount {db local} {
-   vfs::filesystem unmount $local
-   ::mk4vfs::_umount $db
- }
-
- proc handler {db cmd root relative actualpath args} {
-#puts stderr "handler: $db - $cmd - $root - $relative - $actualpath - $args"
-   if {$cmd == "matchindirectory"} {
-     eval [list $cmd $db $relative $actualpath] $args
-   } elseif {$cmd == "fileattributes"} {
-     eval [list $cmd $db $root $relative] $args
-   } else {
-     eval [list $cmd $db $relative] $args
-   }
- }
-
- proc utime {db path actime modtime} {
-   ::mk4vfs::stat $db $path sb
-   
-   if { $sb(type) == "file" } {
-     ::mk::set $sb(ino) date $modtime
-   }
- }
-
- proc matchindirectory {db path actualpath pattern type} {
-   set newres [list]
-   if {![string length $pattern]} {
-     # check single file
-     set res [list $actualpath]
-     set actualpath ""
-   } else {
-     set res [::mk4vfs::getdir $db $path $pattern]
-   }
-   foreach p [::vfs::matchCorrectTypes $type $res $actualpath] {
-     lappend newres "$actualpath$p"
-   }
-   return $newres
- }
-
- proc stat {db name} {
-   ::mk4vfs::stat $db $name sb
-
-   set sb(ino) 0
-   array get sb
- }
-
- proc access {db name mode} {
-   # This needs implementing better.  
-   ::mk4vfs::stat $db $name sb
- }
-
- proc open {db file 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 {
-       ::mk4vfs::stat $db $file sb
-
-       if { $sb(csize) != $sb(size) } {
-        set fd [vfs::memchan]
-        fconfigure $fd -translation binary
-        set s [mk::get $sb(ino) contents]
-        puts -nonewline $fd [vfs::zip -mode decompress $s]
-
-        fconfigure $fd -translation auto
-        seek $fd 0
-        return $fd
-       } elseif { $::mk4vfs::direct } {
-        set fd [vfs::memchan]
-        fconfigure $fd -translation binary
-        puts -nonewline $fd [mk::get $sb(ino) contents]
-
-        fconfigure $fd -translation auto
-        seek $fd 0
-        return $fd
-       } else {
-        set fd [mk::channel $sb(ino) contents r]
-       }
-       return [list $fd]
-     }
-     a {
-       if { [catch {::mk4vfs::stat $db $file sb }] } {
-        # Create file
-        ::mk4vfs::stat $db [file dirname $file] sb
-        set tail [file tail $file]
-        set fview $sb(ino).files
-        if {[info exists mk4vfs::v::fcache($fview)]} {
-          lappend mk4vfs::v::fcache($fview) $tail
-        }
-        set now [clock seconds]
-        set sb(ino) [mk::row append $fview name $tail size 0 date $now ]
-
-        if { [string match *z* $mode] || $mk4vfs::compress } {
-          set sb(csize) -1  ;# HACK - force compression
-        } else {
-          set sb(csize) 0
-        }
-       }
-
-       set fd [vfs::memchan]
-       fconfigure $fd -translation binary
-       set s [mk::get $sb(ino) contents]
-
-       if { $sb(csize) != $sb(size) && $sb(csize) > 0 } {
-        append mode z
-        puts -nonewline $fd [vfs::zip -mode decompress $s]
-       } else {
-        if { $mk4vfs::compress } { append mode z }
-        puts -nonewline $fd $s
-        #set fd [mk::channel $sb(ino) contents a]
-       }
-       fconfigure $fd -translation auto
-       seek $fd 0 end
-       return [list $fd [list mk4vfs::do_close $fd $mode $sb(ino)]]
-     }
-     w*  {
-       if { [catch {::mk4vfs::stat $db $file sb }] } {
-        # Create file
-        ::mk4vfs::stat $db [file dirname $file] sb
-        set tail [file tail $file]
-        set fview $sb(ino).files
-        if {[info exists mk4vfs::v::fcache($fview)]} {
-          lappend mk4vfs::v::fcache($fview) $tail
-        }
-        set now [clock seconds]
-        set sb(ino) [mk::row append $fview name $tail size 0 date $now ]
-       }
-
-       if { [string match *z* $mode] || $mk4vfs::compress } {
-        append mode z
-        set fd [vfs::memchan]
-       } else {
-        set fd [mk::channel $sb(ino) contents w]
-       }
-       return [list $fd [list mk4vfs::do_close $fd $mode $sb(ino)]]
-     }
-     default   {
-       error "illegal access mode \"$mode\""
-     }
-   }
- }
-
- proc createdirectory {db name} {
-   mk4vfs::mkdir $db $name
- }
-
proc removedirectory {db name} {
-   mk4vfs::delete $db $name
- }
-
- proc deletefile {db name} {
-   mk4vfs::delete $db $name
- }
-
- proc fileattributes {db root relative args} {
-   switch -- [llength $args] {
-     0 {
-       # list strings
-       return [::vfs::listAttributes]
-     }
-     1 {
-       # get value
-       set index [lindex $args 0]
-       return [::vfs::attributesGet $root $relative $index]
-
-     }
-     2 {
-       # set value
-       set index [lindex $args 0]
-       set val [lindex $args 1]
-       return [::vfs::attributesSet $root $relative $index $val]
-     }
-   }
- }
 proc Mount {mkfile local args} {
+    set db [eval [list ::mk4vfs::_mount $local $mkfile] $args]
+    ::vfs::filesystem mount $local [list ::vfs::mk4::handler $db]
+    ::vfs::RegisterMount $local [list ::vfs::mk4::Unmount $db]
+    return $db
 }
+
 proc Unmount {db local} {
+    vfs::filesystem unmount $local
+    ::mk4vfs::_umount $db
 }
+
 proc handler {db cmd root relative actualpath args} {
+ #puts stderr "handler: $db - $cmd - $root - $relative - $actualpath - $args"
+    if {$cmd == "matchindirectory"} {
+      eval [list $cmd $db $relative $actualpath] $args
+    } elseif {$cmd == "fileattributes"} {
+      eval [list $cmd $db $root $relative] $args
+    } else {
+      eval [list $cmd $db $relative] $args
+    }
 }
+
 proc utime {db path actime modtime} {
+    ::mk4vfs::stat $db $path sb
+    
+    if { $sb(type) == "file" } {
+      ::mk::set $sb(ino) date $modtime
+    }
 }
+
 proc matchindirectory {db path actualpath pattern type} {
+    set newres [list]
+    if {![string length $pattern]} {
+      # check single file
+      set res [list $actualpath]
+      set actualpath ""
+    } else {
+      set res [::mk4vfs::getdir $db $path $pattern]
+    }
+    foreach p [::vfs::matchCorrectTypes $type $res $actualpath] {
+      lappend newres "$actualpath$p"
+    }
+    return $newres
 }
+
 proc stat {db name} {
+    ::mk4vfs::stat $db $name sb
+
+    set sb(ino) 0
+    array get sb
 }
+
 proc access {db name mode} {
+    # This needs implementing better.  
+    ::mk4vfs::stat $db $name sb
 }
+
 proc open {db file 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 {
+       ::mk4vfs::stat $db $file sb
+
+       if { $sb(csize) != $sb(size) } {
+         set fd [vfs::memchan]
+         fconfigure $fd -translation binary
+         set s [mk::get $sb(ino) contents]
+         puts -nonewline $fd [vfs::zip -mode decompress $s]
+
+         fconfigure $fd -translation auto
+         seek $fd 0
+         return $fd
+       } elseif { $::mk4vfs::direct } {
+         set fd [vfs::memchan]
+         fconfigure $fd -translation binary
+         puts -nonewline $fd [mk::get $sb(ino) contents]
+
+         fconfigure $fd -translation auto
+         seek $fd 0
+         return $fd
+       } else {
+         set fd [mk::channel $sb(ino) contents r]
+       }
+       return [list $fd]
+      }
+      a {
+       if { [catch {::mk4vfs::stat $db $file sb }] } {
+         # Create file
+         ::mk4vfs::stat $db [file dirname $file] sb
+         set tail [file tail $file]
+         set fview $sb(ino).files
+         if {[info exists mk4vfs::v::fcache($fview)]} {
+           lappend mk4vfs::v::fcache($fview) $tail
+         }
+         set now [clock seconds]
+         set sb(ino) [mk::row append $fview name $tail size 0 date $now ]
+
+         if { [string match *z* $mode] || $mk4vfs::compress } {
+           set sb(csize) -1  ;# HACK - force compression
+         } else {
+           set sb(csize) 0
+         }
+       }
+
+       set fd [vfs::memchan]
+       fconfigure $fd -translation binary
+       set s [mk::get $sb(ino) contents]
+
+       if { $sb(csize) != $sb(size) && $sb(csize) > 0 } {
+         append mode z
+         puts -nonewline $fd [vfs::zip -mode decompress $s]
+       } else {
+         if { $mk4vfs::compress } { append mode z }
+         puts -nonewline $fd $s
+         #set fd [mk::channel $sb(ino) contents a]
+       }
+       fconfigure $fd -translation auto
+       seek $fd 0 end
+       return [list $fd [list mk4vfs::do_close $fd $mode $sb(ino)]]
+      }
+      w*  {
+       if { [catch {::mk4vfs::stat $db $file sb }] } {
+         # Create file
+         ::mk4vfs::stat $db [file dirname $file] sb
+         set tail [file tail $file]
+         set fview $sb(ino).files
+         if {[info exists mk4vfs::v::fcache($fview)]} {
+           lappend mk4vfs::v::fcache($fview) $tail
+         }
+         set now [clock seconds]
+         set sb(ino) [mk::row append $fview name $tail size 0 date $now ]
+       }
+
+       if { [string match *z* $mode] || $mk4vfs::compress } {
+         append mode z
+         set fd [vfs::memchan]
+       } else {
+         set fd [mk::channel $sb(ino) contents w]
+       }
+       return [list $fd [list mk4vfs::do_close $fd $mode $sb(ino)]]
+      }
+      default   {
+       error "illegal access mode \"$mode\""
+      }
+    }
 }
+
 proc createdirectory {db name} {
+    mk4vfs::mkdir $db $name
 }
+
 proc removedirectory {db name recursive} {
+    mk4vfs::delete $db $name $recursive
 }
+
 proc deletefile {db name} {
+    mk4vfs::delete $db $name
 }
+
 proc fileattributes {db root relative args} {
+    switch -- [llength $args] {
+      0 {
+       # list strings
+       return [::vfs::listAttributes]
+      }
+      1 {
+       # get value
+       set index [lindex $args 0]
+       return [::vfs::attributesGet $root $relative $index]
+
+      }
+      2 {
+       # set value
+       set index [lindex $args 0]
+       set val [lindex $args 1]
+       return [::vfs::attributesSet $root $relative $index $val]
+      }
+    }
 }
 }
 
 namespace eval mk4vfs {
- variable compress 1     ;# HACK - needs to be part of "Super-Block"
- variable flush    5000  ;# Auto-Commit frequency
- variable direct   0     ;# read through a memchan, or from Mk4tcl if zero
-
- namespace eval v {
-   variable seq      0
-
-   array set cache {}
-   array set fcache {}
- }
-
- namespace export mount umount
-
- proc init {db} {
-   mk::view layout $db.dirs {name:S parent:I {files {name:S size:I date:I contents:M}}}
-
-   if { [mk::view size $db.dirs] == 0 } {
-     mk::row append $db.dirs name <root> parent 0
-   }
-
-   # 2001-12-13: use parent -1 for root level!
-   mk::set $db.dirs!0 parent -1
- }
-
- proc mount {local mkfile args} {
-   uplevel [list ::vfs::mk4::Mount $mkfile $local] $args
- }
-
- proc _mount {path file args} {
-   set db mk4vfs[incr v::seq]
-
-   eval [list mk::file open $db $file] $args
-
-   init $db
-
-   set flush 1
-   for {set idx 0} {$idx < [llength $args]} {incr idx} {
-     switch -- [lindex $args $idx] {
-       -readonly   -
-       -nocommit   {set flush 0}
-     }
-   }
-   if { $flush } {
-     _commit $db
-   }
-   return $db
- }
-
- proc _commit {db} {
-   variable flush
-   after $flush [list mk4vfs::_commit $db]
-   mk::file commit $db
- }
-
- proc umount {local} {
-   foreach {db path} [mk::file open] {
-     if {[string equal $local $path]} {
-       uplevel ::vfs::mk4::Unmount $db $local
-       return
-     }
-   }
-   tclLog "umount $local? [mk::file open]"
- }
-
- proc _umount {db} {
-   after cancel [list mk4vfs::_commit $db]
-   array unset v::cache $db,*
-   array unset v::fcache $db.*
-   mk::file close $db
- }
-
- proc stat {db path arr} {
-   upvar 1 $arr sb
-
-   set sp [::file split $path]
-   set tail [lindex $sp end]
-
-   set parent 0
-   set view $db.dirs
-   set type directory
-
-   foreach ele [lrange $sp 0 end-1] {
-     if {[info exists v::cache($db,$parent,$ele)]} {
-       set parent $v::cache($db,$parent,$ele)
-     } else {
-       set row [mk::select $view -count 1 parent $parent name $ele]
-       if { $row == "" } {
-        return -code error "could not read \"$path\": no such file or directory"
-       }
-       set v::cache($db,$parent,$ele) $row
-       set parent $row
-     }
-   }
-   
-   # Now check if final comp is a directory or a file
-   # CACHING is required - it can deliver a x15 speed-up!
-   
-   if { [string equal $tail "."] || [string equal $tail ":"] ||
-                                        [string equal $tail ""] } {
-     set row $parent
-
-   } elseif { [info exists v::cache($db,$parent,$tail)] } {
-     set row $v::cache($db,$parent,$tail)
-   } else {
-     # File?
-     set fview $view!$parent.files
-     # create a name cache of files in this directory
-     if {![info exists v::fcache($fview)]} {
-       # cache only a limited number of directories
-       if {[array size v::fcache] >= 10} {
-        array unset v::fcache *
-       }
-       set v::fcache($fview) {}
-       mk::loop c $fview {
-        lappend v::fcache($fview) [mk::get $c name]
-       }
-     }
-     set row [lsearch -exact $v::fcache($fview) $tail]
-     #set row [mk::select $fview -count 1 name $tail]
-     #if {$row == ""} { set row -1 }
-     if { $row != -1 } {
-       set type file
-       set view $view!$parent.files
-     } else {
-       # Directory?
-       set row [mk::select $view -count 1 parent $parent name $tail]
-       if { $row != "" } {
-        set v::cache($db,$parent,$tail) $row
-       } else { 
-        return -code error "could not read \"$path\": no such file or directory"
-       }
-     }
-   }
-   set cur $view!$row
-
-   set sb(type)    $type
-   set sb(view)    $view
-   set sb(ino)     $cur
-
-   if { [string equal $type "directory"] } {
-     set sb(atime) 0
-     set sb(ctime) 0
-     set sb(gid)   0
-     set sb(mode)  0777
-     set sb(mtime) 0
-     set sb(nlink) [expr { [mk::get $cur files] + 1 }]
-     set sb(size)  0
-     set sb(csize) 0
-     set sb(uid)   0
-   } else {
-     set mtime   [mk::get $cur date]
-     set sb(atime) $mtime
-     set sb(ctime) $mtime
-     set sb(gid)   0
-     set sb(mode)  0777
-     set sb(mtime) $mtime
-     set sb(nlink) 1
-     set sb(size)  [mk::get $cur size]
-     set sb(csize) [mk::get $cur -size contents]
-     set sb(uid)   0
-   }
- }
-
- proc do_close {fd mode cur} {
-   if {![regexp {[aw]} $mode]} {
-     error "mk4vfs::do_close called with bad mode: $mode"
-   }
-
-   mk::set $cur size -1 date [clock seconds]
-   flush $fd
-   if { [string match *z* $mode] } {
-     fconfigure $fd -translation binary
-     seek $fd 0
-     set data [read $fd]
-     set cdata [vfs::zip -mode compress $data]
-     set len [string length $data]
-     set clen [string length $cdata]
-     if { $clen < $len } {
-       mk::set $cur size $len contents $cdata
-     } else {
-       mk::set $cur size $len contents $data
-     }
-   } else {
-     mk::set $cur size [mk::get $cur -size contents]
-   }
-   # added 30-10-2000
-   set db [lindex [split $cur .] 0]
-   mk::file autocommit $db
- }
-
- proc mkdir {db path} {
-   set sp [::file split $path]
-   set parent 0
-   set view $db.dirs
-
-   set npath {}
-   foreach ele $sp {
-     set npath [file join $npath $ele]
-
-     if { ![catch {stat $db $npath sb}] } {
-       if { $sb(type) != "directory" } {
-        return -code error "can't create directory \"$npath\": file already exists"
-       }
-       set parent [mk::cursor position sb(ino)]
-       continue
-     }
-     #set parent [mk::cursor position sb(ino)]
-     set cur [mk::row append $view name $ele parent $parent]
-     set parent [mk::cursor position cur]
-   }
- }
-
- proc getdir {db path {pat *}} {
-   if {[catch { stat $db $path sb }] || $sb(type) != "directory" } {
-     return
-   }
-
-   # Match directories
-   set parent [mk::cursor position sb(ino)] 
-   foreach row [mk::select $sb(view) parent $parent -glob name $pat] {
-     set hits([mk::get $sb(view)!$row name]) 1
-   }
-   # Match files
-   set view $sb(view)!$parent.files
-   foreach row [mk::select $view -glob name $pat] {
-     set hits([mk::get $view!$row name]) 1
-   }
-   return [lsort [array names hits]]
- }
-
- proc mtime {db path time} {
-
-   stat $db $path sb
-
-   if { $sb(type) == "file" } {
-     mk::set $sb(ino) date $time
-   }
-   return $time
- }
-
- proc delete {db path {recursive 0}} {
-   stat $db $path sb
-   if {$sb(type) == "file" } {
-     mk::row delete $sb(ino)
-     if {[regexp {(.*)!(\d+)} $sb(ino) - v r] && [info exists v::fcache($v)]} {
-       set v::fcache($v) [lreplace $v::fcache($v) $r $r]
-     }
-   } else {
-     # just mark dirs as deleted
-     set contents [getdir $db $path *]
-     if {$recursive} {
-       # We have to delete these manually, else
-       # they (or their cache) may conflict with
-       # something later
-       foreach f $contents {
-        delete $db [file join $path $f] $recursive
-       }
-     } else {
-       if {[llength $contents]} {
-        return -code error "Non-empty"
-       }
-     }
-     array unset v::cache "$db,[mk::get $sb(ino) parent],[file tail $path]"
-     
-     mk::set $sb(ino) parent -1 name ""
-   }
-   return ""
- }
+  variable compress 1     ;# HACK - needs to be part of "Super-Block"
+  variable flush    5000  ;# Auto-Commit frequency
+  variable direct   0    ;# read through a memchan, or from Mk4tcl if zero
+
+  namespace eval v {
+    variable seq      0
+
+    array set cache {}
+    array set fcache {}
+  }
+
+  namespace export mount umount
+
+  proc init {db} {
+    mk::view layout $db.dirs {name:S parent:I {files {name:S size:I date:I contents:M}}}
+
+    if { [mk::view size $db.dirs] == 0 } {
+      mk::row append $db.dirs name <root> parent 0
+    }
+
+    # 2001-12-13: use parent -1 for root level!
+    mk::set $db.dirs!0 parent -1
+  }
+
+  proc mount {local mkfile args} {
+    uplevel [list ::vfs::mk4::Mount $mkfile $local] $args
+  }
+
+  proc _mount {path file args} {
+    set db mk4vfs[incr v::seq]
+
+    eval [list mk::file open $db $file] $args
+
+    init $db
+
+    set flush 1
+    for {set idx 0} {$idx < [llength $args]} {incr idx} {
+      switch -- [lindex $args $idx] {
+       -readonly   -
+       -nocommit   {set flush 0}
+      }
+    }
+    if { $flush } {
+      _commit $db
+    }
+    return $db
+  }
+
+  proc _commit {db} {
+    variable flush
+    after $flush [list mk4vfs::_commit $db]
+    mk::file commit $db
+  }
+
+  proc umount {local} {
+    foreach {db path} [mk::file open] {
+      if {[string equal $local $path]} {
+       uplevel ::vfs::mk4::Unmount $db $local
+       return
+      }
+    }
+    tclLog "umount $local? [mk::file open]"
+  }
+
+  proc _umount {db} {
+    after cancel [list mk4vfs::_commit $db]
+    array unset v::cache $db,*
+    array unset v::fcache $db.*
+    mk::file close $db
+  }
+
+  proc stat {db path arr} {
+    upvar 1 $arr sb
+
+    set sp [::file split $path]
+    set tail [lindex $sp end]
+
+    set parent 0
+    set view $db.dirs
+    set type directory
+
+    foreach ele [lrange $sp 0 end-1] {
+      if {[info exists v::cache($db,$parent,$ele)]} {
+       set parent $v::cache($db,$parent,$ele)
+      } else {
+       set row [mk::select $view -count 1 parent $parent name $ele]
+       if { $row == "" } {
+         return -code error "could not read \"$path\": no such file or directory"
+       }
+       set v::cache($db,$parent,$ele) $row
+       set parent $row
+      }
+    }
+    
+    # Now check if final comp is a directory or a file
+    # CACHING is required - it can deliver a x15 speed-up!
+    
+    if { [string equal $tail "."] || [string equal $tail ":"] ||
+                                         [string equal $tail ""] } {
+      set row $parent
+
+    } elseif { [info exists v::cache($db,$parent,$tail)] } {
+      set row $v::cache($db,$parent,$tail)
+    } else {
+      # File?
+      set fview $view!$parent.files
+      # create a name cache of files in this directory
+      if {![info exists v::fcache($fview)]} {
+       # cache only a limited number of directories
+       if {[array size v::fcache] >= 10} {
+         array unset v::fcache *
+       }
+       set v::fcache($fview) {}
+       mk::loop c $fview {
+         lappend v::fcache($fview) [mk::get $c name]
+       }
+      }
+      set row [lsearch -exact $v::fcache($fview) $tail]
+      #set row [mk::select $fview -count 1 name $tail]
+      #if {$row == ""} { set row -1 }
+      if { $row != -1 } {
+       set type file
+       set view $view!$parent.files
+      } else {
+       # Directory?
+       set row [mk::select $view -count 1 parent $parent name $tail]
+       if { $row != "" } {
+         set v::cache($db,$parent,$tail) $row
+       } else { 
+         return -code error "could not read \"$path\": no such file or directory"
+       }
+      }
+    }
+    set cur $view!$row
+
+    set sb(type)    $type
+    set sb(view)    $view
+    set sb(ino)     $cur
+
+    if { [string equal $type "directory"] } {
+      set sb(atime) 0
+      set sb(ctime) 0
+      set sb(gid)   0
+      set sb(mode)  0777
+      set sb(mtime) 0
+      set sb(nlink) [expr { [mk::get $cur files] + 1 }]
+      set sb(size)  0
+      set sb(csize) 0
+      set sb(uid)   0
+    } else {
+      set mtime   [mk::get $cur date]
+      set sb(atime) $mtime
+      set sb(ctime) $mtime
+      set sb(gid)   0
+      set sb(mode)  0777
+      set sb(mtime) $mtime
+      set sb(nlink) 1
+      set sb(size)  [mk::get $cur size]
+      set sb(csize) [mk::get $cur -size contents]
+      set sb(uid)   0
+    }
+  }
+
+  proc do_close {fd mode cur} {
+    if {![regexp {[aw]} $mode]} {
+      error "mk4vfs::do_close called with bad mode: $mode"
+    }
+
+    mk::set $cur size -1 date [clock seconds]
+    flush $fd
+    if { [string match *z* $mode] } {
+      fconfigure $fd -translation binary
+      seek $fd 0
+      set data [read $fd]
+      set cdata [vfs::zip -mode compress $data]
+      set len [string length $data]
+      set clen [string length $cdata]
+      if { $clen < $len } {
+       mk::set $cur size $len contents $cdata
+      } else {
+       mk::set $cur size $len contents $data
+      }
+    } else {
+      mk::set $cur size [mk::get $cur -size contents]
+    }
+    # added 30-10-2000
+    set db [lindex [split $cur .] 0]
+    mk::file autocommit $db
+  }
+
+  proc mkdir {db path} {
+    set sp [::file split $path]
+    set parent 0
+    set view $db.dirs
+
+    set npath {}
+    foreach ele $sp {
+      set npath [file join $npath $ele]
+
+      if { ![catch {stat $db $npath sb}] } {
+       if { $sb(type) != "directory" } {
+         return -code error "can't create directory \"$npath\": file already exists"
+       }
+       set parent [mk::cursor position sb(ino)]
+       continue
+      }
+      #set parent [mk::cursor position sb(ino)]
+      set cur [mk::row append $view name $ele parent $parent]
+      set parent [mk::cursor position cur]
+    }
+  }
+
+  proc getdir {db path {pat *}} {
+    if {[catch { stat $db $path sb }] || $sb(type) != "directory" } {
+      return
+    }
+
+    # Match directories
+    set parent [mk::cursor position sb(ino)] 
+    foreach row [mk::select $sb(view) parent $parent -glob name $pat] {
+      set hits([mk::get $sb(view)!$row name]) 1
+    }
+    # Match files
+    set view $sb(view)!$parent.files
+    foreach row [mk::select $view -glob name $pat] {
+      set hits([mk::get $view!$row name]) 1
+    }
+    return [lsort [array names hits]]
+  }
+
+  proc mtime {db path time} {
+    stat $db $path sb
+    if { $sb(type) == "file" } {
+      mk::set $sb(ino) date $time
+    }
+    return $time
+  }
+
+  proc delete {db path {recursive 0}} {
+    #puts stderr "mk4delete db $db path $path recursive $recursive"
+    stat $db $path sb
+    if {$sb(type) == "file" } {
+      mk::row delete $sb(ino)
+      if {[regexp {(.*)!(\d+)} $sb(ino) - v r] && [info exists v::fcache($v)]} {
+       set v::fcache($v) [lreplace $v::fcache($v) $r $r]
+      }
+    } else {
+      # just mark dirs as deleted
+      set contents [getdir $db $path *]
+      if {$recursive} {
+       # We have to delete these manually, else
+       # they (or their cache) may conflict with
+       # something later
+       foreach f $contents {
+         delete $db [file join $path $f] $recursive
+       }
+      } else {
+       if {[llength $contents]} {
+         return -code error "Non-empty"
+       }
+      }
+      array unset v::cache "$db,[mk::get $sb(ino) parent],[file tail $path]"
+      
+      # flag with -99, because parent -1 is not reserved for the root dir
+      # deleted entries never get re-used, should be cleaned up one day
+      mk::set $sb(ino) parent -99 name ""
+      # get rid of file entries to release the space in the datafile
+      mk::view size $sb(ino).files 0
+    }
+    return ""
+  }
 }
 
index 2e4ae13f68c395511070b7f8f11799c0ebc03e31..ed9dabf1d360f666e2034bb6eefad5e3ad114900 100644 (file)
@@ -45,4 +45,4 @@ proc loadvfs {file} {
 package ifneeded vfs 1.0 [list loadvfs $file]
 unset file
 
-package ifneeded mk4vfs 1.0 [list source [file join $dir mk4vfs.tcl]]
+package ifneeded mk4vfs 1.5 [list source [file join $dir mk4vfs.tcl]]
index 43a98ca6036dfc89f5b316237cc125b9d14a737e..c7b671b95de49d247f8b4edfe508192f983faf92 100644 (file)
@@ -16,6 +16,4 @@ if {[info tclversion] == 8.4} {
 package ifneeded vfs 1.0 "load [list [file join $dir Vfs[info sharedlibextension]]] vfs
 source -rsrc vfs:tclIndex"
 
-package ifneeded scripdoc 0.3 [list source -rsrc scripdoc]
-package ifneeded mk4vfs 1.0 [list source -rsrc mk4vfs]
-package ifneeded vfslib 0.1 [list source -rsrc vfs]
+package ifneeded mk4vfs 1.5 [list source -rsrc mk4vfs]