@@ -50,11 +50,13 @@ */ typedef enum { APPFS_PATHTYPE_INVALID, APPFS_PATHTYPE_FILE, APPFS_PATHTYPE_DIRECTORY, - APPFS_PATHTYPE_SYMLINK + APPFS_PATHTYPE_SYMLINK, + APPFS_PATHTYPE_SOCKET, + APPFS_PATHTYPE_FIFO, } appfs_pathtype_t; /* * AppFS Path Information: * Completely describes a specific path, how it should be returned to @@ -501,10 +503,14 @@ memcpy(pathinfo->typeinfo.symlink.source, attr_value_str, attr_value_int); } } break; + case 'p': /* pipe/fifo */ + break; + case 'S': /* UNIX domain socket */ + break; default: return(-EIO); } Tcl_DictObjGet(interp, attrs_dict, attr_key_packaged, &attr_value); @@ -522,10 +528,36 @@ pathinfo->time = 0; } return(0); } + +static char *appfs_prepare_to_create(const char *path) { + Tcl_Interp *interp; + const char *real_path; + int tcl_ret; + + interp = appfs_TclInterp(); + if (interp == NULL) { + return(NULL); + } + + 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_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); + + return(NULL); + } + + real_path = Tcl_GetStringResult(interp); + if (real_path == NULL) { + return(NULL); + } + + return(strdup(real_path)); +} static int appfs_fuse_readlink(const char *path, char *buf, size_t size) { struct appfs_pathinfo pathinfo; int retval = 0; @@ -592,12 +624,14 @@ case APPFS_PATHTYPE_SYMLINK: stbuf->st_mode = S_IFLNK | 0555; stbuf->st_nlink = 1; stbuf->st_size = pathinfo.typeinfo.symlink.size; break; + case APPFS_PATHTYPE_SOCKET: + case APPFS_PATHTYPE_FIFO: case APPFS_PATHTYPE_INVALID: - retval = -EIO; + retval = -ENOENT; break; } if (pathinfo.packaged) { @@ -751,10 +785,57 @@ write_ret = write(fi->fh, buf, size); return(write_ret); } + +static int appfs_fuse_mknod(const char *path, mode_t mode, dev_t device) { + char *real_path; + int mknod_ret; + + if ((mode & S_IFCHR) == S_IFCHR) { + return(-EPERM); + } + + if ((mode & S_IFBLK) == S_IFBLK) { + return(-EPERM); + } + + real_path = appfs_prepare_to_create(path); + if (real_path == NULL) { + return(-EIO); + } + + mknod_ret = mknod(real_path, mode, device); + + free(real_path); + + if (mknod_ret != 0) { + return(errno * -1); + } + + return(0); +} + +static int appfs_fuse_create(const char *path, mode_t mode, struct fuse_file_info *fi) { + int fd; + int chmod_ret; + + fd = appfs_fuse_open(path, fi); + if (fd < 0) { + return(fd); + } + + chmod_ret = fchmod(fd, mode); + if (chmod_ret != 0) { + close(fd); + + return(-EIO); + } + + return(fd); +} /* * SQLite3 mode: Execute raw SQL and return success or failure */ static int appfs_sqlite3(const char *sql) { @@ -843,11 +924,13 @@ .readdir = appfs_fuse_readdir, .readlink = appfs_fuse_readlink, .open = appfs_fuse_open, .release = appfs_fuse_close, .read = appfs_fuse_read, - .write = appfs_fuse_write + .write = appfs_fuse_write, + .mknod = appfs_fuse_mknod, + .create = appfs_fuse_create, }; /* * FUSE option parsing callback */