Check-in [6af0168ed8]
Overview
Comment:Updated to support unthreaded Tcl and fixed a memory leak with home directory determination
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6af0168ed827e5774e23d29cc8b9ea61da332cf4
User & Date: rkeene on 2014-11-14 21:46:19
Other Links: manifest | tags
Context
2014-11-15
16:46
Added more debugging, renamed appfs_terminate_interp for with more accurate name, fixed FUSE read/write to use pread/pwrite and return no short reads as is required by FUSE, added call to Tcl_FinalizeThread() on thread termination check-in: d5bfe6710c user: rkeene tags: trunk
2014-11-14
21:46
Updated to support unthreaded Tcl and fixed a memory leak with home directory determination check-in: 6af0168ed8 user: rkeene tags: trunk
21:44
Updated to use TCL_DEFS from tclConfig.sh check-in: 24908ac300 user: rkeene tags: trunk
Changes

Modified appfsd.c from [b7668e46f2] to [1768754e26].

51
52
53
54
55
56
57













58
59
60
61
62
63
64
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77







+
+
+
+
+
+
+
+
+
+
+
+
+







/*
 * Global variables for AppFS caching
 */
pthread_mutex_t appfs_path_info_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
int appfs_path_info_cache_size = 8209;
struct appfs_pathinfo *appfs_path_info_cache = NULL;

#ifndef TCL_THREADS
/*
 * Handle unthreaded Tcl
 */
pthread_mutex_t appfs_tcl_big_global_lock = PTHREAD_MUTEX_INITIALIZER;
#define appfs_call_libtcl_enter pthread_mutex_lock(&appfs_tcl_big_global_lock);
#define appfs_call_libtcl_exit pthread_mutex_unlock(&appfs_tcl_big_global_lock);
#else
#define appfs_call_libtcl_enter /**/
#define appfs_call_libtcl_exit /**/
#endif
#define appfs_call_libtcl(x...) appfs_call_libtcl_enter x appfs_call_libtcl_exit

/*
 * Global variables for AppFS Tcl Interpreter restarting
 */
int interp_reset_key = 0;

/*
 * AppFS Path Type:  Describes the type of path a given file is
105
106
107
108
109
110
111

112
113
114

115


116
117
118
119
120
121
122
123
124
125
126

127

128


129
130

131
132



133

134


135
136
137

138
139
140
141

142
143
144
145

146


147
148

149
150



151

152


153
154
155

156
157
158
159

160
161
162
163

164


165
166

167
168



169

170


171
172
173

174
175
176
177

178
179
180
181
182
183
184

185

186
187


188
189

190
191



192

193


194
195
196

197
198
199
200

201
202
203
204
205
206
207
208
209

210

211
212


213
214

215
216



217

218


219
220
221

222
223
224
225

226
227
228
229
230
231
232

233



234
235
236

237


238
239
240

241
242
243
244

245
246
247
248
249
250
251
252

253


254
255

256
257



258

259


260
261
262

263
264
265
266

267
268
269
270
271
272
273
274

275
276
277




278
279
280
281
282
283

284
285
286
287
288
289
290
118
119
120
121
122
123
124
125
126
127
128
129

130
131
132
133
134
135
136
137
138
139
140
141

142
143
144

145
146
147
148
149


150
151
152
153
154

155
156
157
158

159
160
161
162

163
164
165
166
167
168

169
170
171
172
173


174
175
176
177
178

179
180
181
182

183
184
185
186

187
188
189
190
191
192

193
194
195
196
197


198
199
200
201
202

203
204
205
206

207
208
209
210

211
212
213
214
215
216
217
218
219

220
221

222
223
224
225
226


227
228
229
230
231

232
233
234
235

236
237
238
239

240
241
242
243
244
245
246
247
248
249
250

251
252

253
254
255
256
257


258
259
260
261
262

263
264
265
266

267
268
269
270

271
272
273
274
275
276
277
278
279

280
281
282
283
284
285
286

287
288
289
290

291
292
293
294

295
296
297
298
299
300
301
302
303
304

305
306
307
308
309


310
311
312
313
314

315
316
317
318

319
320
321
322

323
324
325
326
327
328
329
330
331
332



333
334
335
336
337
338
339
340
341

342
343
344
345
346
347
348
349







+



+
-
+
+










-
+

+
-
+
+


+
-
-
+
+
+

+
-
+
+


-
+



-
+




+
-
+
+


+
-
-
+
+
+

+
-
+
+


-
+



-
+




+
-
+
+


+
-
-
+
+
+

+
-
+
+


-
+



-
+







+
-
+

-
+
+


+
-
-
+
+
+

+
-
+
+


-
+



-
+









+
-
+

-
+
+


+
-
-
+
+
+

+
-
+
+


-
+



-
+







+
-
+
+
+



+
-
+
+


-
+



-
+








+
-
+
+


+
-
-
+
+
+

+
-
+
+


-
+



-
+








+
-
-
-
+
+
+
+





-
+








/*
 * Create a new Tcl interpreter and completely initialize it
 */
