Diff

Differences From Artifact [251a7402cc]:

To Artifact [3ec5e46dc5]:


   343    343   	}
   344    344   
   345    345   	proc _localpath {package hostname file} {
   346    346   		set homedir [::appfsd::get_homedir]
   347    347   		set dir [file join $homedir .appfs "./${package}@${hostname}" "./${file}"]
   348    348   		return $dir
   349    349   	}
          350  +
          351  +	proc _whiteoutpath {package hostname file} {
          352  +		set homedir [::appfsd::get_homedir]
          353  +		set dir [file join $homedir .appfs "./${package}@${hostname}" ".APPFS.WHITEOUT" "./${file}.APPFS.WHITEOUT"]
          354  +		return $dir
          355  +	}
   350    356   
   351    357   	proc _parsepath {path} {
   352    358   		set path [string trim $path "/"]
   353    359   		set path [split $path "/"]
   354    360   		set pathlen [llength $path]
   355    361   
   356    362   		array set retval [list _children sites _type toplevel]
................................................................................
   454    460   					::appfs::getpkgmanifest $pathinfo(hostname) $pathinfo(package_sha1)
   455    461   				}
   456    462   
   457    463   				set retval [::appfs::db eval {SELECT DISTINCT file_name FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $pathinfo(file);}]
   458    464   
   459    465   				if {[info exists pathinfo(package)] && [info exists pathinfo(hostname)] && [info exists pathinfo(file)]} {
   460    466   					set dir [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
          467  +					set whiteoutdir [string range [_whiteoutpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)] 0 end-15]
          468  +
          469  +					foreach file [glob -nocomplain -tails -directory $whiteoutdir {{.,}*.APPFS.WHITEOUT}] {
          470  +						set remove [string range $file 0 end-15]
          471  +						set idx [lsearch -exact $retval $remove]
          472  +						if {$idx != -1} {
          473  +							set retval [lreplace $retval $idx $idx]
          474  +						}
          475  +					}
          476  +
   461    477   					foreach file [glob -nocomplain -tails -directory $dir -types {d f l} {{.,}*}] {
   462    478   						if {$file == "." || $file == ".."} {
   463    479   							continue
   464    480   						}
   465    481   
   466         -						if {[string match "*.APPFS.WHITEOUT" $file]} {
   467         -							set remove [string range $file 0 end-15]
   468         -							set idx [lsearch -exact $retval $remove]
   469         -							if {$idx != -1} {
   470         -								set retval [lreplace $retval $idx $idx]
   471         -							}
          482  +						if {$file == ".APPFS.WHITEOUT"} {
   472    483   							continue
   473    484   						}
   474    485   
   475    486   						if {[lsearch -exact $retval $file] != -1} {
   476    487   							continue
   477    488   						}
   478    489   
................................................................................
   540    551   					}
   541    552   				}
   542    553   			}
   543    554   			"files" {
   544    555   				set retval(packaged) 1
   545    556   
   546    557   				set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
          558  +				set whiteoutpath  [_whiteoutpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   547    559   
   548    560   				set retval(localpath) $localpath
   549         -
   550         -				if {![file exists "${localpath}.APPFS.WHITEOUT"]} {
   551         -					if {[file exists $localpath]} {
   552         -						set retval(is_localfile) 1
   553         -						catch {
   554         -							file lstat $localpath localpathinfo
   555         -							set retval(time) $localpathinfo(mtime)
   556         -
   557         -							switch -- $localpathinfo(type) {
   558         -								"directory" {
   559         -									set retval(type) "directory"
   560         -									set retval(childcount) 2
   561         -								}
   562         -								"file" {
   563         -									set retval(type) "file"
   564         -									set retval(size) $localpathinfo(size)
   565         -									if {[file executable $localpath]} {
   566         -										set retval(perms) "x"
   567         -									} else {
   568         -										set retval(perms) ""
   569         -									}
   570         -								}
   571         -								"link" {
   572         -									set retval(type) "symlink"
   573         -									set retval(source) [file readlink $localpath]
          561  +				set retval(whiteoutpath) $whiteoutpath
          562  +
          563  +				if {[file exists $localpath]} {
          564  +					set retval(is_localfile) 1
          565  +					catch {
          566  +						file lstat $localpath localpathinfo
          567  +						set retval(time) $localpathinfo(mtime)
          568  +
          569  +						switch -- $localpathinfo(type) {
          570  +							"directory" {
          571  +								set retval(type) "directory"
          572  +								set retval(childcount) 2
          573  +							}
          574  +							"file" {
          575  +								set retval(type) "file"
          576  +								set retval(size) $localpathinfo(size)
          577  +								if {[file executable $localpath]} {
          578  +									set retval(perms) "x"
          579  +								} else {
          580  +									set retval(perms) ""
   574    581   								}
   575    582   							}
   576         -						} err
   577         -					} else {
          583  +							"link" {
          584  +								set retval(type) "symlink"
          585  +								set retval(source) [file readlink $localpath]
          586  +							}
          587  +						}
          588  +					} err
          589  +				} else {
          590  +					if {![file exists $whiteoutpath]} {
   578    591   						set retval(is_remotefile) 1
   579    592   
   580    593   						set work [split $pathinfo(file) "/"]
   581    594   						set directory [join [lrange $work 0 end-1] "/"]
   582    595   						set file [lindex $work end]
          596  +
          597  +						if {$directory == "" && $file == ""} {
          598  +							array set retval [list type directory childcount 2]
          599  +						}
          600  +
   583    601   						::appfs::db eval {SELECT type, time, source, size, perms FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $directory AND file_name = $file;} retval {}
   584    602   						unset -nocomplain retval(*)
   585    603   					}
   586    604   				}
   587    605   
   588    606   			}
   589    607   		}
................................................................................
   601    619   		if {$pathinfo(_type) != "files"} {
   602    620   			return -code error "invalid type"
   603    621   		}
   604    622   
   605    623   		set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   606    624   
   607    625   		if {$mode == "create"} {
   608         -			file delete -- "${localpath}.APPFS.WHITEOUT"
   609         -
   610    626   			return $localpath
   611    627   		}
   612    628   
   613    629   		if {[file exists $localpath]} {
   614    630   			return $localpath
   615    631   		}
   616    632   
................................................................................
   650    666   			}
   651    667   
   652    668   			return $localpath
   653    669   		}
   654    670   
   655    671   		return $localcachefile
   656    672   	}
          673  +
          674  +	proc localpath {path} {
          675  +		array set pathinfo [_parsepath $path]
          676  +
          677  +		if {$pathinfo(_type) != "files"} {
          678  +			return -code error "invalid type"
          679  +		}
          680  +
          681  +		set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
          682  +
          683  +		return $localpath
          684  +	}
   657    685   
   658    686   	proc exists {path} {
   659    687   		catch {
   660    688   			set info [getattr $path]
   661    689   		} err
   662    690   
   663    691   		if {![info exists info]} {
................................................................................
   667    695   				return -code error $err
   668    696   			}
   669    697   		}
   670    698   
   671    699   		return $info
   672    700   	}
   673    701   
   674         -	proc prepare_to_create {path} {
   675         -		if {[exists $path] != ""} {
   676         -			return -code error "File already exists"
          702  +	proc prepare_to_create {path {must_not_exist 1}} {
          703  +		if {$must_not_exist} {
          704  +			if {[exists $path] != ""} {
          705  +				return -code error "File already exists"
          706  +			}
   677    707   		}
   678    708   
   679         -		set filename [openpath $path "create"]
          709  +		set filename [localpath $path]
   680    710   
   681    711   		set dirname [file dirname $filename]
   682    712   
   683    713   		file mkdir $dirname
   684    714   
   685    715   		return $filename
   686    716   	}
   687    717   
   688         -	proc localpath {path} {
   689         -		array set pathinfo [_parsepath $path]
   690         -
   691         -		if {$pathinfo(_type) != "files"} {
   692         -			return -code error "invalid type"
   693         -		}
   694         -
   695         -		set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   696         -
   697         -		return $localpath
   698         -	}
   699         -
   700    718   	proc unlinkpath {path} {
   701    719   		array set pathattrs [exists $path]
   702    720   
   703    721   		if {![info exists pathattrs(packaged)]} {
   704    722   			return -code error "invalid type"
   705    723   		}
   706    724   
   707    725   		set localpath $pathattrs(localpath)
   708    726   
   709    727   		set whiteout 0
   710    728   		set isdirectory 0
   711    729   		if {[info exists pathattrs(is_localfile)]} {
   712    730   			if {[file isdirectory $localpath]} {
   713         -				set isdirectory 1
   714    731   				set whiteout 1
   715         -			} else {
   716         -				file delete -force -- $localpath
          732  +
          733  +				set isdirectory 1
          734  +				set children [getchildren $path]
   717    735   			}
          736  +			file delete -force -- $localpath
   718    737   		} elseif {[info exists pathattrs(is_remotefile)]} {
   719    738   			if {$pathattrs(type) == "directory"} {
   720    739   				set isdirectory 1
          740  +				set children [getchildren $path]
   721    741   			}
   722    742   
   723    743   			set whiteout 1
   724    744   		} else {
   725    745   			return -code error "Unknown if file is remote or local !?"
   726    746   		}
   727    747   
   728    748   		if {$isdirectory} {
   729         -			set children [getchildren $path]
   730    749   			if {$children != [list]} {
   731    750   				return -code error "Asked to delete non-empty directory"
   732    751   			}
   733    752   		}
   734    753   
   735    754   		if {$whiteout} {
   736         -			set whiteoutfile "${localpath}.APPFS.WHITEOUT"
          755  +			set whiteoutfile $pathattrs(whiteoutpath)
   737    756   			set whiteoutdir [file dirname $whiteoutfile]
   738    757   			file mkdir $whiteoutdir
   739    758   			close [open $whiteoutfile w]
   740    759   		}
   741    760   	}
   742    761   }