Check-in [1adf504f9a]
Overview
Comment:More work towards a writable solution
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tcl-ops
Files: files | file ages | folders
SHA1:1adf504f9a4e6eb2cc3b4657d6bb9fe8b8ec9667
User & Date: rkeene on 2014-11-09 09:04:33
Other Links: manifest | tags
Context
2014-11-09
09:10
Removed spurious deletes and fixed permissions on version directory check-in: 7d728e1078 user: rkeene tags: tcl-ops
09:04
More work towards a writable solution check-in: 1adf504f9a user: rkeene tags: tcl-ops
08:01
Added a truncate action check-in: 8ea4ed266f user: rkeene tags: tcl-ops
Changes

Modified appfsd.c from [6a9a58fb18] to [070b2bd8e3].

   814    814   	return(write_ret);
   815    815   }
   816    816   
   817    817   static int appfs_fuse_mknod(const char *path, mode_t mode, dev_t device) {
   818    818   	char *real_path;
   819    819   	int mknod_ret;
   820    820   
          821  +	APPFS_DEBUG("Enter (path = %s, ...)", path);
          822  +
   821    823   	if ((mode & S_IFCHR) == S_IFCHR) {
   822    824   		return(-EPERM);
   823    825   	}
   824    826   
   825    827   	if ((mode & S_IFBLK) == S_IFBLK) {
   826    828   		return(-EPERM);
   827    829   	}
................................................................................
   842    844   	return(0);
   843    845   }
   844    846   
   845    847   static int appfs_fuse_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
   846    848   	int fd;
   847    849   	int chmod_ret;
   848    850   
          851  +	APPFS_DEBUG("Enter (path = %s, ...)", path);
          852  +
   849    853   	fd = appfs_fuse_open(path, fi);
   850    854   	if (fd < 0) {
   851    855   		return(fd);
   852    856   	}
   853    857   
   854    858   	chmod_ret = fchmod(fd, mode);
   855    859   	if (chmod_ret != 0) {
................................................................................
   861    865   	return(fd);
   862    866   }
   863    867   
   864    868   static int appfs_fuse_truncate(const char *path, off_t size) {
   865    869   	char *real_path;
   866    870   	int truncate_ret;
   867    871   
          872  +	APPFS_DEBUG("Enter (path = %s, ...)", path);
          873  +
   868    874   	real_path = appfs_localpath(path);
   869    875   	if (real_path == NULL) {
   870    876   		return(-EIO);
   871    877   	}
   872    878   
   873    879   	truncate_ret = truncate(real_path, size);
   874    880   
   875    881   	free(real_path);
   876    882   
   877    883   	if (truncate_ret != 0) {
   878    884   		return(errno * -1);
   879    885   	}
   880    886   
   881         -	return(truncate_ret);
          887  +	return(0);
          888  +}
          889  +
          890  +static int appfs_fuse_unlink_rmdir(const char *path) {
          891  +	Tcl_Interp *interp;
          892  +	int tcl_ret;
          893  +
          894  +	APPFS_DEBUG("Enter (path = %s, ...)", path);
          895  +
          896  +	interp = appfs_TclInterp();
          897  +	if (interp == NULL) {
          898  +		return(-EIO);
          899  +	}
          900  +
          901  +	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::unlinkpath", path);
          902  +	if (tcl_ret != TCL_OK) {
          903  +		APPFS_DEBUG("::appfs::unlinkpath(%s) failed.", path);
          904  +		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
          905  +
          906  +		return(-EIO);
          907  +	}
          908  +
          909  +	return(0);
          910  +}
          911  +
          912  +static int appfs_fuse_mkdir(const char *path, mode_t mode) {
          913  +	char *real_path;
          914  +	int mkdir_ret;
          915  +
          916  +	APPFS_DEBUG("Enter (path = %s, ...)", path);
          917  +
          918  +	real_path = appfs_prepare_to_create(path);
          919  +	if (real_path == NULL) {
          920  +		return(-EIO);
          921  +	}
          922  +
          923  +	mkdir_ret = mkdir(real_path, mode);
          924  +
          925  +	free(real_path);
          926  +
          927  +	if (mkdir_ret != 0) {
          928  +		if (errno != EEXIST) {
          929  +			return(errno * -1);
          930  +		}
          931  +	}
          932  +
          933  +	return(0);
   882    934   }
   883    935   
   884    936   /*
   885    937    * SQLite3 mode: Execute raw SQL and return success or failure
   886    938    */
   887    939   static int appfs_sqlite3(const char *sql) {
   888    940   	Tcl_Interp *interp;
................................................................................
   972   1024   	.open      = appfs_fuse_open,
   973   1025   	.release   = appfs_fuse_close,
   974   1026   	.read      = appfs_fuse_read,
   975   1027   	.write     = appfs_fuse_write,
   976   1028   	.mknod     = appfs_fuse_mknod,
   977   1029   	.create    = appfs_fuse_create,
   978   1030   	.truncate  = appfs_fuse_truncate,
         1031  +	.unlink    = appfs_fuse_unlink_rmdir,
         1032  +	.rmdir     = appfs_fuse_unlink_rmdir,
         1033  +	.mkdir     = appfs_fuse_mkdir,
   979   1034   };
   980   1035   
   981   1036   /*
   982   1037    * FUSE option parsing callback
   983   1038    */
   984   1039   static int appfs_fuse_opt_cb(void *data, const char *arg, int key, struct fuse_args *outargs) {
   985   1040   	static int seen_cachedir = 0;

Modified appfsd.tcl from [3cd77a5342] to [d0837729e0].

   457    457   
   458    458   				if {[info exists pathinfo(package)] && [info exists pathinfo(hostname)] && [info exists pathinfo(file)]} {
   459    459   					set dir [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   460    460   					foreach file [glob -nocomplain -tails -directory $dir -types {d f l} {{.,}*}] {
   461    461   						if {$file == "." || $file == ".."} {
   462    462   							continue
   463    463   						}
          464  +
          465  +						if {[string match "*.APPFS.WHITEOUT" $file]} {
          466  +							set remove [string range $file 0 end-15]
          467  +							set idx [lsearch -exact $retval $remove]
          468  +							if {$idx != -1} {
          469  +								set retval [lreplace $retval $idx $idx]
          470  +							}
          471  +							continue
          472  +						}
   464    473   
   465    474   						if {[lsearch -exact $retval $file] != -1} {
   466    475   							continue
   467    476   						}
   468    477   
   469    478   						lappend retval $file
   470    479   					}
................................................................................
   527    536   					if {[info exists pathinfo(package_sha1)] && $pathinfo(package_sha1) != ""} {
   528    537   						set retval(type) directory
   529    538   						set retval(childcount) 2;
   530    539   					}
   531    540   				}
   532    541   			}
   533    542   			"files" {
   534         -
   535    543   				set retval(packaged) 1
   536    544   
   537    545   				set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   538    546   
   539    547   				set retval(localpath) $localpath
   540    548   
   541         -				if {[file exists $localpath]} {
   542         -					catch {
   543         -						file lstat $localpath localpathinfo
   544         -						set retval(time) $localpathinfo(mtime)
   545         -
   546         -						switch -- $localpathinfo(type) {
   547         -							"directory" {
   548         -								set retval(type) "directory"
   549         -								set retval(childcount) 2
   550         -							}
   551         -							"file" {
   552         -								set retval(type) "file"
   553         -								set retval(size) $localpathinfo(size)
   554         -								if {[file executable $localpath]} {
   555         -									set retval(perms) "x"
   556         -								} else {
   557         -									set retval(perms) ""
          549  +				if {![file exists "${localpath}.APPFS.WHITEOUT"]} {
          550  +					if {[file exists $localpath]} {
          551  +						set retval(is_localfile) 1
          552  +						catch {
          553  +							file lstat $localpath localpathinfo
          554  +							set retval(time) $localpathinfo(mtime)
          555  +
          556  +							switch -- $localpathinfo(type) {
          557  +								"directory" {
          558  +									set retval(type) "directory"
          559  +									set retval(childcount) 2
          560  +								}
          561  +								"file" {
          562  +									set retval(type) "file"
          563  +									set retval(size) $localpathinfo(size)
          564  +									if {[file executable $localpath]} {
          565  +										set retval(perms) "x"
          566  +									} else {
          567  +										set retval(perms) ""
          568  +									}
          569  +								}
          570  +								"link" {
          571  +									set retval(type) "symlink"
          572  +									set retval(source) [file readlink $localpath]
   558    573   								}
   559    574   							}
   560         -							"link" {
   561         -								set retval(type) "symlink"
   562         -								set retval(source) [file readlink $localpath]
   563         -							}
   564         -						}
   565         -					} err
   566         -				} else {
   567         -					set work [split $pathinfo(file) "/"]
   568         -					set directory [join [lrange $work 0 end-1] "/"]
   569         -					set file [lindex $work end]
   570         -					::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 {}
   571         -					unset -nocomplain retval(*)
          575  +						} err
          576  +					} else {
          577  +						set retval(is_remotefile) 1
          578  +
          579  +						set work [split $pathinfo(file) "/"]
          580  +						set directory [join [lrange $work 0 end-1] "/"]
          581  +						set file [lindex $work end]
          582  +						::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 {}
          583  +						unset -nocomplain retval(*)
          584  +					}
   572    585   				}
   573    586   
   574    587   			}
   575    588   		}
   576    589   
   577    590   		if {![info exists retval(type)]} {
   578    591   			return -code error "No such file or directory"
................................................................................
   586    599   
   587    600   		if {$pathinfo(_type) != "files"} {
   588    601   			return -code error "invalid type"
   589    602   		}
   590    603   
   591    604   		set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   592    605   
   593         -		if {[file exists $localpath]} {
          606  +		if {$mode == "create"} {
          607  +			file delete -- "${localpath}.APPFS.WHITEOUT"
          608  +
   594    609   			return $localpath
   595    610   		}
   596    611   
   597         -		if {$mode == "create"} {
          612  +		if {[file exists $localpath]} {
   598    613   			return $localpath
   599    614   		}
   600    615   
   601    616   		set work [split $pathinfo(file) "/"]
   602    617   		set directory [join [lrange $work 0 end-1] "/"]
   603    618   		set file [lindex $work end]
   604    619   		::appfs::db eval {SELECT file_sha1, perms FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_name = $file AND file_directory = $directory;} pkgpathinfo {}
................................................................................
   665    680   		set dirname [file dirname $filename]
   666    681   
   667    682   		file mkdir $dirname
   668    683   
   669    684   		return $filename
   670    685   	}
   671    686   
   672         -	proc prepare_to_create {path} {
   673         -		if {[exists $path] != ""} {
   674         -			return -code error "File already exists"
   675         -		}
   676         -
   677         -		set filename [openpath $path "create"]
   678         -
   679         -		set dirname [file dirname $filename]
   680         -
   681         -		file mkdir $dirname
   682         -
   683         -		return $filename
   684         -	}
   685         -
   686    687   	proc localpath {path} {
   687    688   		array set pathinfo [_parsepath $path]
   688    689   
   689    690   		if {$pathinfo(_type) != "files"} {
   690    691   			return -code error "invalid type"
   691    692   		}
   692    693   
   693    694   		set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]
   694    695   
   695    696   		return $localpath
   696    697   	}
          698  +
          699  +	proc _delete_files_except_whiteout {path} {
          700  +		foreach file [glob -nocomplain -directory $path {{.,}*}] {
          701  +			if {[string match "*/.." $file] || [string match "*/." $file]} {
          702  +				continue
          703  +			}
          704  +
          705  +			if {[file isdirectory $file]} {
          706  +				_delete_files_except_whiteout $file
          707  +			}
          708  +
          709  +			if {[string match "*.APPFS.WHITEOUT" $file]} {
          710  +				continue
          711  +			}
          712  +
          713  +			catch {
          714  +				file delete -- $file
          715  +			}
          716  +		}
          717  +	}
          718  +
          719  +	proc unlinkpath {path} {
          720  +		array set pathattrs [exists $path]
          721  +
          722  +		if {![info exists pathattrs(packaged)]} {
          723  +			return -code error "invalid type"
          724  +		}
          725  +
          726  +		set localpath $pathattrs(localpath)
          727  +
          728  +		set whiteout 0
          729  +		set isdirectory 0
          730  +		if {[info exists pathattrs(is_localfile)]} {
          731  +			if {[file isdirectory $localpath]} {
          732  +				set isdirectory 1
          733  +				set whiteout 1
          734  +				_delete_files_except_whiteout $localpath
          735  +			} else {
          736  +				file delete -force -- $localpath
          737  +			}
          738  +		} elseif {[info exists pathattrs(is_remotefile)]} {
          739  +			if {$pathattrs(type) == "directory"} {
          740  +				set isdirectory 1
          741  +			}
          742  +
          743  +			set whiteout 1
          744  +		} else {
          745  +			return -code error "Unknown if file is remote or local !?"
          746  +		}
          747  +
          748  +		if {$isdirectory} {
          749  +			set children [getchildren $path]
          750  +			if {$children != [list]} {
          751  +				return -code error "Asked to delete non-empty directory"
          752  +			}
          753  +		}
          754  +
          755  +		if {$whiteout} {
          756  +			set whiteoutfile "${localpath}.APPFS.WHITEOUT"
          757  +			set whiteoutdir [file dirname $whiteoutfile]
          758  +			file mkdir $whiteoutdir
          759  +			close [open $whiteoutfile w]
          760  +		}
          761  +	}
   697    762   }