Check-in [89eabdaec1]
Overview
Comment:Updated to include attribute caching since we now disable all FUSE attribute caching
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:89eabdaec1f1875e07aae2ae900bb78df0cd52e2
User & Date: rkeene on 2014-11-10 20:09:19
Other Links: manifest | tags
Context
2014-11-11
05:11
Updated allow future versions to deal with manifests that are not linked from the index file check-in: 34f1255a38 user: rkeene tags: trunk
2014-11-10
20:09
Updated to include attribute caching since we now disable all FUSE attribute caching check-in: 89eabdaec1 user: rkeene tags: trunk
19:19
Updated to correctly deal with the "latest" symlink check-in: a706ef58b8 user: rkeene tags: trunk
Changes

Modified appfsd.c from [a0dcafd0c9] to [5e5056a24c].

    42     42    * Global variables, needed for all threads but only initialized before any
    43     43    * FUSE threads are created
    44     44    */
    45     45   const char *appfs_cachedir;
    46     46   time_t appfs_boottime;
    47     47   int appfs_fuse_started = 0;
    48     48   
           49  +/*
           50  + * Global variables for AppFS caching
           51  + */
           52  +pthread_mutex_t appfs_path_info_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
           53  +int appfs_path_info_cache_size = 8209;
           54  +struct appfs_pathinfo *appfs_path_info_cache = NULL;
           55  +
    49     56   /*
    50     57    * AppFS Path Type:  Describes the type of path a given file is
    51     58    */
    52     59   typedef enum {
    53     60   	APPFS_PATHTYPE_INVALID,
           61  +	APPFS_PATHTYPE_DOES_NOT_EXIST,
    54     62   	APPFS_PATHTYPE_FILE,
    55     63   	APPFS_PATHTYPE_DIRECTORY,
    56     64   	APPFS_PATHTYPE_SYMLINK,
    57     65   	APPFS_PATHTYPE_SOCKET,
    58     66   	APPFS_PATHTYPE_FIFO,
    59     67   } appfs_pathtype_t;
    60     68   