static Tcl_Interp *appfs_create_TclInterp(char **error_string) {
	Tcl_Interp *interp;
	int tcl_ret;
	const char *tcl_setvar_ret;

	APPFS_DEBUG("Creating new Tcl interpreter for TID = 0x%llx", (unsigned long long) pthread_self());

	appfs_call_libtcl(
	interp = Tcl_CreateInterp();
		interp = Tcl_CreateInterp();
	)
	if (interp == NULL) {
		fprintf(stderr, "Unable to create Tcl Interpreter.  Aborting.\n");

		if (error_string) {
			*error_string = strdup("Unable to create Tcl interpreter.");
		}

		return(NULL);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	appfs_call_libtcl(
	tcl_ret = Tcl_Init(interp);
		tcl_ret = Tcl_Init(interp);
	)
	if (tcl_ret != TCL_OK) {
		fprintf(stderr, "Unable to initialize Tcl.  Aborting.\n");
		appfs_call_libtcl(
		fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));

			fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));
		)

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	appfs_call_libtcl(
	tcl_ret = Tcl_Eval(interp, "package ifneeded sha1 1.0 [list load {} sha1]");
		tcl_ret = Tcl_Eval(interp, "package ifneeded sha1 1.0 [list load {} sha1]");
	)
	if (tcl_ret != TCL_OK) {
		fprintf(stderr, "Unable to initialize Tcl SHA1.  Aborting.\n");
		appfs_call_libtcl(
		fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));

			fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));
		)

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	appfs_call_libtcl(
	tcl_ret = Tcl_Eval(interp, "package ifneeded appfsd 1.0 [list load {} appfsd]");
		tcl_ret = Tcl_Eval(interp, "package ifneeded appfsd 1.0 [list load {} appfsd]");
	)
	if (tcl_ret != TCL_OK) {
		fprintf(stderr, "Unable to initialize Tcl AppFS Package.  Aborting.\n");
		appfs_call_libtcl(
		fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));

			fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));
		)

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	/*
	 * Load "pki.tcl" in the same way as appfsd.tcl (see below)
	 */
	appfs_call_libtcl_enter
	tcl_ret = Tcl_Eval(interp, ""
		tcl_ret = Tcl_Eval(interp, ""
#include "pki.tcl.h"
	"");
		"");
	appfs_call_libtcl_exit
	if (tcl_ret != TCL_OK) {
		fprintf(stderr, "Unable to initialize Tcl PKI.  Aborting.\n");
		appfs_call_libtcl(
		fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));

			fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));
		)

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	/*
	 * Load the "appfsd.tcl" script, which is "compiled" into a C header
	 * so that it does not need to exist on the filesystem and can be
	 * directly evaluated.
	 */
	appfs_call_libtcl_enter
	tcl_ret = Tcl_Eval(interp, ""
		tcl_ret = Tcl_Eval(interp, ""
#include "appfsd.tcl.h"
	"");
		"");
	appfs_call_libtcl_exit
	if (tcl_ret != TCL_OK) {
		fprintf(stderr, "Unable to initialize Tcl AppFS script.  Aborting.\n");
		appfs_call_libtcl(
		fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));

			fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));
		)

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	/*
	 * Set global variables from C to Tcl
	 */
	appfs_call_libtcl(
	if (Tcl_SetVar(interp, "::appfs::cachedir", appfs_cachedir, TCL_GLOBAL_ONLY) == NULL) {
		tcl_setvar_ret = Tcl_SetVar(interp, "::appfs::cachedir", appfs_cachedir, TCL_GLOBAL_ONLY);
	)
	if (tcl_setvar_ret == NULL) {
		fprintf(stderr, "Unable to set cache directory.  This should never fail.\n");

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	/*
	 * Initialize the "appfsd.tcl" environment, which must be done after
	 * global variables are set.
	 */
	appfs_call_libtcl(
	tcl_ret = Tcl_Eval(interp, "::appfs::init");
		tcl_ret = Tcl_Eval(interp, "::appfs::init");
	)
	if (tcl_ret != TCL_OK) {
		fprintf(stderr, "Unable to initialize Tcl AppFS script (::appfs::init).  Aborting.\n");
		appfs_call_libtcl(
		fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));

			fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp));
		)

		if (error_string) {
			appfs_call_libtcl(
			*error_string = strdup(Tcl_GetStringResult(interp));
				*error_string = strdup(Tcl_GetStringResult(interp));
			)
		}

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		APPFS_DEBUG("Terminating Tcl interpreter.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		return(NULL);
	}

	/*
	 * Hide some Tcl commands that we do not care to use and which may
	 * slow down run-time operations.
	 */
	appfs_call_libtcl(
	Tcl_HideCommand(interp, "auto_load_index", "auto_load_index");
	Tcl_HideCommand(interp, "unknown", "unknown");
	Tcl_HideCommand(interp, "exit", "exit");
		Tcl_HideCommand(interp, "auto_load_index", "auto_load_index");
		Tcl_HideCommand(interp, "unknown", "unknown");
		Tcl_HideCommand(interp, "exit", "exit");
	)

	/*
	 * Release the hold we have on the interpreter so that it may be
	 * deleted if needed
	 */
	Tcl_Release(interp);
	appfs_call_libtcl(Tcl_Release(interp);)

	/*
	 * Return the completely initialized interpreter
	 */
	return(interp);
}

