Tcl pathInFilesystemProc get current filesystem

63 Views Asked by At

When creating a vfs using the tcl api how do you get the current filesystem in Tcl_Filesystem.pathInFilesystemProc

My code looks something like this:

typedef struct {
    FILE* dbFile;
    /*...*/

} FSBackend;

void createFS(const char* dbFile)
{

    FSBackend* fsback = (FSBackend*)malloc(sizeof(FSBackend));
    initDb(fsback,dbFile);

    Tcl_Filesystem tfs;

    tfs.typeName="Db Fs";
    tfs.structureLength = sizeof(Tcl_Filesystem);
    tfs.version = TCL_FILESYSTEM_VERSION_1;
    tfs.pathInFilesystemProc = inFsProc;

    /*...*/

    Tcl_FSRegister((void*),tfs);
}

int inFsProc(Tcl_Obj* pathPtr,ClientData* cd)
{
    /* How do I get my FSBackend struct here */
    FSBackend* bk = /* ? */

    int len;

    const char* searchPath = Tcl_GetStringFromObj(pathPtr,&len);

    char* foundPath = findFileInDb(searchPath,bk);

    if (foundPath == 0) {
        return -1;
    }

    cd = buildInternalRep(foundPath,bk);
    return TCL_OK;
}

/**
 ...
*/

int main()
{
    createFS("db1.db");
    createFS("db2.db");
}

How do I, in inFsProc get back the struct I passed into Tcl_FSRegister?

The Tcl_FSData function says it can get it but I would then need to get a Tcl_Filesystem pointer

1

There are 1 best solutions below

3
Donal Fellows On BEST ANSWER

That's a weird one. The clientData handle there is not used to specify a mount point, but rather a separate capability of the filesystem type. Tcl's internal use of Tcl_FSRegister doesn't use it at all. The code which is as close as anything to a canonical use of it is the tclvfs package.

https://github.com/tcl-mirror/tclvfs/blob/master/generic/vfs.c#L385 shows us the use:

static void 
Vfs_RegisterWithInterp(interp)
    Tcl_Interp *interp;
{
    ClientData vfsAlreadyRegistered;
    /* 
     * We need to know if the interpreter is deleted, so we can
     * remove all interp-specific mounts.
     */
    Tcl_SetAssocData(interp, "vfs::inUse", (Tcl_InterpDeleteProc*) 
             Vfs_UnregisterWithInterp, (ClientData) 1);
    /* 
     * Perform one-off registering of our filesystem if that
     * has not happened before.
     */
    vfsAlreadyRegistered = Tcl_FSData(&vfsFilesystem);
    if (vfsAlreadyRegistered == NULL) {
        Tcl_FSRegister((ClientData)1, &vfsFilesystem);
        Tcl_CreateExitHandler(VfsExitProc, (ClientData)NULL);
        Tcl_CreateThreadExitHandler(VfsThreadExitProc, NULL);
    }
}

As you can see, the clientData there is really just being used as a marker so the code knows whether to do one-time initialisation.

To discover what the mount mapping is, you'll need to keep internal structures. You're strongly recommended to make the Tcl_Filesystem structure instance itself be global (or rather static at file scope) in your code.