Check-in [ebbca87b7e]
Overview
Comment:Added basic "open" support
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tcl-ops
Files: files | file ages | folders
SHA1:ebbca87b7e1f67a72bd69ff4168467adf4dab486
User & Date: rkeene on 2014-11-07 12:13:30
Other Links: manifest | tags
Context
2014-11-07
12:26
Added basic write support check-in: db5fcbef28 user: rkeene tags: tcl-ops
12:13
Added basic "open" support check-in: ebbca87b7e user: rkeene tags: tcl-ops
11:36
Add "getattr" implementation check-in: d64c2e9bf7 user: rkeene tags: tcl-ops
Changes

Modified appfsd.c from [70718fd2dc] to [a228e5eaeb].

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421

422
423
424
425
426
427
428
...
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617

618
619

620
621
622
623
624
625
626
627


628
629
630
631



632
633



634
635
636
637
638
639
640













641
642
643
644
645
646

647
648
649
650
651
652
653
654
655
656
657
658
659
...
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
	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;
	int tcl_ret;

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

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

		return(1);
	}

	if (attr_key_type == NULL) {
		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);
................................................................................

	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		return(1);
	}

	if (attr_value == NULL) {
		return(1);
	}

	pathinfo->packaged = 0;


	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;

................................................................................
					pathinfo->typeinfo.symlink.source[attr_value_int] = '\0';

					memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int);
				}
			}
			break;
		default:
			return(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;
................................................................................
}

static int appfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
	Tcl_Interp *interp;
	Tcl_Obj **children;
	int children_count, idx;
	int tcl_ret;
	int retval;

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

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(0);
	}
................................................................................
	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		
		return(0);
	}

	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));
		
		return(0);
	}

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

	return(0);
}

static int appfs_fuse_open(const char *path, struct fuse_file_info *fi) {

	struct appfs_pathinfo pathinfo;
	const char *real_path;

	int fh;
	int gpi_ret;

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

#if 0

	if ((fi->flags & 3) != O_RDONLY) {


                return(-EACCES);
	}

	gpi_ret = appfs_get_path_info(path, &pathinfo, NULL);



	if (gpi_ret != 0) {
		return(gpi_ret);



	}

	if (pathinfo.type == APPFS_PATHTYPE_DIRECTORY) {
		return(-EISDIR);
	}

	real_path = appfs_getfile(pathinfo.hostname, pathinfo.typeinfo.file.sha1);













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

	fh = open(real_path, O_RDONLY);
	free((void *) real_path);

	if (fh < 0) {
		return(-EIO);
	}

	fi->fh = fh;
#endif

	return(0);
}

static int appfs_fuse_close(const char *path, struct fuse_file_info *fi) {
	int close_ret;

................................................................................
	.read      = appfs_fuse_read
};

/*
 * FUSE option parsing callback
 */
static int appfs_fuse_opt_cb(void *data, const char *arg, int key, struct fuse_args *outargs) {
	static seen_cachedir = 0;

	if (key == FUSE_OPT_KEY_NONOPT && seen_cachedir == 0) {
		seen_cachedir = 1;

		appfs_cachedir = strdup(arg);

		return(0);







|







|







 







|



|



>







 







|







 







<







 







|







|











>

|
>

<



|

|
>
>
|
|

<
>
>
>
|
|
>
>
>






|
>
>
>
>
>
>
>
>
>
>
>
>
>




|
|
>





<







 







|







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
...
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
...
576
577
578
579
580
581
582

583
584
585
586
587
588
589
...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

623
624
625
626
627
628
629
630
631
632
633

634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

674
675
676
677
678
679
680
...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
	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;
	int tcl_ret;

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

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

		return(-ENOENT);
	}

	if (attr_key_type == NULL) {
		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);
................................................................................

	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		return(-EIO);
	}

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

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

	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;

................................................................................
					pathinfo->typeinfo.symlink.source[attr_value_int] = '\0';

					memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int);
				}
			}
			break;
		default:
			return(-EIO);
	}

	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;
................................................................................
}

static int appfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
	Tcl_Interp *interp;
	Tcl_Obj **children;
	int children_count, idx;
	int tcl_ret;


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

	interp = appfs_TclInterp();
	if (interp == NULL) {
		return(0);
	}
................................................................................
	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		return(0);
	}

	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		return(0);
	}

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

	return(0);
}