299
300
301
302
303
304
305
306

307
308
309
310
311
312
313
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372







-
+








	global_interp_reset_key = __sync_fetch_and_add(&interp_reset_key, 0);

	interp = pthread_getspecific(interpKey);
	if (interp != NULL && thread_interp_reset_key != global_interp_reset_key) {
		APPFS_DEBUG("Terminating old interpreter and restarting due to reset request.");

		Tcl_DeleteInterp(interp);
		appfs_call_libtcl(Tcl_DeleteInterp(interp);)

		interp = NULL;

		pthread_ret = pthread_setspecific(interpKey, interp);
	}

	if (global_interp_reset_key == -1) {
325
326
327
328
329
330
331
332

333
334
335
336
337
338
339
384
385
386
387
388
389
390

391
392
393
394
395
396
397
398







-
+







			return(NULL);
		}

		pthread_ret = pthread_setspecific(interpKey, interp);
		if (pthread_ret != 0) {
			APPFS_DEBUG("pthread_setspecific() failed.  Terminating Tcl interpreter.");

			Tcl_DeleteInterp(interp);
			appfs_call_libtcl(Tcl_DeleteInterp(interp);)

			return(NULL);
		}
	}

	return(interp);
}
351
352
353
354
355
356
357

358

359
360

361
362
363
364



365
366

367
368
369
370
371
372
373
374
375
376
377















378
379
380

381


382
383
384
385
386
387
388
410
411
412
413
414
415
416
417

418
419

420
421



422
423
424
425

426
427










428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

447
448
449
450
451
452
453
454
455







+
-
+

-
+

-
-
-
+
+
+

-
+

-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



