Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -17,13 +17,14 @@ example.so: example.o xvfs-core.o Makefile $(CC) $(CFLAGS) $(LDFLAGS) -shared -o example.so example.o xvfs-core.o $(LIBS) test: example.so - echo 'if {[catch { load ./example.so Xvfs_example; source //xvfs:/main.tcl }]} { puts stderr $$::errorInfo; exit 1 }; exit 0' | tclsh + echo 'if {[catch { load ./example.so Xvfs_example; source //xvfs:/example/main.tcl }]} { puts stderr $$::errorInfo; exit 1 }; exit 0' | tclsh clean: rm -f example.so example.o example.c + rm -f xvfs-core.o distclean: clean .PHONY: all clean distclean test Index: xvfs-core.c ================================================================== --- xvfs-core.c +++ xvfs-core.c @@ -1,18 +1,102 @@ #include +#include #include -static int xvfs_tclvfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) { - return(TCL_ERROR); +#define XVFS_ROOT_MOUNTPOINT "//xvfs:/" + +struct xvfs_tclfs_instance_info { + struct Xvfs_FSInfo *fsInfo; + Tcl_Obj *mountpoint; +}; +static struct xvfs_tclfs_instance_info xvfs_tclfs_standalone_info; + +/* + * Internal Core Utilities + */ +static const char *xvfs_relativePath(Tcl_Obj *path, struct xvfs_tclfs_instance_info *info) { + const char *pathStr, *rootStr; + int pathLen, rootLen; + + pathStr = Tcl_GetStringFromObj(path, &pathLen); + rootStr = Tcl_GetStringFromObj(info->mountpoint, &rootLen); + + if (pathLen < rootLen) { + return(NULL); + } + + if (memcmp(pathStr, rootStr, rootLen) != 0) { + return(NULL); + } + + if (pathLen == rootLen) { + return(""); + } + + /* XXX:TODO: Should this use the native OS path separator ? */ + if (pathStr[rootLen] != '/') { + return(NULL); + } + + return(pathStr + rootLen + 1); +} + +/* + * Internal Tcl_Filesystem functions, with the appropriate instance info + */ +static int xvfs_tclfs_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr, struct xvfs_tclfs_instance_info *instanceInfo) { + const char *relativePath; + + relativePath = xvfs_relativePath(path, instanceInfo); + if (!relativePath) { + return(-1); + } + + return(TCL_OK); +} + +static int xvfs_tclfs_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf, struct xvfs_tclfs_instance_info *instanceInfo) { + const char *pathStr; + int retval; + + pathStr = xvfs_relativePath(path, instanceInfo); + + retval = instanceInfo->fsInfo->getInfoProc(pathStr, statBuf); + + return(retval); +} + +static Tcl_Obj *xvfs_tclfs_listVolumes(struct xvfs_tclfs_instance_info *instanceInfo) { + return(NULL); +} + +static Tcl_Channel xvfs_tclfs_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions, struct xvfs_tclfs_instance_info *instanceInfo) { + const char *pathStr; + + pathStr = xvfs_relativePath(path, instanceInfo); +fprintf(stderr, "Called open(%s)!\n", pathStr); + + return(NULL); +} + +/* + * Tcl_Filesystem handlers for the standalone implementation + */ +static int xvfs_tclfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) { + return(xvfs_tclfs_pathInFilesystem(path, dataPtr, &xvfs_tclfs_standalone_info)); +} + +static int xvfs_tclfs_standalone_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) { + return(xvfs_tclfs_stat(path, statBuf, &xvfs_tclfs_standalone_info)); } -static int xvfs_tclvfs_normalizePath(Tcl_Interp *interp, Tcl_Obj *path, int nextCheckpoint) { - return(TCL_ERROR); +static Tcl_Obj *xvfs_tclfs_standalone_listVolumes(void) { + return(xvfs_tclfs_listVolumes(&xvfs_tclfs_standalone_info)); } -static Tcl_Obj *xvfs_tclvfs_listVolumes() { - return(NULL); +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)); } /* * There are three (3) modes of operation for Xvfs_Register: * 1. standalone -- We register our own Tcl_Filesystem @@ -25,13 +109,22 @@ * process at runtime, if found do #2, otherwise * fallback to #1 * */ static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) { - Tcl_Filesystem *xvfsInfo; + Tcl_Filesystem *xvfs_tclfs_Info; int tcl_ret; + static int registered = 0; + /* + * Ensure this instance is not already registered + */ + if (registered) { + return(TCL_OK); + } + registered = 1; + /* * In standalone mode, we only support the same protocol we are * compiling for. */ if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) { @@ -39,51 +132,55 @@ Tcl_SetResult(interp, "Protocol mismatch", NULL); } return(TCL_ERROR); } - xvfsInfo = (Tcl_Filesystem *) Tcl_AttemptAlloc(sizeof(*xvfsInfo)); - if (!xvfsInfo) { + xvfs_tclfs_Info = (Tcl_Filesystem *) Tcl_AttemptAlloc(sizeof(*xvfs_tclfs_Info)); + if (!xvfs_tclfs_Info) { if (interp) { Tcl_SetResult(interp, "Unable to allocate Tcl_Filesystem object", NULL); } return(TCL_ERROR); } - xvfsInfo->typeName = "xvfs"; - xvfsInfo->structureLength = sizeof(*xvfsInfo); - xvfsInfo->version = TCL_FILESYSTEM_VERSION_1; - xvfsInfo->pathInFilesystemProc = xvfs_tclvfs_standalone_pathInFilesystem; - xvfsInfo->dupInternalRepProc = NULL; - xvfsInfo->freeInternalRepProc = NULL; - xvfsInfo->internalToNormalizedProc = NULL; - xvfsInfo->createInternalRepProc = NULL; - xvfsInfo->normalizePathProc = xvfs_tclvfs_normalizePath; - xvfsInfo->filesystemPathTypeProc = NULL; - xvfsInfo->filesystemSeparatorProc = NULL; - xvfsInfo->statProc = NULL; - xvfsInfo->accessProc = NULL; - xvfsInfo->openFileChannelProc = NULL; - xvfsInfo->matchInDirectoryProc = NULL; - xvfsInfo->utimeProc = NULL; - xvfsInfo->linkProc = NULL; - xvfsInfo->listVolumesProc = xvfs_tclvfs_listVolumes; - xvfsInfo->fileAttrStringsProc = NULL; - xvfsInfo->fileAttrsGetProc = NULL; - xvfsInfo->fileAttrsSetProc = NULL; - xvfsInfo->createDirectoryProc = NULL; - xvfsInfo->removeDirectoryProc = NULL; - xvfsInfo->deleteFileProc = NULL; - xvfsInfo->copyFileProc = NULL; - xvfsInfo->renameFileProc = NULL; - xvfsInfo->copyDirectoryProc = NULL; - xvfsInfo->lstatProc = NULL; - xvfsInfo->loadFileProc = NULL; - xvfsInfo->getCwdProc = NULL; - xvfsInfo->chdirProc = NULL; - - tcl_ret = Tcl_FSRegister(NULL, xvfsInfo); + xvfs_tclfs_Info->typeName = strdup("xvfs"); + xvfs_tclfs_Info->structureLength = sizeof(*xvfs_tclfs_Info); + xvfs_tclfs_Info->version = TCL_FILESYSTEM_VERSION_1; + xvfs_tclfs_Info->pathInFilesystemProc = xvfs_tclfs_standalone_pathInFilesystem; + xvfs_tclfs_Info->dupInternalRepProc = NULL; + xvfs_tclfs_Info->freeInternalRepProc = NULL; + xvfs_tclfs_Info->internalToNormalizedProc = NULL; + xvfs_tclfs_Info->createInternalRepProc = NULL; + xvfs_tclfs_Info->normalizePathProc = NULL; + xvfs_tclfs_Info->filesystemPathTypeProc = NULL; + xvfs_tclfs_Info->filesystemSeparatorProc = NULL; + xvfs_tclfs_Info->statProc = xvfs_tclfs_standalone_stat; + xvfs_tclfs_Info->accessProc = NULL; + xvfs_tclfs_Info->openFileChannelProc = xvfs_tclfs_standalone_openFileChannel; + xvfs_tclfs_Info->matchInDirectoryProc = NULL; + xvfs_tclfs_Info->utimeProc = NULL; + xvfs_tclfs_Info->linkProc = NULL; + xvfs_tclfs_Info->listVolumesProc = xvfs_tclfs_standalone_listVolumes; + xvfs_tclfs_Info->fileAttrStringsProc = NULL; + xvfs_tclfs_Info->fileAttrsGetProc = NULL; + xvfs_tclfs_Info->fileAttrsSetProc = NULL; + xvfs_tclfs_Info->createDirectoryProc = NULL; + xvfs_tclfs_Info->removeDirectoryProc = NULL; + xvfs_tclfs_Info->deleteFileProc = NULL; + xvfs_tclfs_Info->copyFileProc = NULL; + xvfs_tclfs_Info->renameFileProc = NULL; + xvfs_tclfs_Info->copyDirectoryProc = NULL; + xvfs_tclfs_Info->lstatProc = NULL; + xvfs_tclfs_Info->loadFileProc = NULL; + xvfs_tclfs_Info->getCwdProc = NULL; + xvfs_tclfs_Info->chdirProc = NULL; + + xvfs_tclfs_standalone_info.fsInfo = fsInfo; + xvfs_tclfs_standalone_info.mountpoint = Tcl_NewObj(); + Tcl_AppendStringsToObj(xvfs_tclfs_standalone_info.mountpoint, XVFS_ROOT_MOUNTPOINT, fsInfo->name, NULL); + + tcl_ret = Tcl_FSRegister(NULL, xvfs_tclfs_Info); if (tcl_ret != TCL_OK) { if (interp) { Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL); } Index: xvfs-core.h ================================================================== --- xvfs-core.h +++ xvfs-core.h @@ -5,16 +5,18 @@ #define XVFS_PROTOCOL_VERSION 1 typedef const char **(*xvfs_proc_getChildren_t)(const char *path, Tcl_WideInt *count); typedef const unsigned char *(*xvfs_proc_getData_t)(const char *path, Tcl_WideInt start, Tcl_WideInt *length); +typedef int (*xvfs_proc_getInfo_t)(const char *path, Tcl_StatBuf *statBuf); struct Xvfs_FSInfo { int protocolVersion; - const char *fsName; + const char *name; xvfs_proc_getChildren_t getChildrenProc; xvfs_proc_getData_t getDataProc; + xvfs_proc_getInfo_t getInfoProc; }; int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo); #endif Index: xvfs.c.rvt ================================================================== --- xvfs.c.rvt +++ xvfs.c.rvt @@ -1,9 +1,10 @@ #include #include #include #include +#include #define XVFS_NAME_LOOKUP_ERROR (-1) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) typedef enum { @@ -129,18 +130,67 @@ /* * Return the data */ return(fileInfo->data.fileContents + start); } + +static int xvfs__getInfo(const char *path, Tcl_StatBuf *statBuf) { + struct xvfs_file_data *fileInfo; + long inode; + + /* + * Validate input parameters + */ + if (!statBuf) { + return(-1); + } + + /* + * Get the inode from the lookup function + */ + inode = xvfs__nameToIndex(path); + if (inode == XVFS_NAME_LOOKUP_ERROR) { + return(-1); + } + + fileInfo = &xvfs__data[inode]; + + statBuf->st_dev = 0; + statBuf->st_rdev = 0; + statBuf->st_ino = inode; + statBuf->st_uid = -1; + statBuf->st_gid = -1; + statBuf->st_atime = 0; + statBuf->st_ctime = 0; + statBuf->st_mtime = 0; + statBuf->st_blksize = 1024; + + if (fileInfo->type == XVFS_FILE_TYPE_REG) { + statBuf->st_mode = 0400; + 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_nlink = fileInfo->size; + statBuf->st_size = fileInfo->size; + statBuf->st_blocks = 1; + } + + return(0); +} + + +static struct Xvfs_FSInfo xvfs__fsInfo = { + .protocolVersion = XVFS_PROTOCOL_VERSION, + .name = "", + .getChildrenProc = xvfs__getChildren, + .getDataProc = xvfs__getData, + .getInfoProc = xvfs__getInfo +}; int Xvfs__Init(Tcl_Interp *interp) { - struct Xvfs_FSInfo fsInfo = { - .protocolVersion = XVFS_PROTOCOL_VERSION, - .fsName = "", - .getChildrenProc = xvfs__getChildren, - .getDataProc = xvfs__getData - }; int register_ret; #ifdef USE_TCL_STUBS const char *tclInitStubs_ret; /* Initialize Stubs */ @@ -148,12 +198,12 @@ if (!tclInitStubs_ret) { return(TCL_ERROR); } #endif - register_ret = Xvfs_Register(interp, &fsInfo); + register_ret = Xvfs_Register(interp, &xvfs__fsInfo); if (register_ret != TCL_OK) { return(register_ret); } return(TCL_OK); }