Lines of
xvfs-core.c
from check-in 5ae034e55e
that are changed by the sequence of edits moving toward
check-in d80c88cee0:
1: #include <xvfs-core.h>
2: #include <string.h>
3: #include <sys/stat.h>
4: #include <errno.h>
5: #include <fcntl.h>
6: #include <tcl.h>
7:
8: #if defined(XVFS_MODE_FLEXIBLE) || defined(XVFS_MODE_SERVER)
9: #define XVFS_INTERNAL_SERVER_MAGIC "\xD4\xF3\x05\x96\x25\xCF\xAF\xFE"
10: #define XVFS_INTERNAL_SERVER_MAGIC_LEN 8
11:
12: struct xvfs_tclfs_server_info {
13: char magic[XVFS_INTERNAL_SERVER_MAGIC_LEN];
14: int (*registerProc)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
15: };
16: #endif /* XVFS_MODE_FLEXIBLE || XVFS_MODE_SERVER */
17:
18: #if defined(XVFS_MODE_SERVER) || defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
19: #define XVFS_ROOT_MOUNTPOINT "//xvfs:/"
20:
21: struct xvfs_tclfs_instance_info {
22: struct Xvfs_FSInfo *fsInfo;
23: Tcl_Obj *mountpoint;
24: };
25:
26: /*
27: * Internal Core Utilities
28: */
5ae034e55e 2019-09-14 29: static const char *xvfs_relativePath(Tcl_Obj *path, struct xvfs_tclfs_instance_info *info) {
30: Tcl_Obj *currentDirectory;
5ae034e55e 2019-09-14 31: const char *pathStr, *rootStr;
5ae034e55e 2019-09-14 32: const char *pathFinal;
5ae034e55e 2019-09-14 33: int pathLen, rootLen;
34:
5ae034e55e 2019-09-14 35: rootStr = Tcl_GetStringFromObj(info->mountpoint, &rootLen);
5ae034e55e 2019-09-14 36: pathStr = Tcl_GetStringFromObj(path, &pathLen);
37: if (pathStr[0] != '/') {
38: currentDirectory = Tcl_FSGetCwd(NULL);
39: Tcl_IncrRefCount(currentDirectory);
40:
5ae034e55e 2019-09-14 41: /* XXX:TODO: Free this */
42: path = Tcl_ObjPrintf("%s/%s", Tcl_GetString(currentDirectory), pathStr);
43: Tcl_IncrRefCount(path);
44: Tcl_DecrRefCount(currentDirectory);
5ae034e55e 2019-09-14 45:
5ae034e55e 2019-09-14 46: pathStr = Tcl_GetStringFromObj(path, &pathLen);
5ae034e55e 2019-09-14 47: }
5ae034e55e 2019-09-14 48:
5ae034e55e 2019-09-14 49: if (pathLen < rootLen) {
50: return(NULL);
51: }
52:
53: if (memcmp(pathStr, rootStr, rootLen) != 0) {
54: return(NULL);
55: }
56:
57: if (pathLen == rootLen) {
58: return("");
59: }
60:
61: /* XXX:TODO: Should this use the native OS path separator ? */
62: if (pathStr[rootLen] != '/') {
63: return(NULL);
64: }
65:
66: pathFinal = pathStr + rootLen + 1;
67: pathLen -= rootLen + 1;
68:
69: if (pathLen == 1 && memcmp(pathFinal, ".", 1) == 0) {
70: return("");
71: }
72:
73: while (pathLen >= 2 && memcmp(pathFinal, "./", 2) == 0) {
74: pathFinal += 2;
75: pathLen -= 2;
76: }
77:
78: return(pathFinal);
79: }
80:
81: static const char *xvfs_perror(int xvfs_error) {
82: if (xvfs_error >= 0) {
83: return("Not an error");
84: }
85:
86: switch (xvfs_error) {
87: case XVFS_RV_ERR_ENOENT:
88: return("No such file or directory");
89: case XVFS_RV_ERR_EINVAL:
90: return("Invalid argument");
91: case XVFS_RV_ERR_EISDIR:
92: return("Is a directory");
93: case XVFS_RV_ERR_ENOTDIR:
94: return("Not a directory");
95: case XVFS_RV_ERR_EFAULT:
96: return("Bad address");
97: case XVFS_RV_ERR_INTERNAL:
98: return("Internal error");
99: default:
100: return("Unknown error");
101: }
102: }
103:
104: static int xvfs_errorToErrno(int xvfs_error) {
105: if (xvfs_error >= 0) {
106: return(0);
107: }
108:
109: switch (xvfs_error) {
110: case XVFS_RV_ERR_ENOENT:
111: return(ENOENT);
112: case XVFS_RV_ERR_EINVAL:
113: return(EINVAL);
114: case XVFS_RV_ERR_EISDIR:
115: return(EISDIR);
116: case XVFS_RV_ERR_ENOTDIR:
117: return(ENOTDIR);
118: case XVFS_RV_ERR_EFAULT:
119: return(EFAULT);
120: case XVFS_RV_ERR_INTERNAL:
121: return(EINVAL);
122: default:
123: return(ERANGE);
124: }
125: }
126:
127: /*
128: * Xvfs Memory Channel
129: */
130: struct xvfs_tclfs_channel_id {
131: Tcl_Channel channel;
132: struct xvfs_tclfs_instance_info *fsInstanceInfo;
133: Tcl_Obj *path;
134: Tcl_WideInt currentOffset;
135: Tcl_WideInt fileSize;
136: int eofMarked;
137: int queuedEvents;
138: int closed;
139: };
140: struct xvfs_tclfs_channel_event {
141: Tcl_Event tcl;
142: struct xvfs_tclfs_channel_id *channelInstanceData;
143: };
144: static Tcl_ChannelType xvfs_tclfs_channelType;
145:
146: static Tcl_Channel xvfs_tclfs_openChannel(Tcl_Obj *path, struct xvfs_tclfs_instance_info *instanceInfo) {
147: struct xvfs_tclfs_channel_id *channelInstanceData;
148: Tcl_Channel channel;
149: Tcl_StatBuf fileInfo;
150: Tcl_Obj *channelName;
151: int statRet;
152:
153: statRet = instanceInfo->fsInfo->getStatProc(Tcl_GetString(path), &fileInfo);
154: if (statRet < 0) {
155: return(NULL);
156: }
157:
158: channelInstanceData = (struct xvfs_tclfs_channel_id *) Tcl_Alloc(sizeof(*channelInstanceData));
159: channelInstanceData->currentOffset = 0;
160: channelInstanceData->eofMarked = 0;
161: channelInstanceData->queuedEvents = 0;
162: channelInstanceData->closed = 0;
163: channelInstanceData->channel = NULL;
164:
165: channelName = Tcl_ObjPrintf("xvfs0x%llx", (unsigned long long) channelInstanceData);
166: if (!channelName) {
167: Tcl_Free((char *) channelInstanceData);
168:
169: return(NULL);
170: }
171: Tcl_IncrRefCount(channelName);
172:
173: channelInstanceData->fsInstanceInfo = instanceInfo;
174: channelInstanceData->fileSize = fileInfo.st_size;
175: channelInstanceData->path = path;
176: Tcl_IncrRefCount(path);
177:
178: channel = Tcl_CreateChannel(&xvfs_tclfs_channelType, Tcl_GetString(channelName), channelInstanceData, TCL_READABLE);
179: Tcl_DecrRefCount(channelName);
180: if (!channel) {
181: Tcl_DecrRefCount(path);
182: Tcl_Free((char *) channelInstanceData);
183:
184: return(NULL);
185: }
186:
187: channelInstanceData->channel = channel;
188:
189: return(channel);
190: }
191:
192: static int xvfs_tclfs_closeChannel(ClientData channelInstanceData_p, Tcl_Interp *interp);
193: static int xvfs_tclfs_closeChannelEvent(Tcl_Event *event_p, int flags) {
194: struct xvfs_tclfs_channel_id *channelInstanceData;
195: struct xvfs_tclfs_channel_event *event;
196:
197: event = (struct xvfs_tclfs_channel_event *) event_p;
198: channelInstanceData = event->channelInstanceData;
199:
200: channelInstanceData->queuedEvents--;
201:
202: xvfs_tclfs_closeChannel((ClientData) channelInstanceData, NULL);
203:
204: return(1);
205: }
206:
207: static int xvfs_tclfs_closeChannel(ClientData channelInstanceData_p, Tcl_Interp *interp) {
208: struct xvfs_tclfs_channel_id *channelInstanceData;
209: struct xvfs_tclfs_channel_event *event;
210:
211: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
212:
213: channelInstanceData->closed = 1;
214:
215: if (channelInstanceData->queuedEvents != 0) {
216: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
217: event->tcl.proc = xvfs_tclfs_closeChannelEvent;
218: event->tcl.nextPtr = NULL;
219: event->channelInstanceData = channelInstanceData;
220:
221: channelInstanceData->queuedEvents++;
222:
223: Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
224:
225: return(0);
226: }
227:
228: Tcl_DecrRefCount(channelInstanceData->path);
229: Tcl_Free((char *) channelInstanceData);
230:
231: return(0);
232: }
233:
234: static int xvfs_tclfs_readChannel(ClientData channelInstanceData_p, char *buf, int bufSize, int *errorCodePtr) {
235: struct xvfs_tclfs_channel_id *channelInstanceData;
236: const unsigned char *data;
237: Tcl_WideInt offset, length;
238: char *path;
239:
240: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
241:
242: /*
243: * If we are already at the end of the file we can skip
244: * attempting to read it
245: */
246: if (channelInstanceData->eofMarked) {
247: return(0);
248: }
249:
250: path = Tcl_GetString(channelInstanceData->path);
251: offset = channelInstanceData->currentOffset;
252: length = bufSize;
253:
254: data = channelInstanceData->fsInstanceInfo->fsInfo->getDataProc(path, offset, &length);
255:
256: if (length < 0) {
257: *errorCodePtr = xvfs_errorToErrno(length);
258:
259: return(-1);
260: }
261:
262: if (length == 0) {
263: channelInstanceData->eofMarked = 1;
264: } else {
265: memcpy(buf, data, length);
266:
267: channelInstanceData->currentOffset += length;
268: }
269:
270: return(length);
271: }
272:
273: static int xvfs_tclfs_watchChannelEvent(Tcl_Event *event_p, int flags) {
274: struct xvfs_tclfs_channel_id *channelInstanceData;
275: struct xvfs_tclfs_channel_event *event;
276:
277: event = (struct xvfs_tclfs_channel_event *) event_p;
278: channelInstanceData = event->channelInstanceData;
279:
280: channelInstanceData->queuedEvents--;
281:
282: if (channelInstanceData->closed) {
283: return(1);
284: }
285:
286: Tcl_NotifyChannel(channelInstanceData->channel, TCL_READABLE);
287:
288: return(1);
289: }
290:
291: static void xvfs_tclfs_watchChannel(ClientData channelInstanceData_p, int mask) {
292: struct xvfs_tclfs_channel_id *channelInstanceData;
293: struct xvfs_tclfs_channel_event *event;
294:
295: if ((mask & TCL_READABLE) != TCL_READABLE) {
296: return;
297: }
298:
299: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
300:
301: /*
302: * If the read call has marked that we have reached EOF,
303: * do not signal any further
304: */
305: if (channelInstanceData->eofMarked) {
306: return;
307: }
308:
309: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
310: event->tcl.proc = xvfs_tclfs_watchChannelEvent;
311: event->tcl.nextPtr = NULL;
312: event->channelInstanceData = channelInstanceData;
313:
314: channelInstanceData->queuedEvents++;
315:
316: Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
317:
318: return;
319: }
320:
321: static int xvfs_tclfs_seekChannel(ClientData channelInstanceData_p, long offset, int mode, int *errorCodePtr) {
322: struct xvfs_tclfs_channel_id *channelInstanceData;
323: Tcl_WideInt newOffset, fileSize;
324:
325: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
326:
327: newOffset = channelInstanceData->currentOffset;
328: fileSize = channelInstanceData->fileSize;
329:
330: switch (mode) {
331: case SEEK_CUR:
332: newOffset += offset;
333: break;
334: case SEEK_SET:
335: newOffset = offset;
336: break;
337: case SEEK_END:
338: newOffset = fileSize + offset;
339: break;
340: default:
341: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
342:
343: return(-1);
344: }
345:
346: /*
347: * We allow users to seek right up to the end of the buffer, but
348: * no further, this way if they want to seek backwards from there
349: * it is possible to do so.
350: */
351: if (newOffset < 0 || newOffset > fileSize) {
352: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
353:
354: return(-1);
355: }
356:
357: if (newOffset != channelInstanceData->currentOffset) {
358: channelInstanceData->eofMarked = 0;
359: channelInstanceData->currentOffset = newOffset;
360: }
361:
362: return(channelInstanceData->currentOffset);
363: }
364:
365: static void xvfs_tclfs_prepareChannelType(void) {
366: xvfs_tclfs_channelType.typeName = "xvfs";
367: xvfs_tclfs_channelType.version = TCL_CHANNEL_VERSION_2;
368: xvfs_tclfs_channelType.closeProc = xvfs_tclfs_closeChannel;
369: xvfs_tclfs_channelType.inputProc = xvfs_tclfs_readChannel;
370: xvfs_tclfs_channelType.outputProc = NULL;
371: xvfs_tclfs_channelType.watchProc = xvfs_tclfs_watchChannel;
372: xvfs_tclfs_channelType.getHandleProc = NULL;
373: xvfs_tclfs_channelType.seekProc = xvfs_tclfs_seekChannel;
374: xvfs_tclfs_channelType.setOptionProc = NULL;
375: xvfs_tclfs_channelType.getOptionProc = NULL;
376: xvfs_tclfs_channelType.close2Proc = NULL;
377: xvfs_tclfs_channelType.blockModeProc = NULL;
378: xvfs_tclfs_channelType.flushProc = NULL;
379: xvfs_tclfs_channelType.handlerProc = NULL;
380: xvfs_tclfs_channelType.wideSeekProc = NULL;
381: xvfs_tclfs_channelType.threadActionProc = NULL;
382: xvfs_tclfs_channelType.truncateProc = NULL;
383: }
384:
385: /*
386: * Internal Tcl_Filesystem functions, with the appropriate instance info
387: */
388: static int xvfs_tclfs_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr, struct xvfs_tclfs_instance_info *instanceInfo) {
389: const char *relativePath;
390:
391: relativePath = xvfs_relativePath(path, instanceInfo);
392: if (!relativePath) {
5ae034e55e 2019-09-14 393: return(-1);
394: }
395:
5ae034e55e 2019-09-14 396: return(TCL_OK);
397: }
398:
399: static int xvfs_tclfs_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf, struct xvfs_tclfs_instance_info *instanceInfo) {
400: const char *pathStr;
401: int retval;
402:
403: pathStr = xvfs_relativePath(path, instanceInfo);
404:
405: retval = instanceInfo->fsInfo->getStatProc(pathStr, statBuf);
406: if (retval < 0) {
407: retval = -1;
408: }
409:
410: return(retval);
411: }
412:
413: static int xvfs_tclfs_access(Tcl_Obj *path, int mode, struct xvfs_tclfs_instance_info *instanceInfo) {
414: const char *pathStr;
415: Tcl_StatBuf fileInfo;
416: int statRetVal;
417:
418: pathStr = xvfs_relativePath(path, instanceInfo);
419:
5ae034e55e 2019-09-14 420: if (mode & W_OK) {
421: return(-1);
422: }
423:
424: statRetVal = instanceInfo->fsInfo->getStatProc(pathStr, &fileInfo);
425: if (statRetVal < 0) {
426: return(-1);
427: }
428:
429: if (mode & X_OK) {
430: if (!(fileInfo.st_mode & 040000)) {
431: return(-1);
432: }
433: }
434:
435: return(0);
5ae034e55e 2019-09-14 436: }
5ae034e55e 2019-09-14 437:
5ae034e55e 2019-09-14 438: static Tcl_Obj *xvfs_tclfs_listVolumes(struct xvfs_tclfs_instance_info *instanceInfo) {
5ae034e55e 2019-09-14 439: return(NULL);
440: }
441:
442: static Tcl_Channel xvfs_tclfs_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions, struct xvfs_tclfs_instance_info *instanceInfo) {
443: const char *pathStr;
444:
5ae034e55e 2019-09-14 445: pathStr = xvfs_relativePath(path, instanceInfo);
446:
447: if (mode & O_WRONLY) {
448: return(NULL);
449: }
450:
5ae034e55e 2019-09-14 451: return(xvfs_tclfs_openChannel(Tcl_NewStringObj(pathStr, -1), instanceInfo));
452: }
453:
454: static int xvfs_tclfs_verifyType(Tcl_Obj *path, Tcl_GlobTypeData *types, struct xvfs_tclfs_instance_info *instanceInfo) {
455: const char *pathStr;
456: Tcl_StatBuf fileInfo;
457: int statRetVal;
458:
459: statRetVal = xvfs_tclfs_stat(path, &fileInfo, instanceInfo);
460: if (statRetVal != 0) {
461: return(0);
462: }
463:
464: if (!types) {
465: return(1);
466: }
467:
468: if (types->perm != TCL_GLOB_PERM_RONLY) {
469: if (types->perm & (TCL_GLOB_PERM_W | TCL_GLOB_PERM_HIDDEN)) {
470: return(0);
471: }
472:
473: if ((types->perm & TCL_GLOB_PERM_X) == TCL_GLOB_PERM_X) {
474: if (!(fileInfo.st_mode & 040000)) {
475: return(0);
476: }
477: }
478: }
479:
480: if (types->type & (TCL_GLOB_TYPE_BLOCK | TCL_GLOB_TYPE_CHAR | TCL_GLOB_TYPE_PIPE | TCL_GLOB_TYPE_SOCK | TCL_GLOB_TYPE_LINK)) {
481: return(0);
482: }
483:
484: if ((types->type & TCL_GLOB_TYPE_DIR) == TCL_GLOB_TYPE_DIR) {
485: if (!(fileInfo.st_mode & 040000)) {
486: return(0);
487: }
488: }
489:
490: if ((types->type & TCL_GLOB_TYPE_FILE) == TCL_GLOB_TYPE_FILE) {
491: if (!(fileInfo.st_mode & 0100000)) {
492: return(0);
493: }
494: }
495:
496: if ((types->type & TCL_GLOB_TYPE_MOUNT) == TCL_GLOB_TYPE_MOUNT) {
497: pathStr = xvfs_relativePath(path, instanceInfo);
498: if (!pathStr) {
499: return(0);
500: }
501:
502: if (strlen(pathStr) != 0) {
503: return(0);
504: }
505: }
506:
507: return(1);
508: }
509:
510: 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) {
511: const char *pathStr;
512: const char **children, *child;
513: Tcl_WideInt childrenCount, idx;
514: Tcl_Obj *childObj;
515: int tclRetVal;
516:
517: if (pattern == NULL) {
518: if (xvfs_tclfs_verifyType(path, types, instanceInfo)) {
519: return(TCL_OK);
520: }
521:
522: return(TCL_ERROR);
523: }
524:
525: pathStr = xvfs_relativePath(path, instanceInfo);
526: if (!pathStr) {
527: if (interp) {
528: Tcl_SetResult(interp, (char *) xvfs_perror(XVFS_RV_ERR_ENOENT), NULL);
529: }
530:
5ae034e55e 2019-09-14 531: return(TCL_ERROR);
532: }
533:
534: childrenCount = 0;
535: children = instanceInfo->fsInfo->getChildrenProc(pathStr, &childrenCount);
536: if (childrenCount < 0) {
537: if (interp) {
538: Tcl_SetResult(interp, (char *) xvfs_perror(childrenCount), NULL);
539: }
540:
541: return(TCL_ERROR);
542: }
543:
544: for (idx = 0; idx < childrenCount; idx++) {
545: child = children[idx];
546:
547: if (!Tcl_StringMatch(child, pattern)) {
548: continue;
549: }
550:
551: childObj = Tcl_DuplicateObj(path);
552: Tcl_IncrRefCount(childObj);
553: Tcl_AppendStringsToObj(childObj, "/", child, NULL);
554:
555: if (!xvfs_tclfs_verifyType(childObj, types, instanceInfo)) {
556: Tcl_DecrRefCount(childObj);
557:
558: continue;
559: }
560:
561: tclRetVal = Tcl_ListObjAppendElement(interp, resultPtr, childObj);
562: Tcl_DecrRefCount(childObj);
563:
564: if (tclRetVal != TCL_OK) {
565: return(tclRetVal);
566: }
567: }
568:
569: return(TCL_OK);
570: }
571: #endif /* XVFS_MODE_SERVER || XVFS_MODE_STANDALONE || XVFS_MODE_FLEIXBLE */
572:
573: #if defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
574: /*
575: * Tcl_Filesystem handlers for the standalone implementation
576: */
577: static struct xvfs_tclfs_instance_info xvfs_tclfs_standalone_info;
578: static int xvfs_tclfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) {
579: return(xvfs_tclfs_pathInFilesystem(path, dataPtr, &xvfs_tclfs_standalone_info));
580: }
581:
582: static int xvfs_tclfs_standalone_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) {
583: return(xvfs_tclfs_stat(path, statBuf, &xvfs_tclfs_standalone_info));
584: }
585:
586: static int xvfs_tclfs_standalone_access(Tcl_Obj *path, int mode) {
587: return(xvfs_tclfs_access(path, mode, &xvfs_tclfs_standalone_info));
5ae034e55e 2019-09-14 588: }
5ae034e55e 2019-09-14 589:
5ae034e55e 2019-09-14 590: static Tcl_Obj *xvfs_tclfs_standalone_listVolumes(void) {
5ae034e55e 2019-09-14 591: return(xvfs_tclfs_listVolumes(&xvfs_tclfs_standalone_info));
592: }
593:
594: static Tcl_Channel xvfs_tclfs_standalone_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) {
595: return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, &xvfs_tclfs_standalone_info));
596: }
597:
598: static int xvfs_tclfs_standalone_matchInDir(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) {
599: return(xvfs_tclfs_matchInDir(interp, resultPtr, pathPtr, pattern, types, &xvfs_tclfs_standalone_info));
600: }
601:
602: /*
603: * There are three (3) modes of operation for Xvfs_Register:
604: * 1. standalone -- We register our own Tcl_Filesystem
605: * and handle requests under `//xvfs:/<fsName>`
606: * 2. client -- A single Tcl_Filesystem is registered for the
607: * interp to handle requests under `//xvfs:/` which
608: * then dispatches to the appropriate registered
609: * handler
610: * 3. flexible -- Attempts to find a core Xvfs instance for the
611: * process at runtime, if found do #2, otherwise
612: * fallback to #1
613: *
614: */
615: static Tcl_Filesystem xvfs_tclfs_standalone_fs;
616: static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
617: int tcl_ret;
618: static int registered = 0;
619:
620: /*
621: * Ensure this instance is not already registered
622: */
623: if (registered) {
624: return(TCL_OK);
625: }
626: registered = 1;
627:
628: /*
629: * In standalone mode, we only support the same protocol we are
630: * compiling for.
631: */
632: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
633: if (interp) {
634: Tcl_SetResult(interp, "Protocol mismatch", NULL);
635: }
636: return(TCL_ERROR);
637: }
638:
639: xvfs_tclfs_standalone_fs.typeName = "xvfs";
640: xvfs_tclfs_standalone_fs.structureLength = sizeof(xvfs_tclfs_standalone_fs);
641: xvfs_tclfs_standalone_fs.version = TCL_FILESYSTEM_VERSION_1;
642: xvfs_tclfs_standalone_fs.pathInFilesystemProc = xvfs_tclfs_standalone_pathInFilesystem;
643: xvfs_tclfs_standalone_fs.dupInternalRepProc = NULL;
644: xvfs_tclfs_standalone_fs.freeInternalRepProc = NULL;
645: xvfs_tclfs_standalone_fs.internalToNormalizedProc = NULL;
646: xvfs_tclfs_standalone_fs.createInternalRepProc = NULL;
647: xvfs_tclfs_standalone_fs.normalizePathProc = NULL;
648: xvfs_tclfs_standalone_fs.filesystemPathTypeProc = NULL;
649: xvfs_tclfs_standalone_fs.filesystemSeparatorProc = NULL;
650: xvfs_tclfs_standalone_fs.statProc = xvfs_tclfs_standalone_stat;
651: xvfs_tclfs_standalone_fs.accessProc = xvfs_tclfs_standalone_access;
652: xvfs_tclfs_standalone_fs.openFileChannelProc = xvfs_tclfs_standalone_openFileChannel;
653: xvfs_tclfs_standalone_fs.matchInDirectoryProc = xvfs_tclfs_standalone_matchInDir;
654: xvfs_tclfs_standalone_fs.utimeProc = NULL;
655: xvfs_tclfs_standalone_fs.linkProc = NULL;
5ae034e55e 2019-09-14 656: xvfs_tclfs_standalone_fs.listVolumesProc = xvfs_tclfs_standalone_listVolumes;
657: xvfs_tclfs_standalone_fs.fileAttrStringsProc = NULL;
658: xvfs_tclfs_standalone_fs.fileAttrsGetProc = NULL;
659: xvfs_tclfs_standalone_fs.fileAttrsSetProc = NULL;
660: xvfs_tclfs_standalone_fs.createDirectoryProc = NULL;
661: xvfs_tclfs_standalone_fs.removeDirectoryProc = NULL;
662: xvfs_tclfs_standalone_fs.deleteFileProc = NULL;
663: xvfs_tclfs_standalone_fs.copyFileProc = NULL;
664: xvfs_tclfs_standalone_fs.renameFileProc = NULL;
665: xvfs_tclfs_standalone_fs.copyDirectoryProc = NULL;
666: xvfs_tclfs_standalone_fs.lstatProc = NULL;
667: xvfs_tclfs_standalone_fs.loadFileProc = NULL;
668: xvfs_tclfs_standalone_fs.getCwdProc = NULL;
669: xvfs_tclfs_standalone_fs.chdirProc = NULL;
670:
671: xvfs_tclfs_standalone_info.fsInfo = fsInfo;
672: xvfs_tclfs_standalone_info.mountpoint = Tcl_NewObj();
673:
674: Tcl_IncrRefCount(xvfs_tclfs_standalone_info.mountpoint);
675: Tcl_AppendStringsToObj(xvfs_tclfs_standalone_info.mountpoint, XVFS_ROOT_MOUNTPOINT, fsInfo->name, NULL);
676:
677: tcl_ret = Tcl_FSRegister(NULL, &xvfs_tclfs_standalone_fs);
678: if (tcl_ret != TCL_OK) {
679: Tcl_DecrRefCount(xvfs_tclfs_standalone_info.mountpoint);
680:
681: if (interp) {
682: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
683: }
684:
685: return(tcl_ret);
686: }
687:
688: xvfs_tclfs_prepareChannelType();
689:
690: return(TCL_OK);
691: }
692: #endif /* XVFS_MODE_STANDALONE || XVFS_MODE_FLEXIBLE */
693:
694: #if defined(XVFS_MODE_FLEXIBLE)
695: static int xvfs_flexible_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
696: ClientData fsHandlerDataRaw;
697: struct xvfs_tclfs_server_info *fsHandlerData;
698: const Tcl_Filesystem *fsHandler;
699: int (*xvfs_register)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
700: Tcl_Obj *rootPathObj;
701:
702: xvfs_register = &xvfs_standalone_register;
703:
704: rootPathObj = Tcl_NewStringObj(XVFS_ROOT_MOUNTPOINT, -1);
705: if (!rootPathObj) {
706: return(xvfs_register(interp, fsInfo));
707: }
708:
709: Tcl_IncrRefCount(rootPathObj);
710: fsHandler = Tcl_FSGetFileSystemForPath(rootPathObj);
711: Tcl_DecrRefCount(rootPathObj);
712:
713: if (!fsHandler) {
714: return(xvfs_register(interp, fsInfo));
715: }
716:
717: fsHandlerDataRaw = Tcl_FSData(fsHandler);
718: if (!fsHandlerDataRaw) {
719: return(xvfs_register(interp, fsInfo));
720: }
721:
722: fsHandlerData = (struct xvfs_tclfs_server_info *) fsHandlerDataRaw;
723:
724: /*
725: * XXX:TODO: What is the chance that the handler for //xvfs:/ hold
726: * client data smaller than XVFS_INTERNAL_SERVER_MAGIC_LEN ?
727: */
728: if (memcmp(fsHandlerData->magic, XVFS_INTERNAL_SERVER_MAGIC, sizeof(fsHandlerData->magic)) == 0) {
729: xvfs_register = fsHandlerData->registerProc;
730: }
731:
732: return(xvfs_register(interp, fsInfo));
733: }
734: #endif /* XVFS_MODE_FLEXIBLE */
735:
736: #if defined(XVFS_MODE_SERVER)
737: int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
738: return(TCL_ERROR);
739: }
740: #endif /* XVFS_MODE_SERVER */