+
-
+
+








	if (interp == NULL) {
		return(TCL_ERROR);
	}

	objv = (void *) ckalloc(sizeof(*objv) * objc);

	appfs_call_libtcl(
	objv[0] = Tcl_NewStringObj(cmd, -1);
		objv[0] = Tcl_NewStringObj(cmd, -1);

	Tcl_IncrRefCount(objv[0]);
		Tcl_IncrRefCount(objv[0]);

	va_start(argp, cmd);
	for (i = 1; i < objc; i++) {
		arg = va_arg(argp, const char *);
		va_start(argp, cmd);
		for (i = 1; i < objc; i++) {
			arg = va_arg(argp, const char *);

		objv[i] = Tcl_NewStringObj(arg, -1);
			objv[i] = Tcl_NewStringObj(arg, -1);

		Tcl_IncrRefCount(objv[i]);
	}
	va_end(argp);

	retval = Tcl_EvalObjv(interp, objc, objv, 0);

	for (i = 0; i < objc; i++) {
		Tcl_DecrRefCount(objv[i]);
	}

			Tcl_IncrRefCount(objv[i]);
		}
		va_end(argp);
	)

	appfs_call_libtcl(
		retval = Tcl_EvalObjv(interp, objc, objv, 0);
	)

	appfs_call_libtcl(
		for (i = 0; i < objc; i++) {
			Tcl_DecrRefCount(objv[i]);
		}
	)

	ckfree((void *) objv);

	if (retval != TCL_OK) {
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl command failed, ::errorInfo contains: %s\n", Tcl_GetVar(interp, "::errorInfo", 0));
			APPFS_DEBUG("Tcl command failed, ::errorInfo contains: %s\n", Tcl_GetVar(interp, "::errorInfo", 0));
		)
	}

	return(retval);
}

