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