static int appfs_fuse_open(const char *path, struct fuse_file_info *fi) {
	Tcl_Interp *interp;
	struct appfs_pathinfo pathinfo;
	const char *real_path, *mode;
	int gpi_ret, tcl_ret;
	int fh;


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

	gpi_ret = appfs_get_path_info(path, &pathinfo);

	if ((fi->flags & (O_WRONLY|O_CREAT)) == (O_CREAT|O_WRONLY)) {
		/* The file will be created if it does not exist */
		if (gpi_ret != 0 && gpi_ret != -ENOENT) {
			return(gpi_ret);
		}


		mode = "create";
	} else {
		/* The file must already exist */
		if (gpi_ret != 0) {
			return(gpi_ret);
		}

		mode = "";
	}

	if (pathinfo.type == APPFS_PATHTYPE_DIRECTORY) {
		return(-EISDIR);
	}

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

	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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp));

		return(-EIO);
	}

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

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

	fh = open(real_path, fi->flags, 0600);
	if (fh < 0) {
		return(-EIO);
	}

	fi->fh = fh;


	return(0);
}

static int appfs_fuse_close(const char *path, struct fuse_file_info *fi) {
	int close_ret;

................................................................................
	.read      = appfs_fuse_read
};

/*
 * FUSE option parsing callback
 */
static int appfs_fuse_opt_cb(void *data, const char *arg, int key, struct fuse_args *outargs) {
	static int seen_cachedir = 0;

	if (key == FUSE_OPT_KEY_NONOPT && seen_cachedir == 0) {
		seen_cachedir = 1;

		appfs_cachedir = strdup(arg);

		return(0);

Modified appfsd.tcl from [c564230658] to [23568748fe].

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
340
341
342
343
344
345
346

347
348
349
350
351
352
353
...
525
526
527
528
529
530
531

532


533






























		file mkdir [file dirname $file]

		if {[file exists $file]} {
			return $file
		}

		set tmpfile "${file}.[expr {rand()}]"

		set fd [open $tmpfile "w"]
		fconfigure $fd -translation binary

		catch {
			set token [::http::geturl $url -channel $fd -binary true]
		}
................................................................................

		return COMPLETE
	}

	proc _localpath {package hostname file} {
		set homedir [::appfsd::get_homedir]
		set dir [file join $homedir .appfs "./${package}@${hostname}" "./${file}"]

	}

	proc _parsepath {path} {
		set path [string trim $path "/"]
		set path [split $path "/"]
		set pathlen [llength $path]

................................................................................
			return -code error "No such file or directory"
		}

		return [array get retval]
	}

	proc openpath {path mode} {

	}


}




































|







 







>







 







>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566

		file mkdir [file dirname $file]

		if {[file exists $file]} {
			return $file
		}

		set tmpfile "${file}.[expr {rand()}][clock clicks]"

		set fd [open $tmpfile "w"]
		fconfigure $fd -translation binary

		catch {
			set token [::http::geturl $url -channel $fd -binary true]
		}
................................................................................

		return COMPLETE
	}

	proc _localpath {package hostname file} {
		set homedir [::appfsd::get_homedir]
		set dir [file join $homedir .appfs "./${package}@${hostname}" "./${file}"]
		return $dir
	}

	proc _parsepath {path} {
		set path [string trim $path "/"]
		set path [split $path "/"]
		set pathlen [llength $path]

................................................................................
			return -code error "No such file or directory"
		}

		return [array get retval]
	}

	proc openpath {path mode} {
		array set pathinfo [_parsepath $path]

		if {$pathinfo(_type) != "files"} {
			return -code error "invalid type"
		}

		set localpath [_localpath $pathinfo(package) $pathinfo(hostname) $pathinfo(file)]

		if {[file exists $localpath]} {
			return $localpath
		}

		set work [split $pathinfo(file) "/"]
		set directory [join [lrange $work 0 end-1] "/"]
		set file [lindex $work end]
		set file_sha1 [::appfs::db onecolumn {SELECT file_sha1 FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_name = $file AND file_directory = $directory;}]

		if {$file_sha1 == ""} {
			return -code error "No such file or directory"
		}

		set localcachefile [download $pathinfo(hostname) $file_sha1]

		if {$mode == "create"} {
			set tmplocalpath "${localpath}.[expr rand()][clock clicks]"
			file copy -force -- $localcachefile $tmplocalpath
			file rename -force -- $tmplocalpath $localpath

			return $localpath
		}

		return $localcachefile
	}
}