Check-in [ee13ee5aa4]
Overview
Comment:Added basic "getchildren" implementation in Tcl
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tcl-ops
Files: files | file ages | folders
SHA1:ee13ee5aa491c95977832ce005e40ce61e4b128c
User & Date: rkeene on 2014-11-07 08:48:19
Other Links: manifest | tags
Context
2014-11-07
11:36
Add "getattr" implementation check-in: d64c2e9bf7 user: rkeene tags: tcl-ops
08:48
Added basic "getchildren" implementation in Tcl check-in: ee13ee5aa4 user: rkeene tags: tcl-ops
07:20
Converted global variables to not be part of a struct check-in: f277407cbc user: rkeene tags: tcl-ops
Changes

Modified appfsd.c from [a9240a597b] to [16b07e2510].

   253    253   	if (retval != TCL_OK) {
   254    254   		APPFS_DEBUG("Tcl command failed, ::errorInfo contains: %s\n", Tcl_GetVar(interp, "::errorInfo", 0));
   255    255   	}
   256    256   
   257    257   	return(retval);
   258    258   }
   259    259   
   260         -/*
   261         - * AppFS: Request that a host's package index be updated locally
   262         - */
   263         -static void appfs_update_index(const char *hostname) {
   264         -	Tcl_Interp *interp;
   265         -	int tcl_ret;
   266         -
   267         -	APPFS_DEBUG("Enter: hostname = %s", hostname);
   268         -
   269         -	interp = appfs_TclInterp();
   270         -	if (interp == NULL) {
   271         -		return;
   272         -	}
   273         -
   274         -	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getindex", hostname);
   275         -	if (tcl_ret != TCL_OK) {
   276         -		APPFS_DEBUG("Call to ::appfs::getindex failed: %s", Tcl_GetStringResult(interp));
   277         -
   278         -		return;
   279         -	}
   280         -
   281         -	return;
   282         -}
   283         -
   284         -/*
   285         - * AppFS: Get a SHA1 from a host
   286         - *         Returns a local file name, or NULL if it cannot be fetched
   287         - */
   288         -static const char *appfs_getfile(const char *hostname, const char *sha1) {
   289         -	Tcl_Interp *interp;
   290         -	char *retval;
   291         -	int tcl_ret;
   292         -
   293         -	interp = appfs_TclInterp();
   294         -	if (interp == NULL) {
   295         -		return(NULL);
   296         -	}
   297         -
   298         -	tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::download", hostname, sha1);
   299         -	if (tcl_ret != TCL_OK) {
   300         -		APPFS_DEBUG("Call to ::appfs::download failed: %s", Tcl_GetStringResult(interp));
   301         -
   302         -		return(NULL);
   303         -	}
   304         -
   305         -	retval = strdup(Tcl_GetStringResult(interp));
   306         -
   307         -	return(retval);
   308         -}
   309         -
   310         -/*
   311         - * AppFS: Update the manifest for a specific package (by the package SHA1) on
   312         - * a given host
   313         - */
   314         -static void appfs_update_manifest(const char *hostname, const char *sha1) {
   315         -	Tcl_Interp *interp;
   316         -	int tcl_ret;
   317         -
   318         -	interp = appfs_TclInterp();
   319         -	if (interp == NULL) {
   320         -		return;
   321         -	}
   322         -
   323         -	tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::getpkgmanifest", hostname, sha1);
   324         -	if (tcl_ret != TCL_OK) {
   325         -		APPFS_DEBUG("Call to ::appfs::getpkgmanifest failed: %s", Tcl_GetStringResult(interp));
   326         -
   327         -		return;
   328         -	}
   329         -
   330         -	return;
   331         -}
   332         -
   333    260   /*
   334    261    * Determine the UID for the user making the current FUSE filesystem request.
   335    262    * This will be used to lookup the user's home directory so we can search for
   336    263    * locally modified files.
   337    264    */
   338    265   static uid_t appfs_get_fsuid(void) {
   339    266   	struct fuse_context *ctx;
................................................................................
   481    408   
   482    409   static int appfs_fuse_getattr(const char *path, struct stat *stbuf) {
   483    410   	struct appfs_pathinfo pathinfo;
   484    411   	int res = 0;
   485    412   
   486    413   	APPFS_DEBUG("Enter (path = %s, ...)", path);
   487    414   
   488         -	pathinfo.type = APPFS_PATHTYPE_INVALID;
   489         -
   490         -	res = appfs_get_path_info(path, &pathinfo, NULL);
   491         -	if (res != 0) {
   492         -		return(res);
   493         -	}
          415  +	pathinfo.type = APPFS_PATHTYPE_DIRECTORY;
          416  +	pathinfo.typeinfo.dir.childcount = 0;
   494    417   
   495    418   	memset(stbuf, 0, sizeof(struct stat));
   496    419   
   497    420   	stbuf->st_mtime = pathinfo.time;
   498    421   	stbuf->st_ctime = pathinfo.time;
   499    422   	stbuf->st_atime = pathinfo.time;
   500    423   	stbuf->st_ino   = pathinfo.inode;
................................................................................
   532    455   		}
   533    456   	}
   534    457   
   535    458   	return res;
   536    459   }
   537    460   
   538    461   static int appfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
   539         -	struct appfs_pathinfo pathinfo;
   540         -	struct appfs_children *children, *child;
          462  +	Tcl_Interp *interp;
          463  +	Tcl_Obj **children;
          464  +	int children_count, idx;
          465  +	int tcl_ret;
   541    466   	int retval;
   542    467   
   543    468   	APPFS_DEBUG("Enter (path = %s, ...)", path);
   544    469   
   545         -	retval = appfs_get_path_info(path, &pathinfo, &children);
   546         -	if (retval != 0) {
   547         -		return(retval);
          470  +	interp = appfs_TclInterp();
          471  +	if (interp == NULL) {
          472  +		return(0);
   548    473   	}
   549    474   
   550    475   	filler(buf, ".", NULL, 0);
   551    476   	filler(buf, "..", NULL, 0);
   552    477   
   553         -	for (child = children; child; child = child->_next) {
   554         -		filler(buf, child->name, NULL, 0);
          478  +
          479  +	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getchildren", path);
          480  +	if (tcl_ret != TCL_OK) {
          481  +		APPFS_DEBUG("::appfs::getchildren(%s) failed.", path);
          482  +		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
          483  +		
          484  +		return(0);
   555    485   	}
   556    486   
   557         -//	appfs_free_list_children(children);
          487  +	tcl_ret = Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp), &children_count, &children);
          488  +	if (tcl_ret != TCL_OK) {
          489  +		APPFS_DEBUG("Parsing list of children on path %s failed.", path);
          490  +		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
          491  +		
          492  +		return(0);
          493  +	}
          494  +
          495  +	for (idx = 0; idx < children_count; idx++) {
          496  +		filler(buf, Tcl_GetString(children[idx]), NULL, 0);
          497  +	}
   558    498   
   559    499   	return(0);
   560    500   }
   561    501   
   562    502   static int appfs_fuse_open(const char *path, struct fuse_file_info *fi) {
   563    503   	struct appfs_pathinfo pathinfo;
   564    504   	const char *real_path;

Modified appfsd.tcl from [e0ad1bdba0] to [88b17c4a86].

     4      4   package require sqlite3
     5      5   package require sha1
     6      6   
     7      7   namespace eval ::appfs {
     8      8   	variable cachedir "/tmp/appfs-cache"
     9      9   	variable ttl 3600
    10     10   	variable nttl 60
           11  +
           12  +	# User-replacable function to convert a hostname/hash/method to an URL
           13  +	proc _construct_url {hostname hash method} {
           14  +		return "http://$hostname/appfs/$method/$hash"
           15  +	}
    11     16   
    12     17   	proc _hash_sep {hash {seps 4}} {
    13     18   		for {set idx 0} {$idx < $seps} {incr idx} {
    14     19   			append retval "[string range $hash [expr {$idx * 2}] [expr {($idx * 2) + 1}]]/"
    15     20   		}
    16     21   		append retval "[string range $hash [expr {$idx * 2}] end]"
    17     22   
................................................................................
   123    128   
   124    129   		# Force [parray] to be loaded
   125    130   		catch {
   126    131   			parray does_not_exist
   127    132   		}
   128    133   
   129    134   		set ::appfs::init_called 1
          135  +
          136  +		# Load configuration file
          137  +		set config_file [file join $::appfs::cachedir config]
          138  +		if {[file exists $config_file]} {
          139  +			source $config_file
          140  +		}
   130    141   
   131    142   		if {![info exists ::appfs::db]} {
   132    143   			file mkdir $::appfs::cachedir
   133    144   
   134    145   			sqlite3 ::appfs::db [file join $::appfs::cachedir cache.db]
   135    146   		}
   136    147   
................................................................................
   142    153   		# Create indexes
   143    154   		db eval {CREATE INDEX IF NOT EXISTS sites_index ON sites (hostname);}
   144    155   		db eval {CREATE INDEX IF NOT EXISTS packages_index ON packages (hostname, package, version, os, cpuArch);}
   145    156   		db eval {CREATE INDEX IF NOT EXISTS files_index ON files (package_sha1, file_name, file_directory);}
   146    157   	}
   147    158   
   148    159   	proc download {hostname hash {method sha1}} {
   149         -		set url "http://$hostname/appfs/$method/$hash"
          160  +		set url [_construct_url $hostname $hash $method]
   150    161   		set file [_cachefile $url $hash]
   151    162   
   152    163   		if {![file exists $file]} {
   153    164   			return -code error "Unable to fetch (file does not exist: $file)"
   154    165   		}
   155    166   
   156    167   		return $file
................................................................................
   324    335   				db eval {INSERT INTO files (package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory) VALUES ($package_sha1, $fileInfo(type), $fileInfo(time), $fileInfo(source), $fileInfo(size), $fileInfo(perms), $fileInfo(sha1), $fileInfo(name), $fileInfo(directory) );}
   325    336   				db eval {UPDATE packages SET haveManifest = 1 WHERE sha1 = $package_sha1;}
   326    337   			}
   327    338   		}
   328    339   
   329    340   		return COMPLETE
   330    341   	}
          342  +
          343  +	proc _parsepath {path} {
          344  +		set path [string trim $path "/"]
          345  +		set path [split $path "/"]
          346  +		set pathlen [llength $path]
          347  +
          348  +		array set retval [list _children sites]
          349  +
          350  +		if {$pathlen > 0} {
          351  +			set retval(hostname) [lindex $path 0]
          352  +			set retval(_children) packages
          353  +
          354  +			if {$pathlen > 1} {
          355  +				set package [lindex $path 1]
          356  +				if {[string length $package] == "40" && [regexp {^[a-fA-F0-9]*$} $package]} {
          357  +					set retval(package_sha1) $package
          358  +					set retval(_children) files
          359  +
          360  +					if {$pathlen > 2} {
          361  +						set retval(file) [join [lrange $path 2 end] "/"]
          362  +					} else {
          363  +						set retval(file) ""
          364  +					}
          365  +
          366  +					return [array get retval]
          367  +				} else {
          368  +					set retval(package) $package
          369  +					set retval(_children) os-cpu
          370  +				}
          371  +
          372  +				if {$pathlen > 2} {
          373  +					set os_cpu [lindex $path 2]
          374  +					set os_cpu [split $os_cpu "-"]
          375  +
          376  +					set retval(os) [lindex $os_cpu 0]
          377  +					set retval(cpu) [lindex $os_cpu 1]
          378  +					set retval(_children) versions
          379  +
          380  +					if {$pathlen > 3} {
          381  +						set retval(version) [lindex $path 3]
          382  +						set retval(_children) files
          383  +
          384  +						set retval(package_sha1) [::appfs::db onecolumn {SELECT sha1 FROM packages WHERE hostname = $retval(hostname) AND os = $retval(os) AND cpuArch = $retval(cpu) AND version = $retval(version);}]
          385  +						if {$retval(package_sha1) == ""} {
          386  +							return [list]
          387  +						}
          388  +
          389  +						if {$pathlen > 4} {
          390  +							set retval(file) [join [lrange $path 4 end] "/"]
          391  +						} else {
          392  +							set retval(file) ""
          393  +						}
          394  +					}
          395  +				}
          396  +			}
          397  +		}
          398  +
          399  +		return [array get retval]
          400  +	}
          401  +
          402  +	proc getchildren {dir} {
          403  +		array set pathinfo [_parsepath $dir]
          404  +
          405  +		switch -- $pathinfo(_children) {
          406  +			"sites" {
          407  +				return [::appfs::db eval {SELECT DISTINCT hostname FROM packages;}]
          408  +			}
          409  +			"packages" {
          410  +				catch {
          411  +					::appfs::getindex $pathinfo(hostname)
          412  +				}
          413  +
          414  +				return [::appfs::db eval {SELECT DISTINCT package FROM packages WHERE hostname = $pathinfo(hostname);}]
          415  +			}
          416  +			"os-cpu" {
          417  +				return [::appfs::db eval {SELECT DISTINCT os || "-" || cpuArch FROM packages WHERE hostname = $pathinfo(hostname) AND package = $pathinfo(package);}]
          418  +			}
          419  +			"versions" {
          420  +				return [::appfs::db eval {
          421  +					SELECT DISTINCT version FROM packages WHERE hostname = $pathinfo(hostname) AND package = $pathinfo(package) AND os = $pathinfo(os) AND cpuArch = $pathinfo(cpu);
          422  +				}]
          423  +			}
          424  +			"files" {
          425  +				catch {
          426  +					::appfs::getpkgmanifest $pathinfo(hostname) $pathinfo(package_sha1)
          427  +				}
          428  +
          429  +				return [::appfs::db eval {SELECT DISTINCT file_name FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $pathinfo(file);}]
          430  +			}
          431  +		}
          432  +
          433  +		return -code error "Invalid or unacceptable path: $dir"
          434  +	}
          435  +
          436  +	proc getattr {path} {
          437  +	}
          438  +
          439  +	proc openpath {path mode} {
          440  +	}
   331    441   }