/*
 * Request all Tcl interpreters restart
696
697
698
699
700
701
702

703


704
705
706
707
708
709
710
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780







+

+
+







	Tcl_Obj *attrs_dict, *attr_value;
	const char *attr_value_str;
	Tcl_WideInt attr_value_wide;
	int attr_value_int;
	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;
	int cache_ret;
	int tcl_ret;
	int retval;
	uid_t fsuid;

	retval = 0;

	fsuid = appfs_get_fsuid();

	cache_ret = appfs_get_path_info_cache_get(path, fsuid, pathinfo);
	if (cache_ret == 0) {
		if (pathinfo->type == APPFS_PATHTYPE_DOES_NOT_EXIST) {
			return(-ENOENT);
718
719
720
721
722
723
724
725

726
727
728
729

730


731
732
733
734
735
736

737
738
739
740
741

742
743
744
745
746
747
748
749
750
751
752






















753
754

755
756
757




758
759
760
761
762
763

764
765
766
767
768
769
770

771

772
773
774
775
776




777
778
779
780
781
782
783
784







785
786
787
788
789
790





791
792
793
794
795
796
797
798







799
800
801
802
803
804
805
806
807
808
809
810
811












812
813
814
815



816
817
818
819



820
821
822
823
824
825
826
827
828
829
830
831











832
833

834
835

836
837
838
839
840




841
842
843
844
845
846
847
848
849
850









851
852
853
854
855
856








857
858
859
860
861
862
863
864
865
866
867
868
869
870
871

872

873


874
875

876
877
878




879
880
881
882

883
884
885




886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904

905

906


907
908

909


910
911
912
913

914
915
916




917
918
919
920
921
922
923
788
789
790
791
792
793
794

795
796
797
798
799
800

801
802
803
804
805
806
807

808
809
810
811
812
813
814











815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839



840
841
842
843
844
845
846
847
848

849
850
851
852
853
854
855
856
857

858
859




860
861
862
863
864







865
866
867
868
869
870
871
872





873
874
875
876
877
878







879
880
881
882
883
884
885
886












887
888
889
890
891
892
893
894
895
896
897
898
899



900
901
902
903



904
905
906
907











908
909
910
911
912
913
914
915
916
917
918


919


920
921




922
923
924
925
926









927
928
929
930
931
932
933
934
935
936





937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958

959
960
961

962
963
964
965
966



967
968
969
970
971
972
973
974
975



976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997

998
999
1000

1001
1002
1003
1004
1005

1006
1007
1008
1009
1010
1011
1012



1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023







-
+




+
-
+
+





-
+





+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


+
-
-
-
+
+
+
+





-
+







+
-
+

-
-
-
-
+
+
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
+
+
+

-
-
-
+
+
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
+

-
-
-
-
+
+
+
+

-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+
+
+
+














-
+

+
-
+
+


+
-
-
-
+
+
+
+




+
-
-
-
+
+
+
+


















-
+

+
-
+
+


+
-
+
+




+
-
-
-
+
+
+
+







	}

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(-EIO);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getattr", path);
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::getattr(%s) failed.", path);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		pathinfo->type = APPFS_PATHTYPE_DOES_NOT_EXIST;

		appfs_get_path_info_cache_add(path, fsuid, pathinfo);

		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		return(-ENOENT);
	}

	if (attr_key_type == NULL) {
		appfs_call_libtcl(
		attr_key_type       = Tcl_NewStringObj("type", -1);
		attr_key_perms      = Tcl_NewStringObj("perms", -1);
		attr_key_size       = Tcl_NewStringObj("size", -1);
		attr_key_time       = Tcl_NewStringObj("time", -1);
		attr_key_source     = Tcl_NewStringObj("source", -1);
		attr_key_childcount = Tcl_NewStringObj("childcount", -1);
		attr_key_packaged   = Tcl_NewStringObj("packaged", -1);
	}

	attrs_dict = Tcl_GetObjResult(interp);
	tcl_ret = Tcl_DictObjGet(interp, attrs_dict, attr_key_type, &attr_value);
			attr_key_type       = Tcl_NewStringObj("type", -1);
			attr_key_perms      = Tcl_NewStringObj("perms", -1);
			attr_key_size       = Tcl_NewStringObj("size", -1);
			attr_key_time       = Tcl_NewStringObj("time", -1);
			attr_key_source     = Tcl_NewStringObj("source", -1);
			attr_key_childcount = Tcl_NewStringObj("childcount", -1);
			attr_key_packaged   = Tcl_NewStringObj("packaged", -1);

			Tcl_IncrRefCount(attr_key_type);
			Tcl_IncrRefCount(attr_key_perms);
			Tcl_IncrRefCount(attr_key_size);
			Tcl_IncrRefCount(attr_key_time);
			Tcl_IncrRefCount(attr_key_source);
			Tcl_IncrRefCount(attr_key_childcount);
			Tcl_IncrRefCount(attr_key_packaged);
		)
	}

	appfs_call_libtcl(
		attrs_dict = Tcl_GetObjResult(interp);
		tcl_ret = Tcl_DictObjGet(interp, attrs_dict, attr_key_type, &attr_value);
	)
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("[dict get \"type\"] failed");
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(-EIO);
	}

	if (attr_value == NULL) {
		Tcl_Release(interp);
		appfs_call_libtcl(Tcl_Release(interp);)

		return(-EIO);
	}

	pathinfo->packaged = 0;
	pathinfo->inode = appfs_get_path_inode(path);

	appfs_call_libtcl(
	attr_value_str = Tcl_GetString(attr_value);
		attr_value_str = Tcl_GetString(attr_value);

	switch (attr_value_str[0]) {
		case 'd': /* directory */
			pathinfo->type = APPFS_PATHTYPE_DIRECTORY;
			pathinfo->typeinfo.dir.childcount = 0;
		switch (attr_value_str[0]) {
			case 'd': /* directory */
				pathinfo->type = APPFS_PATHTYPE_DIRECTORY;
				pathinfo->typeinfo.dir.childcount = 0;

			Tcl_DictObjGet(interp, attrs_dict, attr_key_childcount, &attr_value);
			if (attr_value != NULL) {
				tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
				if (tcl_ret == TCL_OK) {
					pathinfo->typeinfo.dir.childcount = attr_value_wide;
				}
			}
				Tcl_DictObjGet(interp, attrs_dict, attr_key_childcount, &attr_value);
				if (attr_value != NULL) {
					tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
					if (tcl_ret == TCL_OK) {
						pathinfo->typeinfo.dir.childcount = attr_value_wide;
					}
				}

			break;
		case 'f': /* file */
			pathinfo->type = APPFS_PATHTYPE_FILE;
			pathinfo->typeinfo.file.size = 0;
			pathinfo->typeinfo.file.executable = 0;
				break;
			case 'f': /* file */
				pathinfo->type = APPFS_PATHTYPE_FILE;
				pathinfo->typeinfo.file.size = 0;
				pathinfo->typeinfo.file.executable = 0;

			Tcl_DictObjGet(interp, attrs_dict, attr_key_size, &attr_value);
			if (attr_value != NULL) {
				tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
				if (tcl_ret == TCL_OK) {
					pathinfo->typeinfo.file.size = attr_value_wide;
				}
			}
				Tcl_DictObjGet(interp, attrs_dict, attr_key_size, &attr_value);
				if (attr_value != NULL) {
					tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
					if (tcl_ret == TCL_OK) {
						pathinfo->typeinfo.file.size = attr_value_wide;
					}
				}

			Tcl_DictObjGet(interp, attrs_dict, attr_key_perms, &attr_value);
			if (attr_value != NULL) {
				attr_value_str = Tcl_GetString(attr_value);
				if (attr_value_str[0] == 'x') {
					pathinfo->typeinfo.file.executable = 1;
				}
			}
			break;
		case 's': /* symlink */
			pathinfo->type = APPFS_PATHTYPE_SYMLINK;
			pathinfo->typeinfo.symlink.size = 0;
			pathinfo->typeinfo.symlink.source[0] = '\0';
				Tcl_DictObjGet(interp, attrs_dict, attr_key_perms, &attr_value);
				if (attr_value != NULL) {
					attr_value_str = Tcl_GetString(attr_value);
					if (attr_value_str[0] == 'x') {
						pathinfo->typeinfo.file.executable = 1;
					}
				}
				break;
			case 's': /* symlink */
				pathinfo->type = APPFS_PATHTYPE_SYMLINK;
				pathinfo->typeinfo.symlink.size = 0;
				pathinfo->typeinfo.symlink.source[0] = '\0';

			Tcl_DictObjGet(interp, attrs_dict, attr_key_source, &attr_value);
			if (attr_value != NULL) {
				attr_value_str = Tcl_GetStringFromObj(attr_value, &attr_value_int); 
				Tcl_DictObjGet(interp, attrs_dict, attr_key_source, &attr_value);
				if (attr_value != NULL) {
					attr_value_str = Tcl_GetStringFromObj(attr_value, &attr_value_int); 

				if ((attr_value_int + 1) <= sizeof(pathinfo->typeinfo.symlink.source)) {
					pathinfo->typeinfo.symlink.size = attr_value_int;
					pathinfo->typeinfo.symlink.source[attr_value_int] = '\0';
					if ((attr_value_int + 1) <= sizeof(pathinfo->typeinfo.symlink.source)) {
						pathinfo->typeinfo.symlink.size = attr_value_int;
						pathinfo->typeinfo.symlink.source[attr_value_int] = '\0';

					memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int);
				}
			}
			break;
		case 'F': /* pipe/fifo */
			pathinfo->type = APPFS_PATHTYPE_FIFO;
			break;
		case 'S': /* UNIX domain socket */
			pathinfo->type = APPFS_PATHTYPE_SOCKET;
			break;
		default:
						memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int);
					}
				}
				break;
			case 'F': /* pipe/fifo */
				pathinfo->type = APPFS_PATHTYPE_FIFO;
				break;
			case 'S': /* UNIX domain socket */
				pathinfo->type = APPFS_PATHTYPE_SOCKET;
				break;
			default:
			Tcl_Release(interp);

				retval = -EIO;
			return(-EIO);
	}
		}

	Tcl_DictObjGet(interp, attrs_dict, attr_key_packaged, &attr_value);
	if (attr_value != NULL) {
		pathinfo->packaged = 1;
	}
		Tcl_DictObjGet(interp, attrs_dict, attr_key_packaged, &attr_value);
		if (attr_value != NULL) {
			pathinfo->packaged = 1;
		}

	Tcl_DictObjGet(interp, attrs_dict, attr_key_time, &attr_value);
	if (attr_value != NULL) {
		tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
		if (tcl_ret == TCL_OK) {
			pathinfo->time = attr_value_wide;
		}
	} else {
		pathinfo->time = 0;
	}
		Tcl_DictObjGet(interp, attrs_dict, attr_key_time, &attr_value);
		if (attr_value != NULL) {
			tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
			if (tcl_ret == TCL_OK) {
				pathinfo->time = attr_value_wide;
			}
		} else {
			pathinfo->time = 0;
		}

	Tcl_Release(interp);

	appfs_get_path_info_cache_add(path, fsuid, pathinfo);

	return(0);
		Tcl_Release(interp);
	)

	if (retval == 0) {
		appfs_get_path_info_cache_add(path, fsuid, pathinfo);
	}

	return(retval);
}

