Lines of
xvfs-core.c
from check-in 149aa89b7d
that are changed by the sequence of edits moving toward
check-in 38bed7cee0:
1: #include <xvfs-core.h>
2: #include <string.h>
3: #include <tcl.h>
4:
5: #if defined(XVFS_MODE_FLEXIBLE) || defined(XVFS_MODE_SERVER)
6: #define XVFS_INTERNAL_SERVER_MAGIC "\xD4\xF3\x05\x96\x25\xCF\xAF\xFE"
7: #define XVFS_INTERNAL_SERVER_MAGIC_LEN 8
8:
9: struct xvfs_tclfs_server_info {
10: char magic[XVFS_INTERNAL_SERVER_MAGIC_LEN];
11: int (*registerProc)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
12: };
13: #endif /* XVFS_MODE_FLEXIBLE || XVFS_MODE_SERVER */
14:
15: #if defined(XVFS_MODE_SERVER) || defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
16: #define XVFS_ROOT_MOUNTPOINT "//xvfs:/"
17:
18: struct xvfs_tclfs_instance_info {
19: struct Xvfs_FSInfo *fsInfo;
20: Tcl_Obj *mountpoint;
21: };
22:
23: /*
24: * Internal Core Utilities
25: */
26: static const char *xvfs_relativePath(Tcl_Obj *path, struct xvfs_tclfs_instance_info *info) {
27: const char *pathStr, *rootStr;
28: int pathLen, rootLen;
149aa89b7d 2019-09-13 29:
30: pathStr = Tcl_GetStringFromObj(path, &pathLen);
31: rootStr = Tcl_GetStringFromObj(info->mountpoint, &rootLen);
149aa89b7d 2019-09-13 32:
33: if (pathLen < rootLen) {
34: return(NULL);
35: }
149aa89b7d 2019-09-13 36:
37: if (memcmp(pathStr, rootStr, rootLen) != 0) {
38: return(NULL);
39: }
149aa89b7d 2019-09-13 40:
41: if (pathLen == rootLen) {
42: return("");
43: }
44:
45: /* XXX:TODO: Should this use the native OS path separator ? */
46: if (pathStr[rootLen] != '/') {
47: return(NULL);
48: }
149aa89b7d 2019-09-13 49:
50: return(pathStr + rootLen + 1);
51: }
52:
53: static const char *xvfs_perror(int xvfs_error) {
54: if (xvfs_error >= 0) {
55: return("Not an error");
56: }
57:
58: switch (xvfs_error) {
59: case XVFS_RV_ERR_ENOENT:
60: return("No such file or directory");
61: case XVFS_RV_ERR_EINVAL:
62: return("Invalid argument");
63: case XVFS_RV_ERR_EISDIR:
64: return("Is a directory");
65: case XVFS_RV_ERR_ENOTDIR:
66: return("Not a directory");
67: case XVFS_RV_ERR_EFAULT:
68: return("Bad address");
69: default:
70: return("Unknown error");
71: }
72: }
73:
74: /*
75: * Internal Tcl_Filesystem functions, with the appropriate instance info
76: */
77: static int xvfs_tclfs_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr, struct xvfs_tclfs_instance_info *instanceInfo) {
78: const char *relativePath;
149aa89b7d 2019-09-13 79:
80: relativePath = xvfs_relativePath(path, instanceInfo);
81: if (!relativePath) {
82: return(-1);
83: }
149aa89b7d 2019-09-13 84:
85: return(TCL_OK);
86: }
87:
88: static int xvfs_tclfs_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf, struct xvfs_tclfs_instance_info *instanceInfo) {
89: const char *pathStr;
90: int retval;
91:
92: pathStr = xvfs_relativePath(path, instanceInfo);
149aa89b7d 2019-09-13 93:
94: retval = instanceInfo->fsInfo->getStatProc(pathStr, statBuf);
95: if (retval < 0) {
96: retval = -1;
97: }
149aa89b7d 2019-09-13 98:
99: return(retval);
100: }
101:
102: static Tcl_Obj *xvfs_tclfs_listVolumes(struct xvfs_tclfs_instance_info *instanceInfo) {
103: return(NULL);
104: }
105:
106: static Tcl_Channel xvfs_tclfs_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions, struct xvfs_tclfs_instance_info *instanceInfo) {
107: const char *pathStr;
149aa89b7d 2019-09-13 108: Tcl_WideInt length;
149aa89b7d 2019-09-13 109: const char *data;
110:
111: pathStr = xvfs_relativePath(path, instanceInfo);
112:
149aa89b7d 2019-09-13 113: /*
149aa89b7d 2019-09-13 114: * XXX:TODO: Do something to create the Tcl_Channel we
149aa89b7d 2019-09-13 115: * need to return here
149aa89b7d 2019-09-13 116: */
117:
149aa89b7d 2019-09-13 118: return(NULL);
119: }
120: #endif /* XVFS_MODE_SERVER || XVFS_MODE_STANDALONE || XVFS_MODE_FLEIXBLE */
121:
122: #if defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
123: /*
124: * Tcl_Filesystem handlers for the standalone implementation
125: */
126: static struct xvfs_tclfs_instance_info xvfs_tclfs_standalone_info;
127: static int xvfs_tclfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) {
128: return(xvfs_tclfs_pathInFilesystem(path, dataPtr, &xvfs_tclfs_standalone_info));
129: }
130:
131: static int xvfs_tclfs_standalone_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) {
132: return(xvfs_tclfs_stat(path, statBuf, &xvfs_tclfs_standalone_info));
133: }
134:
135: static Tcl_Obj *xvfs_tclfs_standalone_listVolumes(void) {
136: return(xvfs_tclfs_listVolumes(&xvfs_tclfs_standalone_info));
137: }
138:
139: static Tcl_Channel xvfs_tclfs_standalone_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) {
140: return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, &xvfs_tclfs_standalone_info));
141: }
142:
143: /*
144: * There are three (3) modes of operation for Xvfs_Register:
145: * 1. standalone -- We register our own Tcl_Filesystem
146: * and handle requests under `//xvfs:/<fsName>`
147: * 2. client -- A single Tcl_Filesystem is registered for the
148: * interp to handle requests under `//xvfs:/` which
149: * then dispatches to the appropriate registered
150: * handler
151: * 3. flexible -- Attempts to find a core Xvfs instance for the
152: * process at runtime, if found do #2, otherwise
153: * fallback to #1
154: *
155: */
156: static Tcl_Filesystem xvfs_tclfs_standalone_fs;
157: static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
158: int tcl_ret;
159: static int registered = 0;
149aa89b7d 2019-09-13 160:
161: /*
162: * Ensure this instance is not already registered
163: */
164: if (registered) {
165: return(TCL_OK);
166: }
167: registered = 1;
168:
169: /*
170: * In standalone mode, we only support the same protocol we are
171: * compiling for.
172: */
173: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
174: if (interp) {
175: Tcl_SetResult(interp, "Protocol mismatch", NULL);
176: }
177: return(TCL_ERROR);
178: }
149aa89b7d 2019-09-13 179:
180: xvfs_tclfs_standalone_fs.typeName = "xvfs";
181: xvfs_tclfs_standalone_fs.structureLength = sizeof(xvfs_tclfs_standalone_fs);
182: xvfs_tclfs_standalone_fs.version = TCL_FILESYSTEM_VERSION_1;
183: xvfs_tclfs_standalone_fs.pathInFilesystemProc = xvfs_tclfs_standalone_pathInFilesystem;
184: xvfs_tclfs_standalone_fs.dupInternalRepProc = NULL;
185: xvfs_tclfs_standalone_fs.freeInternalRepProc = NULL;
186: xvfs_tclfs_standalone_fs.internalToNormalizedProc = NULL;
187: xvfs_tclfs_standalone_fs.createInternalRepProc = NULL;
188: xvfs_tclfs_standalone_fs.normalizePathProc = NULL;
189: xvfs_tclfs_standalone_fs.filesystemPathTypeProc = NULL;
190: xvfs_tclfs_standalone_fs.filesystemSeparatorProc = NULL;
191: xvfs_tclfs_standalone_fs.statProc = xvfs_tclfs_standalone_stat;
192: xvfs_tclfs_standalone_fs.accessProc = NULL;
193: xvfs_tclfs_standalone_fs.openFileChannelProc = xvfs_tclfs_standalone_openFileChannel;
149aa89b7d 2019-09-13 194: xvfs_tclfs_standalone_fs.matchInDirectoryProc = NULL;
195: xvfs_tclfs_standalone_fs.utimeProc = NULL;
196: xvfs_tclfs_standalone_fs.linkProc = NULL;
197: xvfs_tclfs_standalone_fs.listVolumesProc = xvfs_tclfs_standalone_listVolumes;
198: xvfs_tclfs_standalone_fs.fileAttrStringsProc = NULL;
199: xvfs_tclfs_standalone_fs.fileAttrsGetProc = NULL;
200: xvfs_tclfs_standalone_fs.fileAttrsSetProc = NULL;
201: xvfs_tclfs_standalone_fs.createDirectoryProc = NULL;
202: xvfs_tclfs_standalone_fs.removeDirectoryProc = NULL;
203: xvfs_tclfs_standalone_fs.deleteFileProc = NULL;
204: xvfs_tclfs_standalone_fs.copyFileProc = NULL;
205: xvfs_tclfs_standalone_fs.renameFileProc = NULL;
206: xvfs_tclfs_standalone_fs.copyDirectoryProc = NULL;
207: xvfs_tclfs_standalone_fs.lstatProc = NULL;
208: xvfs_tclfs_standalone_fs.loadFileProc = NULL;
209: xvfs_tclfs_standalone_fs.getCwdProc = NULL;
210: xvfs_tclfs_standalone_fs.chdirProc = NULL;
211:
212: xvfs_tclfs_standalone_info.fsInfo = fsInfo;
213: xvfs_tclfs_standalone_info.mountpoint = Tcl_NewObj();
214: Tcl_AppendStringsToObj(xvfs_tclfs_standalone_info.mountpoint, XVFS_ROOT_MOUNTPOINT, fsInfo->name, NULL);
149aa89b7d 2019-09-13 215:
216: tcl_ret = Tcl_FSRegister(NULL, &xvfs_tclfs_standalone_fs);
217: if (tcl_ret != TCL_OK) {
218: if (interp) {
219: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
220: }
149aa89b7d 2019-09-13 221:
222: return(tcl_ret);
223: }
149aa89b7d 2019-09-13 224:
225: return(TCL_OK);
226: }
227: #endif /* XVFS_MODE_STANDALONE || XVFS_MODE_FLEXIBLE */
228:
229: #if defined(XVFS_MODE_FLEXIBLE)
230: static int xvfs_flexible_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
231: ClientData fsHandlerDataRaw;
232: struct xvfs_tclfs_server_info *fsHandlerData;
233: const Tcl_Filesystem *fsHandler;
234: int (*xvfs_register)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
235: Tcl_Obj *rootPathObj;
236:
237: xvfs_register = &xvfs_standalone_register;
238:
239: rootPathObj = Tcl_NewStringObj(XVFS_ROOT_MOUNTPOINT, -1);
240: if (!rootPathObj) {
241: return(xvfs_register(interp, fsInfo));
242: }
243:
244: Tcl_IncrRefCount(rootPathObj);
245: fsHandler = Tcl_FSGetFileSystemForPath(rootPathObj);
246: Tcl_DecrRefCount(rootPathObj);
247:
248: if (!fsHandler) {
249: return(xvfs_register(interp, fsInfo));
250: }
251:
252: fsHandlerDataRaw = Tcl_FSData(fsHandler);
253: if (!fsHandlerDataRaw) {
254: return(xvfs_register(interp, fsInfo));
255: }
256:
257: fsHandlerData = (struct xvfs_tclfs_server_info *) fsHandlerDataRaw;
258:
259: /*
260: * XXX:TODO: What is the chance that the handler for //xvfs:/ hold
261: * client data smaller than XVFS_INTERNAL_SERVER_MAGIC_LEN ?
262: */
263: if (memcmp(fsHandlerData->magic, XVFS_INTERNAL_SERVER_MAGIC, sizeof(fsHandlerData->magic)) == 0) {
264: xvfs_register = fsHandlerData->registerProc;
265: }
266:
267: return(xvfs_register(interp, fsInfo));
268: }
269: #endif /* XVFS_MODE_FLEXIBLE */
270:
271: #if defined(XVFS_MODE_SERVER)
272: int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
273: return(TCL_ERROR);
274: }
275: #endif /* XVFS_MODE_SERVER */