Index: appfsd.c ================================================================== --- appfsd.c +++ appfsd.c @@ -383,19 +383,19 @@ 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); + 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(1); + return(-ENOENT); } if (attr_key_type == NULL) { attr_key_type = Tcl_NewStringObj("type", -1); attr_key_perms = Tcl_NewStringObj("perms", -1); @@ -409,18 +409,19 @@ 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); + return(-EIO); } if (attr_value == NULL) { - return(1); + 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; @@ -472,11 +473,11 @@ memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int); } } break; default: - return(1); + 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); @@ -577,11 +578,10 @@ 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) { @@ -593,19 +593,19 @@ 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); @@ -613,45 +613,66 @@ 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; + const char *real_path, *mode; + int gpi_ret, tcl_ret; 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); + 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); } - real_path = appfs_getfile(pathinfo.hostname, pathinfo.typeinfo.file.sha1); + 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); } - fh = open(real_path, O_RDONLY); - free((void *) real_path); + 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; -#endif return(0); } static int appfs_fuse_close(const char *path, struct fuse_file_info *fi) { @@ -776,11 +797,11 @@ /* * 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; + static int seen_cachedir = 0; if (key == FUSE_OPT_KEY_NONOPT && seen_cachedir == 0) { seen_cachedir = 1; appfs_cachedir = strdup(arg); Index: appfsd.tcl ================================================================== --- appfsd.tcl +++ appfsd.tcl @@ -36,11 +36,11 @@ if {[file exists $file]} { return $file } - set tmpfile "${file}.[expr {rand()}]" + set tmpfile "${file}.[expr {rand()}][clock clicks]" set fd [open $tmpfile "w"] fconfigure $fd -translation binary catch { @@ -342,10 +342,11 @@ } 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 "/"] @@ -527,7 +528,39 @@ 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 } }