static char *appfs_prepare_to_create(const char *path) {
	Tcl_Interp *interp;
	const char *real_path;
	int tcl_ret;

	appfs_get_path_info_cache_flush(appfs_get_fsuid(), -1);

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(NULL);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	appfs_call_libtcl(
	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::prepare_to_create", path);
		tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::prepare_to_create", path);
	)
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::prepare_to_create(%s) failed.", path);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(NULL);
	}

	appfs_call_libtcl(
	real_path = Tcl_GetStringResult(interp);

	Tcl_Release(interp);
		real_path = Tcl_GetStringResult(interp);
	)

	appfs_call_libtcl(Tcl_Release(interp);)

	if (real_path == NULL) {
		return(NULL);
	}

	return(strdup(real_path));
}

static char *appfs_localpath(const char *path) {
	Tcl_Interp *interp;
	const char *real_path;
	int tcl_ret;

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(NULL);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	appfs_call_libtcl(
	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::localpath", path);
		tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::localpath", path);
	)
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::localpath(%s) failed.", path);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		return(NULL);
	}

	appfs_call_libtcl(
	real_path = Tcl_GetStringResult(interp);

	Tcl_Release(interp);
		real_path = Tcl_GetStringResult(interp);
	)

	appfs_call_libtcl(Tcl_Release(interp);)

	if (real_path == NULL) {
		return(NULL);
	}

	return(strdup(real_path));
}
1064
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078

