Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,9 +1,10 @@ CPPFLAGS := -I. -DUSE_TCL_STUBS=1 -DXVFS_MODE_FLEXIBLE CFLAGS := -fPIC -g3 -ggdb3 -Wall LDFLAGS := LIBS := -ltclstub8.6 +TCLSH := tclsh all: example.so example.c: $(shell find example -type f) $(shell find lib -type f) xvfs.c.rvt xvfs-create Makefile ./xvfs-create --directory example --name example > example.c.new @@ -14,14 +15,18 @@ example.so: example.o Makefile $(CC) $(CFLAGS) $(LDFLAGS) -shared -o example.so example.o $(LIBS) test: example.so - echo 'if {[catch { load ./example.so Xvfs_example; source //xvfs:/example/main.tcl }]} { puts stderr $$::errorInfo; exit 1 }; exit 0' | tclsh + rm -f __test__.tcl + echo 'if {[catch { load ./example.so Xvfs_example; source //xvfs:/example/main.tcl }]} { puts stderr $$::errorInfo; exit 1 }; exit 0' > __test__.tcl + $(GDB) $(TCLSH) __test__.tcl + rm -f __test__.tcl clean: rm -f example.c example.c.new rm -f example.so example.o + rm -f __test__.tcl distclean: clean .PHONY: all clean distclean test Index: example/main.tcl ================================================================== --- example/main.tcl +++ example/main.tcl @@ -1,6 +1,8 @@ -set file "//xvfs:/example/foo" +set dir "//xvfs:/example" +set dirNative [file join [pwd] example] +set file "${dir}/foo" set fd [open $file] seek $fd 0 end seek $fd -1 current set check [read $fd 1] @@ -46,6 +48,63 @@ error "EXPECTED [lsort -integer $output], GOT $output" } close $fd update idle + +proc glob_verify {args} { + set rv [glob -nocomplain -directory $::dir {*}$args] + set verify [glob -nocomplain -directory $::dirNative {*}$args] + + if {[llength $rv] != [llength $verify]} { + error "VERIFY FAILED: glob ... $args ($rv versus $verify)" + } + + return $rv +} + +set check [glob_verify *] +if {[llength $check] < 2} { + error "EXPECTED >=2, GOT [llength $check] ($check)" +} + +set check [glob_verify f*] +if {[llength $check] != 1} { + error "EXPECTED 1, GOT [llength $check] ($check)" +} + +set check [glob_verify ./f*] +if {[llength $check] != 1} { + error "EXPECTED 1, GOT [llength $check] ($check)" +} + +set check [glob_verify -type f ./f*] +if {[llength $check] != 1} { + error "EXPECTED 1, GOT [llength $check] ($check)" +} + +set check [glob_verify -type d ./f*] +if {[llength $check] != 0} { + error "EXPECTED 0, GOT [llength $check] ($check)" +} + +set check [glob_verify x*] +if {[llength $check] != 0} { + error "EXPECTED 0, GOT [llength $check] ($check)" +} + +set check [glob_verify lib/*] +if {[llength $check] != 1} { + error "EXPECTED 1, GOT [llength $check] ($check)" +} + +set check [lindex $check 0] +if {![string match $dir/* $check]} { + error "EXPECTED \"$dir/*\", GOT $check" +} + +set check [glob_verify -type d *] +if {[llength $check] != 1} { + error "EXPECTED 1, GOT [llength $check] ($check)" +} + puts "ALL TESTS PASSED" Index: xvfs-core.c ================================================================== --- xvfs-core.c +++ xvfs-core.c @@ -26,10 +26,11 @@ /* * Internal Core Utilities */ static const char *xvfs_relativePath(Tcl_Obj *path, struct xvfs_tclfs_instance_info *info) { const char *pathStr, *rootStr; + const char *pathFinal; int pathLen, rootLen; pathStr = Tcl_GetStringFromObj(path, &pathLen); rootStr = Tcl_GetStringFromObj(info->mountpoint, &rootLen); @@ -48,17 +49,25 @@ /* XXX:TODO: Should this use the native OS path separator ? */ if (pathStr[rootLen] != '/') { return(NULL); } - return(pathStr + rootLen + 1); + pathFinal = pathStr + rootLen + 1; + pathLen -= rootLen + 1; + + if (pathLen == 1 && memcmp(pathFinal, ".", 1) == 0) { + return(""); + } + + while (pathLen >= 2 && memcmp(pathFinal, "./", 2) == 0) { + pathFinal += 2; + pathLen -= 2; + } + + return(pathFinal); } -#if 0 -/* - * Currently unused - */ static const char *xvfs_perror(int xvfs_error) { if (xvfs_error >= 0) { return("Not an error"); } @@ -71,15 +80,16 @@ return("Is a directory"); case XVFS_RV_ERR_ENOTDIR: return("Not a directory"); case XVFS_RV_ERR_EFAULT: return("Bad address"); + case XVFS_RV_ERR_INTERNAL: + return("Internal error"); default: return("Unknown error"); } } -#endif static int xvfs_errorToErrno(int xvfs_error) { if (xvfs_error >= 0) { return(0); } @@ -93,10 +103,12 @@ return(EISDIR); case XVFS_RV_ERR_ENOTDIR: return(ENOTDIR); case XVFS_RV_ERR_EFAULT: return(EFAULT); + case XVFS_RV_ERR_INTERNAL: + return(EINVAL); default: return(ERANGE); } } @@ -399,10 +411,122 @@ return(NULL); } return(xvfs_tclfs_openChannel(Tcl_NewStringObj(pathStr, -1), instanceInfo)); } + +static int xvfs_tclfs_verifyType(Tcl_Obj *path, Tcl_GlobTypeData *types, struct xvfs_tclfs_instance_info *instanceInfo) { + const char *pathStr; + Tcl_StatBuf fileInfo; + int statRetVal; + + statRetVal = xvfs_tclfs_stat(path, &fileInfo, instanceInfo); + if (statRetVal != 0) { + return(0); + } + + if (!types) { + return(1); + } + + if (types->perm != TCL_GLOB_PERM_RONLY) { + if (types->perm & (TCL_GLOB_PERM_W | TCL_GLOB_PERM_X | TCL_GLOB_PERM_HIDDEN)) { + return(0); + } + } + + if (types->type & (TCL_GLOB_TYPE_BLOCK | TCL_GLOB_TYPE_CHAR | TCL_GLOB_TYPE_PIPE | TCL_GLOB_TYPE_SOCK | TCL_GLOB_TYPE_LINK)) { + return(0); + } + + if ((types->type & TCL_GLOB_TYPE_DIR) == TCL_GLOB_TYPE_DIR) { + if (!(fileInfo.st_mode & 040000)) { + return(0); + } + } + + if ((types->type & TCL_GLOB_TYPE_FILE) == TCL_GLOB_TYPE_FILE) { + if (!(fileInfo.st_mode & 0100000)) { + return(0); + } + } + + if ((types->type & TCL_GLOB_TYPE_MOUNT) == TCL_GLOB_TYPE_MOUNT) { + pathStr = xvfs_relativePath(path, instanceInfo); + if (!pathStr) { + return(0); + } + + if (strlen(pathStr) != 0) { + return(0); + } + } + + return(1); +} + +static int xvfs_tclfs_matchInDir(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *path, const char *pattern, Tcl_GlobTypeData *types, struct xvfs_tclfs_instance_info *instanceInfo) { + const char *pathStr; + const char **children, *child; + Tcl_WideInt childrenCount, idx; + Tcl_Obj *childObj; + int tclRetVal; + + if (pattern == NULL) { + if (xvfs_tclfs_verifyType(path, types, instanceInfo)) { + return(TCL_OK); + } + + return(TCL_ERROR); + } + + pathStr = xvfs_relativePath(path, instanceInfo); + if (!pathStr) { + if (interp) { + Tcl_SetResult(interp, (char *) xvfs_perror(XVFS_RV_ERR_ENOENT), NULL); + } + + return(TCL_ERROR); + } + + childrenCount = 0; + children = instanceInfo->fsInfo->getChildrenProc(pathStr, &childrenCount); + if (childrenCount < 0) { + if (interp) { + Tcl_SetResult(interp, (char *) xvfs_perror(childrenCount), NULL); + } + + return(TCL_ERROR); + } + + for (idx = 0; idx < childrenCount; idx++) { + child = children[idx]; + + if (!Tcl_StringMatch(child, pattern)) { + continue; + } + + childObj = Tcl_DuplicateObj(path); + Tcl_AppendStringsToObj(childObj, "/", child, NULL); + Tcl_IncrRefCount(childObj); + + if (!xvfs_tclfs_verifyType(childObj, types, instanceInfo)) { + Tcl_DecrRefCount(childObj); + + continue; + } + + tclRetVal = Tcl_ListObjAppendElement(interp, resultPtr, childObj); + Tcl_DecrRefCount(childObj); + + if (tclRetVal != TCL_OK) { + return(tclRetVal); + } + } + + return(TCL_OK); +} #endif /* XVFS_MODE_SERVER || XVFS_MODE_STANDALONE || XVFS_MODE_FLEIXBLE */ #if defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE) /* * Tcl_Filesystem handlers for the standalone implementation @@ -421,10 +545,14 @@ } static Tcl_Channel xvfs_tclfs_standalone_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) { return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, &xvfs_tclfs_standalone_info)); } + +static int xvfs_tclfs_standalone_matchInDir(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) { + return(xvfs_tclfs_matchInDir(interp, resultPtr, pathPtr, pattern, types, &xvfs_tclfs_standalone_info)); +} /* * There are three (3) modes of operation for Xvfs_Register: * 1. standalone -- We register our own Tcl_Filesystem * and handle requests under `//xvfs:/` @@ -473,11 +601,11 @@ xvfs_tclfs_standalone_fs.filesystemPathTypeProc = NULL; xvfs_tclfs_standalone_fs.filesystemSeparatorProc = NULL; xvfs_tclfs_standalone_fs.statProc = xvfs_tclfs_standalone_stat; xvfs_tclfs_standalone_fs.accessProc = NULL; xvfs_tclfs_standalone_fs.openFileChannelProc = xvfs_tclfs_standalone_openFileChannel; - xvfs_tclfs_standalone_fs.matchInDirectoryProc = NULL; /* XXX:TODO */ + xvfs_tclfs_standalone_fs.matchInDirectoryProc = xvfs_tclfs_standalone_matchInDir; xvfs_tclfs_standalone_fs.utimeProc = NULL; xvfs_tclfs_standalone_fs.linkProc = NULL; xvfs_tclfs_standalone_fs.listVolumesProc = xvfs_tclfs_standalone_listVolumes; xvfs_tclfs_standalone_fs.fileAttrStringsProc = NULL; xvfs_tclfs_standalone_fs.fileAttrsGetProc = NULL; Index: xvfs-core.h ================================================================== --- xvfs-core.h +++ xvfs-core.h @@ -29,10 +29,11 @@ #define XVFS_RV_ERR_ENOENT (-8192) #define XVFS_RV_ERR_EINVAL (-8193) #define XVFS_RV_ERR_EISDIR (-8194) #define XVFS_RV_ERR_ENOTDIR (-8195) #define XVFS_RV_ERR_EFAULT (-8196) +#define XVFS_RV_ERR_INTERNAL (-16383) #define XVFS_REGISTER_INTERFACE(name) int name(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo); #if defined(XVFS_MODE_STANDALONE) /* Index: xvfs.c.rvt ================================================================== --- xvfs.c.rvt +++ xvfs.c.rvt @@ -192,16 +192,16 @@ statBuf->st_ctime = 0; statBuf->st_mtime = 0; statBuf->st_blksize = XVFS_FILE_BLOCKSIZE; if (fileInfo->type == XVFS_FILE_TYPE_REG) { - statBuf->st_mode = 0400; + statBuf->st_mode = 0100400; statBuf->st_nlink = 1; statBuf->st_size = fileInfo->size; statBuf->st_blocks = (fileInfo->size + statBuf->st_blksize - 1) / statBuf->st_blksize; } else if (fileInfo->type == XVFS_FILE_TYPE_DIR) { - statBuf->st_mode = 0500; + statBuf->st_mode = 040500; statBuf->st_nlink = fileInfo->size; statBuf->st_size = fileInfo->size; statBuf->st_blocks = 1; }