................................................................................
    78     86   			off_t size;
    79     87   		} file;
    80     88   		struct {
    81     89   			off_t size;
    82     90   			char source[256];
    83     91   		} symlink;
    84     92   	} typeinfo;
           93  +
           94  +	/* Attributes used only for caching entries */
           95  +	char *_cache_path;
           96  +	uid_t _cache_uid;
    85     97   };
    86     98   
    87     99   /*
    88    100    * Create a new Tcl interpreter and completely initialize it
    89    101    */
    90    102   static Tcl_Interp *appfs_create_TclInterp(char **error_string) {
    91    103   	Tcl_Interp *interp;
................................................................................
   403    415   	}
   404    416   
   405    417   	retval = strdup(result->pw_dir);
   406    418   
   407    419   	return(retval);
   408    420   }
   409    421   
   410         -/*
   411         - * Tcl interface to get the home directory for the user making the "current"
   412         - * FUSE I/O request
   413         - */
   414         -static int tcl_appfs_get_homedir(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
   415         -	char *homedir;
   416         -	Tcl_Obj *homedir_obj;
   417         -	uid_t fsuid;
   418         -	static __thread Tcl_Obj *last_homedir_obj = NULL;
   419         -	static __thread uid_t last_fsuid = -1;
   420         -
   421         -        if (objc != 1) {
   422         -                Tcl_WrongNumArgs(interp, 1, objv, NULL);
   423         -                return(TCL_ERROR);
   424         -        }
   425         -
   426         -	fsuid = appfs_get_fsuid();
   427         -
   428         -	if (fsuid == last_fsuid && last_homedir_obj != NULL) {
   429         -		homedir_obj = last_homedir_obj;
   430         -	} else {
   431         -		homedir = appfs_get_homedir(appfs_get_fsuid());
   432         -
   433         -		if (homedir == NULL) {
   434         -			return(TCL_ERROR);
   435         -		}
   436         -
   437         -		homedir_obj = Tcl_NewStringObj(homedir, -1);
   438         -
   439         -		free(homedir);
   440         -
   441         -		if (last_homedir_obj != NULL) {
   442         -			Tcl_DecrRefCount(last_homedir_obj);
   443         -		}
   444         -
   445         -		last_homedir_obj = homedir_obj;
   446         -		last_fsuid = fsuid;
   447         -
   448         -		Tcl_IncrRefCount(last_homedir_obj);
   449         -	}
   450         -
   451         -       	Tcl_SetObjResult(interp, homedir_obj);
   452         -
   453         -        return(TCL_OK);
   454         -}
   455         -
   456         -static int tcl_appfs_simulate_user_fs_enter(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
   457         -	appfs_simulate_user_fs_enter();
   458         -
   459         -	return(TCL_OK);
   460         -}
   461         -
   462         -static int tcl_appfs_simulate_user_fs_leave(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
   463         -	appfs_simulate_user_fs_leave();
   464         -
   465         -	return(TCL_OK);
   466         -}
   467         -
   468         -static int tcl_appfs_get_fsuid(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
   469         -	uid_t fsuid;
   470         -
   471         -	fsuid = appfs_get_fsuid();
   472         -
   473         -       	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(fsuid));
   474         -
   475         -	return(TCL_OK);
   476         -}
   477         -
   478         -static int tcl_appfs_get_fsgid(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
   479         -	gid_t fsgid;
   480         -
   481         -	fsgid = appfs_get_fsgid();
   482         -
   483         -       	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(fsgid));
   484         -
   485         -	return(TCL_OK);
   486         -}
   487         -
   488    422   /*
   489    423    * Generate an inode for a given path.  The inode should be computed in such
   490    424    * a way that it is unlikely to be duplicated and remains the same for a given
   491    425    * file
   492    426    */
   493    427   static long long appfs_get_path_inode(const char *path) {
   494    428   	long long retval;
................................................................................
   503    437   	}
   504    438   
   505    439   	retval += 10;
   506    440   	retval %= 4294967296ULL;
   507    441   
   508    442   	return(retval);
   509    443   }
          444  +
          445  +/*
          446  + * Cache Get Path Info lookups for speed
          447  + */
          448  +static int appfs_get_path_info_cache_get(const char *path, uid_t uid, struct appfs_pathinfo *pathinfo) {
          449  +	unsigned int hash_idx;
          450  +	int pthread_ret;
          451  +	int retval;
          452  +
          453  +	retval = 1;
          454  +
          455  +	pthread_ret = pthread_mutex_lock(&appfs_path_info_cache_mutex);
          456  +	if (pthread_ret != 0) {
          457  +		APPFS_DEBUG("Unable to lock path_info cache mutex !");
          458  +
          459  +		return(-1);
          460  +	}
          461  +
          462  +	if (appfs_path_info_cache != NULL) {
          463  +		hash_idx = (appfs_get_path_inode(path) + uid) % appfs_path_info_cache_size;
          464  +
          465  +		if (appfs_path_info_cache[hash_idx]._cache_path != NULL) {
          466  +			if (strcmp(appfs_path_info_cache[hash_idx]._cache_path, path) == 0 && appfs_path_info_cache[hash_idx]._cache_uid == uid) {
          467  +				retval = 0;
          468  +
          469  +				memcpy(pathinfo, &appfs_path_info_cache[hash_idx], sizeof(*pathinfo));
          470  +				pathinfo->_cache_path = NULL;
          471  +			}
          472  +		}
          473  +	}
          474  +
          475  +	pthread_ret = pthread_mutex_unlock(&appfs_path_info_cache_mutex);
          476  +	if (pthread_ret != 0) {
          477  +		APPFS_DEBUG("Unable to unlock path_info cache mutex !");
          478  +
          479  +		return(-1);
          480  +	}
          481  +
          482  +	if (retval == 0) {
          483  +		APPFS_DEBUG("Cache hit on %s", path);
          484  +	} else {
          485  +		APPFS_DEBUG("Cache miss on %s", path);
          486  +	}
          487  +
          488  +	return(retval);
          489  +}
          490  +
          491  +static void appfs_get_path_info_cache_add(const char *path, uid_t uid, struct appfs_pathinfo *pathinfo) {
          492  +	unsigned int hash_idx;
          493  +	int pthread_ret;
          494  +
          495  +	pthread_ret = pthread_mutex_lock(&appfs_path_info_cache_mutex);
          496  +	if (pthread_ret != 0) {
          497  +		APPFS_DEBUG("Unable to lock path_info cache mutex !");
          498  +
          499  +		return;
          500  +	}
          501  +
          502  +	if (appfs_path_info_cache == NULL) {
          503  +		appfs_path_info_cache = calloc(appfs_path_info_cache_size, sizeof(*appfs_path_info_cache));
          504  +	}
          505  +
          506  +	hash_idx = (appfs_get_path_inode(path) + uid) % appfs_path_info_cache_size;
          507  +
          508  +	if (appfs_path_info_cache[hash_idx]._cache_path != NULL) {
          509  +		free(appfs_path_info_cache[hash_idx]._cache_path);
          510  +	}
          511  +
          512  +	memcpy(&appfs_path_info_cache[hash_idx], pathinfo, sizeof(*pathinfo));
          513  +
          514  +	appfs_path_info_cache[hash_idx]._cache_path = strdup(path);
          515  +	appfs_path_info_cache[hash_idx]._cache_uid  = uid;
          516  +
          517  +	pthread_ret = pthread_mutex_unlock(&appfs_path_info_cache_mutex);
          518  +	if (pthread_ret != 0) {
          519  +		APPFS_DEBUG("Unable to unlock path_info cache mutex !");
          520  +
          521  +		return;
          522  +	}
          523  +	return;
          524  +}
          525  +
          526  +static void appfs_get_path_info_cache_rm(const char *path, uid_t uid) {
          527  +	unsigned int hash_idx;
          528  +	int pthread_ret;
          529  +
          530  +	pthread_ret = pthread_mutex_lock(&appfs_path_info_cache_mutex);
          531  +	if (pthread_ret != 0) {
          532  +		APPFS_DEBUG("Unable to lock path_info cache mutex !");
          533  +
          534  +		return;
          535  +	}
          536  +
          537  +	if (appfs_path_info_cache != NULL) {
          538  +		hash_idx = (appfs_get_path_inode(path) + uid) % appfs_path_info_cache_size;
          539  +
          540  +		if (appfs_path_info_cache[hash_idx]._cache_path != NULL) {
          541  +			free(appfs_path_info_cache[hash_idx]._cache_path);
          542  +
          543  +			appfs_path_info_cache[hash_idx]._cache_path = NULL;
          544  +		}
          545  +	}
          546  +
          547  +	pthread_ret = pthread_mutex_unlock(&appfs_path_info_cache_mutex);
          548  +	if (pthread_ret != 0) {
          549  +		APPFS_DEBUG("Unable to unlock path_info cache mutex !");
          550  +
          551  +		return;
          552  +	}
          553  +
          554  +	return;
          555  +}
          556  +
          557  +static void appfs_get_path_info_cache_flush(uid_t uid, int new_size) {
          558  +	unsigned int idx;
          559  +	int pthread_ret;
          560  +
          561  +	pthread_ret = pthread_mutex_lock(&appfs_path_info_cache_mutex);
          562  +	if (pthread_ret != 0) {
          563  +		APPFS_DEBUG("Unable to lock path_info cache mutex !");
          564  +
          565  +		return;
          566  +	}
          567  +
          568  +	if (appfs_path_info_cache != NULL) {
          569  +		for (idx = 0; idx < appfs_path_info_cache_size; idx++) {
          570  +			if (appfs_path_info_cache[idx]._cache_path != NULL) {
          571  +				if (uid != ((uid_t) -1)) {
          572  +					if (appfs_path_info_cache[idx]._cache_uid != uid) {
          573  +						continue;
          574  +					}
          575  +				}
          576  +
          577  +				free(appfs_path_info_cache[idx]._cache_path);
          578  +
          579  +				appfs_path_info_cache[idx]._cache_path = NULL;
          580  +			}
          581  +		}
          582  +	}
          583  +
          584  +	if (uid == ((uid_t) -1)) {
          585  +		free(appfs_path_info_cache);
          586  +
          587  +		appfs_path_info_cache = NULL;
          588  +
          589  +		if (new_size != -1) {
          590  +			appfs_path_info_cache_size = new_size;
          591  +		}
          592  +	}
          593  +
          594  +	pthread_ret = pthread_mutex_unlock(&appfs_path_info_cache_mutex);
          595  +	if (pthread_ret != 0) {
          596  +		APPFS_DEBUG("Unable to unlock path_info cache mutex !");
          597  +
          598  +		return;
          599  +	}
          600  +
          601  +	return;
          602  +}
   510    603   
   511    604   /* Get information about a path, and optionally list children */
   512    605   static int appfs_get_path_info(const char *path, struct appfs_pathinfo *pathinfo) {
   513    606   	Tcl_Interp *interp;
   514    607   	Tcl_Obj *attrs_dict, *attr_value;
   515    608   	const char *attr_value_str;
   516    609   	Tcl_WideInt attr_value_wide;
   517    610   	int attr_value_int;
   518    611   	static __thread Tcl_Obj *attr_key_type = NULL, *attr_key_perms = NULL, *attr_key_size = NULL, *attr_key_time = NULL, *attr_key_source = NULL, *attr_key_childcount = NULL, *attr_key_packaged = NULL;
          612  +	int cache_ret;
   519    613   	int tcl_ret;
          614  +
          615  +	cache_ret = appfs_get_path_info_cache_get(path, appfs_get_fsuid(), pathinfo);
          616  +	if (cache_ret == 0) {
          617  +		if (pathinfo->type == APPFS_PATHTYPE_DOES_NOT_EXIST) {
          618  +			return(-ENOENT);
          619  +		}
          620  +
          621  +		if (pathinfo->type == APPFS_PATHTYPE_INVALID) {
          622  +			return(-EIO);
          623  +		}
          624  +
          625  +		return(0);
          626  +	}
   520    627   
   521    628   	interp = appfs_TclInterp();
   522    629   	if (interp == NULL) {
   523    630   		return(-EIO);
   524    631   	}
   525    632   
   526    633   	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getattr", path);
   527    634   	if (tcl_ret != TCL_OK) {
   528    635   		APPFS_DEBUG("::appfs::getattr(%s) failed.", path);
   529    636   		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
   530    637   
          638  +		pathinfo->type = APPFS_PATHTYPE_DOES_NOT_EXIST;
          639  +
          640  +		appfs_get_path_info_cache_add(path, appfs_get_fsuid(), pathinfo);
          641  +
   531    642   		return(-ENOENT);
   532    643   	}
   533    644   
   534    645   	if (attr_key_type == NULL) {
   535    646   		attr_key_type       = Tcl_NewStringObj("type", -1);
   536    647   		attr_key_perms      = Tcl_NewStringObj("perms", -1);
   537    648   		attr_key_size       = Tcl_NewStringObj("size", -1);
................................................................................
   631    742   		if (tcl_ret == TCL_OK) {
   632    743   			pathinfo->time = attr_value_wide;
   633    744   		}
   634    745   	} else {
   635    746   		pathinfo->time = 0;
   636    747   	}
   637    748   
          749  +	appfs_get_path_info_cache_add(path, appfs_get_fsuid(), pathinfo);
          750  +
   638    751   	return(0);
   639    752   }
   640    753   
   641    754   static char *appfs_prepare_to_create(const char *path) {
   642    755   	Tcl_Interp *interp;
   643    756   	const char *real_path;
   644    757   	int tcl_ret;
          758  +
          759  +	appfs_get_path_info_cache_flush(appfs_get_fsuid(), -1);
   645    760   
   646    761   	interp = appfs_TclInterp();
   647    762   	if (interp == NULL) {
   648    763   		return(NULL);
   649    764   	}
   650    765   
   651    766   	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::prepare_to_create", path);
................................................................................
   765    880   			stbuf->st_size = 0;
   766    881   			break;
   767    882   		case APPFS_PATHTYPE_FIFO:
   768    883   			stbuf->st_mode = S_IFIFO | 0555;
   769    884   			stbuf->st_nlink = 1;
   770    885   			stbuf->st_size = 0;
   771    886   			break;
   772         -		case APPFS_PATHTYPE_INVALID:
          887  +		case APPFS_PATHTYPE_DOES_NOT_EXIST:
   773    888   			retval = -ENOENT;
   774    889   
          890  +			break;
          891  +		case APPFS_PATHTYPE_INVALID:
          892  +			retval = -EIO;
          893  +
   775    894   			break;
   776    895   	}
   777    896   
   778    897   	if (pathinfo.packaged) {
   779    898   		stbuf->st_uid   = appfs_get_fsuid();
   780    899   		stbuf->st_gid   = appfs_get_fsgid();
   781    900   		stbuf->st_mode |= 0200;
................................................................................
   837    956   	if ((fi->flags & (O_WRONLY|O_CREAT)) == (O_CREAT|O_WRONLY)) {
   838    957   		/* The file will be created if it does not exist */
   839    958   		if (gpi_ret != 0 && gpi_ret != -ENOENT) {
   840    959   			return(gpi_ret);
   841    960   		}
   842    961   
   843    962   		mode = "create";
          963  +
          964  +		/*
          965  +		 * We have to clear the cache here so that the number of
          966  +		 * links gets maintained on the parent directory
          967  +		 */
          968  +		appfs_get_path_info_cache_flush(appfs_get_fsuid(), -1);
   844    969   	} else {
   845    970   		/* The file must already exist */
   846    971   		if (gpi_ret != 0) {
   847    972   			return(gpi_ret);
   848    973   		}
   849    974   
   850    975   		mode = "";
................................................................................
   888   1013   
   889   1014   	return(0);
   890   1015   }
   891   1016   
   892   1017   static int appfs_fuse_close(const char *path, struct fuse_file_info *fi) {
   893   1018   	int close_ret;
   894   1019   
         1020  +	appfs_get_path_info_cache_rm(path, appfs_get_fsuid());
         1021  +
   895   1022   	close_ret = close(fi->fh);
   896   1023   	if (close_ret != 0) {
   897   1024   		return(-EIO);
   898   1025   	}
   899   1026   
   900   1027   	return(0);
   901   1028   }
................................................................................
   917   1044   }
   918   1045   
   919   1046   static int appfs_fuse_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
   920   1047   	off_t lseek_ret;
   921   1048   	ssize_t write_ret;
   922   1049   
   923   1050   	APPFS_DEBUG("Enter (path = %s, ...)", path);
         1051  +
         1052  +	appfs_get_path_info_cache_rm(path, appfs_get_fsuid());
   924   1053   
   925   1054   	lseek_ret = lseek(fi->fh, offset, SEEK_SET);
   926   1055   	if (lseek_ret != offset) {
   927   1056   		return(-EIO);
   928   1057   	}
   929   1058   
   930   1059   	write_ret = write(fi->fh, buf, size);