1079
1080
1081




1082
1083
1084
1085

1086


1087
1088

1089
1090
1091




1092
1093
1094
1095
1096

1097


1098
1099
1100

1101
1102
1103
1104
1105
1106
1107
1164
1165
1166
1167
1168
1169
1170

1171
1172
1173
1174
1175
1176
1177
1178
1179



1180
1181
1182
1183
1184
1185
1186
1187
1188

1189
1190
1191
1192
1193



1194
1195
1196
1197
1198
1199
1200
1201
1202
1203

1204
1205
1206
1207

1208
1209
1210
1211
1212
1213
1214
1215







-
+







+
-
-
-
+
+
+
+




+
-
+
+


+
-
-
-
+
+
+
+





+
-
+
+


-
+







	APPFS_DEBUG("Enter (path = %s, ...)", path);

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(0);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	filler(buf, ".", NULL, 0);
	filler(buf, "..", NULL, 0);

	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getchildren", path);
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::getchildren(%s) failed.", path);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(0);
	}

	appfs_call_libtcl(
	tcl_ret = Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp), &children_count, &children);
		tcl_ret = Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp), &children_count, &children);
	)
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("Parsing list of children on path %s failed.", path);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(0);
	}

	for (idx = 0; idx < children_count; idx++) {
		appfs_call_libtcl(
		filler(buf, Tcl_GetString(children[idx]), NULL, 0);
			filler(buf, Tcl_GetString(children[idx]), NULL, 0);
		)
	}

	Tcl_Release(interp);
	appfs_call_libtcl(Tcl_Release(interp);)

	return(0);
}

static int appfs_fuse_open(const char *path, struct fuse_file_info *fi) {
	Tcl_Interp *interp;
	struct appfs_pathinfo pathinfo;
1144
1145
1146
1147
1148
1149
1150
1151

1152
1153
1154
1155

1156
1157
1158




1159
1160
1161
1162

1163
1164
1165




1166
1167
1168
1169
1170
1171
1172
1252
1253
1254
1255
1256
1257
1258

1259
1260
1261
1262
1263
1264



1265
1266
1267
1268
1269
1270
1271
1272
1273



1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284







-
+




+
-
-
-
+
+
+
+




+
-
-
-
+
+
+
+







	}

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(-EIO);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::openpath", path, mode);
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::openpath(%s, %s) failed.", path, mode);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(-EIO);
	}

	appfs_call_libtcl(
	real_path = Tcl_GetStringResult(interp);

	Tcl_Release(interp);
		real_path = Tcl_GetStringResult(interp);
	)

	appfs_call_libtcl(Tcl_Release(interp);)

	if (real_path == NULL) {
		return(-EIO);
	}

	APPFS_DEBUG("Translated request to open %s to opening %s (mode = \"%s\")", path, real_path, mode);

1338
1339
1340
1341
1342
1343
1344

1345
1346
1347




1348
1349
1350
1351
1352

1353
1354
1355
1356
1357
1358
1359
1450
1451
1452
1453
1454
1455
1456
1457



1458
1459
1460
1461
1462
1463
1464
1465

1466
1467
1468
1469
1470
1471
1472
1473







+
-
-
-
+
+
+
+




