Check-in [2160c4189b]
Overview
Comment:Nearly completely working write support
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tcl-ops
Files: files | file ages | folders
SHA1:2160c4189bf2872e7143399ced1c46b08cadf08d
User & Date: rkeene on 2014-11-10 03:11:18
Other Links: manifest | tags
Context
2014-11-10
03:34
Updated to cache last home directory looked up and to setfsuid()/setfsgid() before accessing the filesystem so that we may be the right user check-in: 63e41c262c user: rkeene tags: tcl-ops
03:11
Nearly completely working write support check-in: 2160c4189b user: rkeene tags: tcl-ops
2014-11-09
09:10
Removed spurious deletes and fixed permissions on version directory check-in: 7d728e1078 user: rkeene tags: tcl-ops
Changes

Modified appfsd.c from [070b2bd8e3] to [227a45ec34].

   627    627   	memset(stbuf, 0, sizeof(struct stat));
   628    628   
   629    629   	stbuf->st_mtime = pathinfo.time;
   630    630   	stbuf->st_ctime = pathinfo.time;
   631    631   	stbuf->st_atime = pathinfo.time;
   632    632   	stbuf->st_ino   = pathinfo.inode;
   633    633   	stbuf->st_mode  = 0;
          634  +	stbuf->st_uid   = appfs_get_fsuid();
   634    635   
   635    636   	switch (pathinfo.type) {
   636    637   		case APPFS_PATHTYPE_DIRECTORY:
   637    638   			stbuf->st_mode = S_IFDIR | 0555;
   638    639   			stbuf->st_nlink = 2 + pathinfo.typeinfo.dir.childcount;
   639    640   			break;
   640    641   		case APPFS_PATHTYPE_FILE:
................................................................................
   841    842   		return(errno * -1);
   842    843   	}
   843    844   
   844    845   	return(0);
   845    846   }
   846    847   
   847    848   static int appfs_fuse_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
          849  +	char *real_path;
   848    850   	int fd;
   849         -	int chmod_ret;
   850    851   
   851    852   	APPFS_DEBUG("Enter (path = %s, ...)", path);
   852    853   
   853         -	fd = appfs_fuse_open(path, fi);
   854         -	if (fd < 0) {
   855         -		return(fd);
          854  +	if ((mode & S_IFCHR) == S_IFCHR) {
          855  +		return(-EPERM);
   856    856   	}
   857    857   
   858         -	chmod_ret = fchmod(fd, mode);
   859         -	if (chmod_ret != 0) {
   860         -		close(fd);
          858  +	if ((mode & S_IFBLK) == S_IFBLK) {
          859  +		return(-EPERM);
          860  +	}
   861    861   
          862  +	real_path = appfs_prepare_to_create(path);
          863  +	if (real_path == NULL) {
   862    864   		return(-EIO);
   863    865   	}
   864    866   
   865         -	return(fd);
          867  +	fd = creat(real_path, mode);
          868  +
          869  +	free(real_path);
          870  +
          871  +	if (fd < 0) {
          872  +		return(errno * -1);
          873  +	}
          874  +
          875  +	fi->fh = fd;
          876  +
          877  +	return(0);
   866    878   }
   867    879   
   868    880   static int appfs_fuse_truncate(const char *path, off_t size) {
   869    881   	char *real_path;
   870    882   	int truncate_ret;
   871    883   
   872    884   	APPFS_DEBUG("Enter (path = %s, ...)", path);
................................................................................
   928    940   		if (errno != EEXIST) {
   929    941   			return(errno * -1);
   930    942   		}
   931    943   	}
   932    944   
   933    945   	return(0);
   934    946   }
          947  +
          948  +static int appfs_fuse_chmod(const char *path, mode_t mode) {
          949  +	Tcl_Interp *interp;
          950  +	const char *real_path;
          951  +	int tcl_ret, chmod_ret;
          952  +
          953  +	APPFS_DEBUG("Enter (path = %s, ...)", path);
          954  +
          955  +	interp = appfs_TclInterp();
          956  +	if (interp == NULL) {
          957  +		return(-EIO);
          958  +	}
          959  +
          960  +	tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::openpath", path, "write");
          961  +	if (tcl_ret != TCL_OK) {
          962  +		APPFS_DEBUG("::appfs::openpath(%s, %s) failed.", path, "write");
          963  +		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
          964  +
          965  +		return(-EIO);
          966  +	}
          967  +
          968  +	real_path = Tcl_GetStringResult(interp);
          969  +	if (real_path == NULL) {
          970  +		return(-EIO);
          971  +	}
          972  +
          973  +	chmod_ret = chmod(real_path, mode);
          974  +
          975  +	return(chmod_ret);
          976  +}
   935    977   
   936    978   /*
   937    979    * SQLite3 mode: Execute raw SQL and return success or failure
   938    980    */
   939    981   static int appfs_sqlite3(const char *sql) {
   940    982   	Tcl_Interp *interp;
   941    983   	const char *sql_ret;
................................................................................
  1027   1069   	.write     = appfs_fuse_write,
  1028   1070   	.mknod     = appfs_fuse_mknod,
  1029   1071   	.create    = appfs_fuse_create,
  1030   1072   	.truncate  = appfs_fuse_truncate,
  1031   1073   	.unlink    = appfs_fuse_unlink_rmdir,
  1032   1074   	.rmdir     = appfs_fuse_unlink_rmdir,
  1033   1075   	.mkdir     = appfs_fuse_mkdir,
         1076  +	.chmod     = appfs_fuse_chmod,
  1034   1077   };
  1035   1078   
  1036   1079   /*
  1037   1080    * FUSE option parsing callback
  1038   1081    */
  1039   1082   static int appfs_fuse_opt_cb(void *data, const char *arg, int key, struct fuse_args *outargs) {
  1040   1083   	static int seen_cachedir = 0;

Modified appfsd.tcl from [251a7402cc] to [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   }