................................................................................
  1009   1138   	APPFS_DEBUG("Enter (path = %s, ...)", path);
  1010   1139   
  1011   1140   	real_path = appfs_localpath(path);
  1012   1141   	if (real_path == NULL) {
  1013   1142   		return(-EIO);
  1014   1143   	}
  1015   1144   
         1145  +	appfs_get_path_info_cache_rm(path, appfs_get_fsuid());
         1146  +
  1016   1147   	appfs_simulate_user_fs_enter();
  1017   1148   
  1018   1149   	truncate_ret = truncate(real_path, size);
  1019   1150   
  1020   1151   	appfs_simulate_user_fs_leave();
  1021   1152   
  1022   1153   	free(real_path);
................................................................................
  1029   1160   }
  1030   1161   
  1031   1162   static int appfs_fuse_unlink_rmdir(const char *path) {
  1032   1163   	Tcl_Interp *interp;
  1033   1164   	int tcl_ret;
  1034   1165   
  1035   1166   	APPFS_DEBUG("Enter (path = %s, ...)", path);
         1167  +
         1168  +	appfs_get_path_info_cache_flush(appfs_get_fsuid(), -1);
  1036   1169   
  1037   1170   	interp = appfs_TclInterp();
  1038   1171   	if (interp == NULL) {
  1039   1172   		return(-EIO);
  1040   1173   	}
  1041   1174   
  1042   1175   	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::unlinkpath", path);
................................................................................
  1051   1184   }
  1052   1185   
  1053   1186   static int appfs_fuse_mkdir(const char *path, mode_t mode) {
  1054   1187   	char *real_path;
  1055   1188   	int mkdir_ret;
  1056   1189   
  1057   1190   	APPFS_DEBUG("Enter (path = %s, ...)", path);
  1058         -
  1059   1191   
  1060   1192   	real_path = appfs_prepare_to_create(path);
  1061   1193   	if (real_path == NULL) {
  1062   1194   		return(-EIO);
  1063   1195   	}
  1064   1196   
  1065   1197   	appfs_simulate_user_fs_enter();
................................................................................
  1081   1213   
  1082   1214   static int appfs_fuse_chmod(const char *path, mode_t mode) {
  1083   1215   	Tcl_Interp *interp;
  1084   1216   	const char *real_path;
  1085   1217   	int tcl_ret, chmod_ret;
  1086   1218   
  1087   1219   	APPFS_DEBUG("Enter (path = %s, ...)", path);
         1220  +
         1221  +	appfs_get_path_info_cache_rm(path, appfs_get_fsuid());
  1088   1222   
  1089   1223   	interp = appfs_TclInterp();
  1090   1224   	if (interp == NULL) {
  1091   1225   		return(-EIO);
  1092   1226   	}
  1093   1227   
  1094   1228   	tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::openpath", path, "write");
................................................................................
  1176   1310   }
  1177   1311   
  1178   1312   /*
  1179   1313    * AppFSd Package for Tcl:
  1180   1314    *         Bridge for I/O operations to request information about the current
  1181   1315    *         transaction
  1182   1316    */
         1317  +/*
         1318  + * Tcl interface to get the home directory for the user making the "current"
         1319  + * FUSE I/O request
         1320  + */
         1321  +static int tcl_appfs_get_homedir(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1322  +	char *homedir;
         1323  +	Tcl_Obj *homedir_obj;
         1324  +	uid_t fsuid;
         1325  +	static __thread Tcl_Obj *last_homedir_obj = NULL;
         1326  +	static __thread uid_t last_fsuid = -1;
         1327  +
         1328  +        if (objc != 1) {
         1329  +                Tcl_WrongNumArgs(interp, 1, objv, NULL);
         1330  +                return(TCL_ERROR);
         1331  +        }
         1332  +
         1333  +	fsuid = appfs_get_fsuid();
         1334  +
         1335  +	if (fsuid == last_fsuid && last_homedir_obj != NULL) {
         1336  +		homedir_obj = last_homedir_obj;
         1337  +	} else {
         1338  +		homedir = appfs_get_homedir(appfs_get_fsuid());
         1339  +
         1340  +		if (homedir == NULL) {
         1341  +			return(TCL_ERROR);
         1342  +		}
         1343  +
         1344  +		homedir_obj = Tcl_NewStringObj(homedir, -1);
         1345  +
         1346  +		free(homedir);
         1347  +
         1348  +		if (last_homedir_obj != NULL) {
         1349  +			Tcl_DecrRefCount(last_homedir_obj);
         1350  +		}
         1351  +
         1352  +		last_homedir_obj = homedir_obj;
         1353  +		last_fsuid = fsuid;
         1354  +
         1355  +		Tcl_IncrRefCount(last_homedir_obj);
         1356  +	}
         1357  +
         1358  +       	Tcl_SetObjResult(interp, homedir_obj);
         1359  +
         1360  +        return(TCL_OK);
         1361  +}
         1362  +
         1363  +static int tcl_appfs_simulate_user_fs_enter(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1364  +	appfs_simulate_user_fs_enter();
         1365  +
         1366  +	return(TCL_OK);
         1367  +}
         1368  +
         1369  +static int tcl_appfs_simulate_user_fs_leave(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1370  +	appfs_simulate_user_fs_leave();
         1371  +
         1372  +	return(TCL_OK);
         1373  +}
         1374  +
         1375  +static int tcl_appfs_get_fsuid(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1376  +	uid_t fsuid;
         1377  +
         1378  +	fsuid = appfs_get_fsuid();
         1379  +
         1380  +       	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(fsuid));
         1381  +
         1382  +	return(TCL_OK);
         1383  +}
         1384  +
         1385  +static int tcl_appfs_get_fsgid(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1386  +	gid_t fsgid;
         1387  +
         1388  +	fsgid = appfs_get_fsgid();
         1389  +
         1390  +       	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(fsgid));
         1391  +
         1392  +	return(TCL_OK);
         1393  +}
         1394  +
         1395  +static int tcl_appfs_get_path_info_cache_flush(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1396  +	int tcl_ret;
         1397  +	int new_size;
         1398  +
         1399  +	new_size = -1;
         1400  +
         1401  +	if (objc == 2) {
         1402  +		tcl_ret = Tcl_GetIntFromObj(interp, objv[1], &new_size);
         1403  +		if (tcl_ret != TCL_OK) {
         1404  +			return(tcl_ret);
         1405  +		}
         1406  +	} else if (objc > 2 || objc < 1) {
         1407  +                Tcl_WrongNumArgs(interp, 1, objv, "?new_cache_size?");
         1408  +		return(TCL_ERROR);
         1409  +	}
         1410  +
         1411  +	appfs_get_path_info_cache_flush(-1, new_size);
         1412  +
         1413  +	return(TCL_OK);
         1414  +}
         1415  +
  1183   1416   static int Appfsd_Init(Tcl_Interp *interp) {
  1184   1417   #ifdef USE_TCL_STUBS
  1185   1418   	if (Tcl_InitStubs(interp, TCL_VERSION, 0) == 0L) {
  1186   1419   		return(TCL_ERROR);
  1187   1420   	}
  1188   1421   #endif
  1189   1422   
  1190   1423   	Tcl_CreateObjCommand(interp, "appfsd::get_homedir", tcl_appfs_get_homedir, NULL, NULL);
  1191   1424   	Tcl_CreateObjCommand(interp, "appfsd::get_fsuid", tcl_appfs_get_fsuid, NULL, NULL);
  1192   1425   	Tcl_CreateObjCommand(interp, "appfsd::get_fsgid", tcl_appfs_get_fsgid, NULL, NULL);
  1193   1426   	Tcl_CreateObjCommand(interp, "appfsd::simulate_user_fs_enter", tcl_appfs_simulate_user_fs_enter, NULL, NULL);
  1194   1427   	Tcl_CreateObjCommand(interp, "appfsd::simulate_user_fs_leave", tcl_appfs_simulate_user_fs_leave, NULL, NULL);
         1428  +	Tcl_CreateObjCommand(interp, "appfsd::get_path_info_cache_flush", tcl_appfs_get_path_info_cache_flush, NULL, NULL);
  1195   1429   
  1196   1430   	Tcl_PkgProvide(interp, "appfsd", "1.0");
  1197   1431   
  1198   1432   	return(TCL_OK);
  1199   1433   }
  1200   1434   
  1201   1435   /*

Modified appfsd.tcl from [bfe8021807] to [99393ab276].

   278    278   			}
   279    279   
   280    280   			if {$pkgInfo(isLatest)} {
   281    281   				db eval {UPDATE packages SET isLatest = 0 WHERE hostname = $hostname AND package = $pkgInfo($package) AND os = $pkgInfo($package) AND cpuArch = $pkgInfo(cpuArch);}
   282    282   			}
   283    283   
   284    284   			db eval {INSERT INTO packages (hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest) VALUES ($hostname, $pkgInfo(hash), $pkgInfo(package), $pkgInfo(version), $pkgInfo(os), $pkgInfo(cpuArch), $pkgInfo(isLatest), 0);}
          285  +
   285    286   		}
   286    287   
   287    288   		# Look for packages that have been deleted
   288    289   		set found_packages [db eval {SELECT sha1 FROM packages WHERE hostname = $hostname;}]
   289    290   		foreach package $found_packages {
   290    291   			set found_packages_arr($package) 1
   291    292   		}
................................................................................
   295    296   		}
   296    297   
   297    298   		foreach package [array names found_packages_arr] {
   298    299   			db eval {DELETE FROM packages WHERE hostname = $hostname AND sha1 = $package;}
   299    300   		}
   300    301   
   301    302   		db eval {INSERT OR REPLACE INTO sites (hostname, lastUpdate, ttl) VALUES ($hostname, $now, $::appfs::ttl);}
          303  +
          304  +		appfsd::get_path_info_cache_flush
   302    305   
   303    306   		return COMPLETE
   304    307   	}
   305    308   
   306    309   	proc getpkgmanifest {hostname package_sha1} {
   307    310   		set haveManifests [db eval {SELECT haveManifest FROM packages WHERE sha1 = $package_sha1 LIMIT 1;}]
   308    311   		set haveManifest [lindex $haveManifests 0]
................................................................................
   354    357   				set fileInfo(directory) [join [lrange $fileInfo(name) 0 end-1] "/"]
   355    358   				set fileInfo(name) [lindex $fileInfo(name) end]
   356    359   
   357    360   				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) );}
   358    361   				db eval {UPDATE packages SET haveManifest = 1 WHERE sha1 = $package_sha1;}
   359    362   			}
   360    363   		}
          364  +
          365  +		appfsd::get_path_info_cache_flush
   361    366   
   362    367   		return COMPLETE
   363    368   	}
   364    369   
   365    370   	proc _localpath {package hostname file} {
   366    371   		set dir ""
   367    372   		catch {