-
+







	if (interp == NULL) {
		return(-EIO);
	}

	tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::unlinkpath", path);
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::unlinkpath(%s) failed.", path);
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(-EIO);
	}

	Tcl_Release(interp);
	appfs_call_libtcl(Tcl_Release(interp);)

	return(0);
}

static int appfs_fuse_mkdir(const char *path, mode_t mode) {
	char *real_path;
	int mkdir_ret;
1392
1393
1394
1395
1396
1397
1398
1399

1400
1401
1402
1403

1404
1405
1406




1407
1408
1409
1410

1411
1412
1413




1414
1415
1416
1417
1418
1419
1420
1506
1507
1508
1509
1510
1511
1512

1513
1514
1515
1516
1517
1518



1519
1520
1521
1522
1523
1524
1525
1526
1527



1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538







-
+




+
-
-
-
+
+
+
+




+
-
-
-
+
+
+
+







	appfs_get_path_info_cache_rm(path, appfs_get_fsuid());

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(-EIO);
	}

	Tcl_Preserve(interp);
	appfs_call_libtcl(Tcl_Preserve(interp);)

	tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::openpath", path, "write");
	if (tcl_ret != TCL_OK) {
		APPFS_DEBUG("::appfs::openpath(%s, %s) failed.", path, "write");
		appfs_call_libtcl(
		APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		Tcl_Release(interp);
			APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		)

		appfs_call_libtcl(Tcl_Release(interp);)

		return(-EIO);
	}

	appfs_call_libtcl(
	real_path = Tcl_GetStringResult(interp);

	Tcl_Release(interp);
		real_path = Tcl_GetStringResult(interp);
	)

	appfs_call_libtcl(Tcl_Release(interp);)

	if (real_path == NULL) {
		return(-EIO);
	}

	appfs_simulate_user_fs_enter();

1508
1509
1510
1511
1512
1513
1514


1515
1516
1517
1518
1519
1520
1521
1522
1523
1524


1525
1526
1527
1528
1529
1530
1531
1532
1533

1534
1535
1536


1537
1538
1539
1540
1541
1542
1543
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654

1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667







+
+










+
+








-
+



+
+







                return(TCL_ERROR);
        }

	fsuid = appfs_get_fsuid();

	if (fsuid == last_fsuid && last_homedir_obj != NULL) {
		homedir_obj = last_homedir_obj;

		Tcl_IncrRefCount(homedir_obj);
	} else {
		homedir = appfs_get_homedir(appfs_get_fsuid());

		if (homedir == NULL) {
			return(TCL_ERROR);
		}

		homedir_obj = Tcl_NewStringObj(homedir, -1);

		free(homedir);

		Tcl_IncrRefCount(homedir_obj);

		if (last_homedir_obj != NULL) {
			Tcl_DecrRefCount(last_homedir_obj);
		}

		last_homedir_obj = homedir_obj;
		last_fsuid = fsuid;

		Tcl_IncrRefCount(last_homedir_obj);
		Tcl_IncrRefCount(homedir_obj);
	}

       	Tcl_SetObjResult(interp, homedir_obj);

	Tcl_DecrRefCount(homedir_obj);

        return(TCL_OK);
}

static int tcl_appfs_simulate_user_fs_enter(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
	appfs_simulate_user_fs_enter();

1655
1656
1657
1658
1659
1660
1661

1662


1663
1664
1665
1666
1667
1668
1669
1779
1780
1781
1782
1783
1784
1785
1786

1787
1788
1789
1790
1791
1792
1793
1794
1795







+
-
+
+







		return;
	}

	interp = _interp;

	APPFS_DEBUG("Terminating interpreter due to thread termination");

	appfs_call_libtcl(
	Tcl_DeleteInterp(interp);
		Tcl_DeleteInterp(interp);
	)

	return;
}

/*
 * FUSE operations structure
 */
1791
1792
1793
1794
1795
1796
1797

1798

1799
1800
1801
1802
1803
1804
1805
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933







+

+







		}

		fprintf(stderr, "Unable to initialize Tcl interpreter for AppFSd:\n");
		fprintf(stderr, "%s\n", test_interp_error);

		return(1);
	}

	Tcl_DeleteInterp(test_interp);

	Tcl_FinalizeNotifier(NULL);

	/*
	 * Register a signal handler for hot-restart requests
	 */
	signal_ret = signal(SIGHUP, appfs_signal_handler);
	if (signal_ret == SIG_ERR) {