Lines of
xvfs-core.c
from check-in 4221e5dcbc
that are changed by the sequence of edits moving toward
check-in f01f82c2d8:
1: #include <xvfs-core.h>
2: #include <string.h>
3: #include <sys/stat.h>
4221e5dcbc 2019-09-18 4: #include <unistd.h>
5: #include <errno.h>
6: #include <fcntl.h>
7: #include <tcl.h>
8:
9: #ifdef XVFS_DEBUG
10: #include <stdio.h> /* Needed for XVFS_DEBUG_PRINTF */
11: static int xvfs_debug_depth = 0;
12: #define XVFS_DEBUG_PRINTF(fmt, ...) fprintf(stderr, "[XVFS:DEBUG:%-30s:%4i] %s" fmt "\n", __func__, __LINE__, " " + (80 - (xvfs_debug_depth * 4)), __VA_ARGS__)
13: #define XVFS_DEBUG_PUTS(str) XVFS_DEBUG_PRINTF("%s", str);
14: #define XVFS_DEBUG_ENTER { xvfs_debug_depth++; XVFS_DEBUG_PUTS("Entered"); }
15: #define XVFS_DEBUG_LEAVE { XVFS_DEBUG_PUTS("Returning"); xvfs_debug_depth--; }
16: #else /* XVFS_DEBUG */
17: #define XVFS_DEBUG_PRINTF(fmt, ...) /**/
18: #define XVFS_DEBUG_PUTS(str) /**/
19: #define XVFS_DEBUG_ENTER /**/
20: #define XVFS_DEBUG_LEAVE /**/
21: #endif /* XVFS_DEBUG */
22:
23: #if defined(XVFS_MODE_FLEXIBLE) || defined(XVFS_MODE_SERVER)
24: #define XVFS_INTERNAL_SERVER_MAGIC "\xD4\xF3\x05\x96\x25\xCF\xAF\xFE"
25: #define XVFS_INTERNAL_SERVER_MAGIC_LEN 8
26:
27: struct xvfs_tclfs_server_info {
28: char magic[XVFS_INTERNAL_SERVER_MAGIC_LEN];
29: int (*registerProc)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
30: };
31: #endif /* XVFS_MODE_FLEXIBLE || XVFS_MODE_SERVER */
32:
33: #if defined(XVFS_MODE_SERVER) || defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
34: #ifndef XVFS_ROOT_MOUNTPOINT
35: # define XVFS_ROOT_MOUNTPOINT "//xvfs:/"
36: #endif
37:
38: struct xvfs_tclfs_instance_info {
39: struct Xvfs_FSInfo *fsInfo;
40: Tcl_Obj *mountpoint;
41: };
42:
43: /*
44: * Internal Core Utilities
45: */
46: static Tcl_Obj *xvfs_absolutePath(Tcl_Obj *path) {
47: Tcl_Obj *currentDirectory;
48: const char *pathStr;
49:
50: XVFS_DEBUG_ENTER;
51:
52: pathStr = Tcl_GetString(path);
53:
54: if (pathStr[0] != '/') {
55: currentDirectory = Tcl_FSGetCwd(NULL);
56: Tcl_IncrRefCount(currentDirectory);
57:
58: path = Tcl_ObjPrintf("%s/%s", Tcl_GetString(currentDirectory), pathStr);
59: Tcl_IncrRefCount(path);
60: Tcl_DecrRefCount(currentDirectory);
61: } else {
62: Tcl_IncrRefCount(path);
63: }
64:
65: XVFS_DEBUG_PRINTF("Converted path \"%s\" to absolute path: \"%s\"", pathStr, Tcl_GetString(path));
66:
67: XVFS_DEBUG_LEAVE;
68: return(path);
69: }
70:
71: static const char *xvfs_relativePath(Tcl_Obj *path, struct xvfs_tclfs_instance_info *info) {
72: const char *pathStr, *rootStr;
73: const char *pathFinal;
74: int pathLen, rootLen;
75:
76: XVFS_DEBUG_ENTER;
77:
78: rootStr = Tcl_GetStringFromObj(info->mountpoint, &rootLen);
79: pathStr = Tcl_GetStringFromObj(path, &pathLen);
80:
81: XVFS_DEBUG_PRINTF("Finding relative path of \"%s\" from \"%s\" ...", pathStr, rootStr);
82:
83: if (pathLen < rootLen) {
84: XVFS_DEBUG_PUTS("... none possible (length)");
85:
86: XVFS_DEBUG_LEAVE;
87: return(NULL);
88: }
89:
90: if (memcmp(pathStr, rootStr, rootLen) != 0) {
91: XVFS_DEBUG_PUTS("... none possible (prefix differs)");
92:
93: XVFS_DEBUG_LEAVE;
94: return(NULL);
95: }
96:
97: if (pathLen == rootLen) {
98: XVFS_DEBUG_PUTS("... short circuit: \"\"");
99:
100: XVFS_DEBUG_LEAVE;
101: return("");
102: }
103:
104: /* XXX:TODO: Should this use the native OS path separator ? */
105: if (pathStr[rootLen] != '/') {
106: XVFS_DEBUG_PUTS("... none possible (no seperator)");
107:
108: XVFS_DEBUG_LEAVE;
109: return(NULL);
110: }
111:
112: pathFinal = pathStr + rootLen + 1;
113: pathLen -= rootLen + 1;
114:
115: if (pathLen == 1 && memcmp(pathFinal, ".", 1) == 0) {
116: XVFS_DEBUG_PUTS("... short circuit: \".\" -> \"\"");
117:
118: XVFS_DEBUG_LEAVE;
119: return("");
120: }
121:
122: while (pathLen >= 2 && memcmp(pathFinal, "./", 2) == 0) {
123: pathFinal += 2;
124: pathLen -= 2;
125: }
126:
127: XVFS_DEBUG_PRINTF("... relative path: \"%s\"", pathFinal);
128:
129: XVFS_DEBUG_LEAVE;
130: return(pathFinal);
131: }
132:
133: static int xvfs_errorToErrno(int xvfs_error) {
134: if (xvfs_error >= 0) {
135: return(0);
136: }
137:
138: switch (xvfs_error) {
139: case XVFS_RV_ERR_ENOENT:
140: return(ENOENT);
141: case XVFS_RV_ERR_EINVAL:
142: return(EINVAL);
143: case XVFS_RV_ERR_EISDIR:
144: return(EISDIR);
145: case XVFS_RV_ERR_ENOTDIR:
146: return(ENOTDIR);
147: case XVFS_RV_ERR_EFAULT:
148: return(EFAULT);
149: case XVFS_RV_ERR_EROFS:
150: return(EROFS);
151: case XVFS_RV_ERR_INTERNAL:
152: return(EINVAL);
153: default:
154: return(ERANGE);
155: }
156: }
157:
158: static const char *xvfs_strerror(int xvfs_error) {
159: if (xvfs_error >= 0) {
160: return("Not an error");
161: }
162:
163: switch (xvfs_error) {
164: case XVFS_RV_ERR_ENOENT:
165: case XVFS_RV_ERR_EINVAL:
166: case XVFS_RV_ERR_EISDIR:
167: case XVFS_RV_ERR_ENOTDIR:
168: case XVFS_RV_ERR_EFAULT:
169: case XVFS_RV_ERR_EROFS:
170: return(Tcl_ErrnoMsg(xvfs_errorToErrno(xvfs_error)));
171: case XVFS_RV_ERR_INTERNAL:
172: return("Internal error");
173: default:
174: return("Unknown error");
175: }
176: }
177:
178: static void xvfs_setresults_error(Tcl_Interp *interp, int xvfs_error) {
179: if (!interp) {
180: return;
181: }
182:
183: Tcl_SetErrno(xvfs_errorToErrno(xvfs_error));
184: Tcl_SetResult(interp, (char *) xvfs_strerror(xvfs_error), NULL);
185:
186: return;
187: }
188:
189: /*
190: * Xvfs Memory Channel
191: */
192: struct xvfs_tclfs_channel_id {
193: Tcl_Channel channel;
194: struct xvfs_tclfs_instance_info *fsInstanceInfo;
195: Tcl_Obj *path;
196: Tcl_WideInt currentOffset;
197: Tcl_WideInt fileSize;
198: int eofMarked;
199: int queuedEvents;
200: int closed;
201: };
202: struct xvfs_tclfs_channel_event {
203: Tcl_Event tcl;
204: struct xvfs_tclfs_channel_id *channelInstanceData;
205: };
206: static Tcl_ChannelType xvfs_tclfs_channelType;
207:
208: static Tcl_Channel xvfs_tclfs_openChannel(Tcl_Interp *interp, Tcl_Obj *path, struct xvfs_tclfs_instance_info *instanceInfo) {
209: struct xvfs_tclfs_channel_id *channelInstanceData;
210: Tcl_Channel channel;
211: Tcl_StatBuf fileInfo;
212: Tcl_Obj *channelName;
213: int statRet;
214:
215: XVFS_DEBUG_ENTER;
216: XVFS_DEBUG_PRINTF("Opening file \"%s\" ...", Tcl_GetString(path));
217:
218: statRet = instanceInfo->fsInfo->getStatProc(Tcl_GetString(path), &fileInfo);
219: if (statRet < 0) {
220: XVFS_DEBUG_PRINTF("... failed: %s", xvfs_strerror(statRet));
221:
222: xvfs_setresults_error(interp, XVFS_RV_ERR_ENOENT);
223:
224: XVFS_DEBUG_LEAVE;
225: return(NULL);
226: }
227:
228: if (fileInfo.st_mode & 040000) {
229: XVFS_DEBUG_PUTS("... failed (cannot open directories)");
230:
231: xvfs_setresults_error(interp, XVFS_RV_ERR_EISDIR);
232:
233: XVFS_DEBUG_LEAVE;
234: return(NULL);
235: }
236:
237: channelInstanceData = (struct xvfs_tclfs_channel_id *) Tcl_Alloc(sizeof(*channelInstanceData));
238: channelInstanceData->currentOffset = 0;
239: channelInstanceData->eofMarked = 0;
240: channelInstanceData->queuedEvents = 0;
241: channelInstanceData->closed = 0;
242: channelInstanceData->channel = NULL;
243:
244: channelName = Tcl_ObjPrintf("xvfs0x%llx", (unsigned long long) channelInstanceData);
245: if (!channelName) {
246: XVFS_DEBUG_PUTS("... failed");
247:
248: Tcl_Free((char *) channelInstanceData);
249:
250: XVFS_DEBUG_LEAVE;
251: return(NULL);
252: }
253: Tcl_IncrRefCount(channelName);
254:
255: channelInstanceData->fsInstanceInfo = instanceInfo;
256: channelInstanceData->fileSize = fileInfo.st_size;
257: channelInstanceData->path = path;
258: Tcl_IncrRefCount(path);
259:
260: channel = Tcl_CreateChannel(&xvfs_tclfs_channelType, Tcl_GetString(channelName), channelInstanceData, TCL_READABLE);
261: Tcl_DecrRefCount(channelName);
262: if (!channel) {
263: XVFS_DEBUG_PUTS("... failed");
264:
265: Tcl_DecrRefCount(path);
266: Tcl_Free((char *) channelInstanceData);
267:
268: XVFS_DEBUG_LEAVE;
269: return(NULL);
270: }
271:
272: channelInstanceData->channel = channel;
273:
274: XVFS_DEBUG_PRINTF("... ok (%p)", channelInstanceData);
275:
276: XVFS_DEBUG_LEAVE;
277: return(channel);
278: }
279:
280: static int xvfs_tclfs_closeChannel(ClientData channelInstanceData_p, Tcl_Interp *interp);
281: static int xvfs_tclfs_closeChannelEvent(Tcl_Event *event_p, int flags) {
282: struct xvfs_tclfs_channel_id *channelInstanceData;
283: struct xvfs_tclfs_channel_event *event;
284:
285: event = (struct xvfs_tclfs_channel_event *) event_p;
286: channelInstanceData = event->channelInstanceData;
287:
288: channelInstanceData->queuedEvents--;
289:
290: xvfs_tclfs_closeChannel((ClientData) channelInstanceData, NULL);
291:
292: return(1);
293: }
294:
295: static int xvfs_tclfs_closeChannel(ClientData channelInstanceData_p, Tcl_Interp *interp) {
296: struct xvfs_tclfs_channel_id *channelInstanceData;
297: struct xvfs_tclfs_channel_event *event;
298:
299: XVFS_DEBUG_ENTER;
300: XVFS_DEBUG_PRINTF("Closing channel %p ...", channelInstanceData_p);
301:
302: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
303:
304: channelInstanceData->closed = 1;
305:
306: if (channelInstanceData->queuedEvents != 0) {
307: XVFS_DEBUG_PUTS("... queued");
308:
309: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
310: event->tcl.proc = xvfs_tclfs_closeChannelEvent;
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: XVFS_DEBUG_LEAVE;
319: return(0);
320: }
321:
322: Tcl_DecrRefCount(channelInstanceData->path);
323: Tcl_Free((char *) channelInstanceData);
324:
325: XVFS_DEBUG_PUTS("... ok");
326:
327: XVFS_DEBUG_LEAVE;
328: return(0);
329: }
330:
331: static int xvfs_tclfs_readChannel(ClientData channelInstanceData_p, char *buf, int bufSize, int *errorCodePtr) {
332: struct xvfs_tclfs_channel_id *channelInstanceData;
333: const unsigned char *data;
334: Tcl_WideInt offset, length;
335: char *path;
336:
337: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
338:
339: /*
340: * If we are already at the end of the file we can skip
341: * attempting to read it
342: */
343: if (channelInstanceData->eofMarked) {
344: return(0);
345: }
346:
347: path = Tcl_GetString(channelInstanceData->path);
348: offset = channelInstanceData->currentOffset;
349: length = bufSize;
350:
351: data = channelInstanceData->fsInstanceInfo->fsInfo->getDataProc(path, offset, &length);
352:
353: if (length < 0) {
354: *errorCodePtr = xvfs_errorToErrno(length);
355:
356: return(-1);
357: }
358:
359: if (length == 0) {
360: channelInstanceData->eofMarked = 1;
361: } else {
362: memcpy(buf, data, length);
363:
364: channelInstanceData->currentOffset += length;
365: }
366:
367: return(length);
368: }
369:
370: static int xvfs_tclfs_watchChannelEvent(Tcl_Event *event_p, int flags) {
371: struct xvfs_tclfs_channel_id *channelInstanceData;
372: struct xvfs_tclfs_channel_event *event;
373:
374: event = (struct xvfs_tclfs_channel_event *) event_p;
375: channelInstanceData = event->channelInstanceData;
376:
377: channelInstanceData->queuedEvents--;
378:
379: if (channelInstanceData->closed) {
380: return(1);
381: }
382:
383: Tcl_NotifyChannel(channelInstanceData->channel, TCL_READABLE);
384:
385: return(1);
386: }
387:
388: static void xvfs_tclfs_watchChannel(ClientData channelInstanceData_p, int mask) {
389: struct xvfs_tclfs_channel_id *channelInstanceData;
390: struct xvfs_tclfs_channel_event *event;
391:
392: if ((mask & TCL_READABLE) != TCL_READABLE) {
393: return;
394: }
395:
396: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
397:
398: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
399: event->tcl.proc = xvfs_tclfs_watchChannelEvent;
400: event->tcl.nextPtr = NULL;
401: event->channelInstanceData = channelInstanceData;
402:
403: channelInstanceData->queuedEvents++;
404:
405: Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
406:
407: return;
408: }
409:
410: static int xvfs_tclfs_seekChannel(ClientData channelInstanceData_p, long offset, int mode, int *errorCodePtr) {
411: struct xvfs_tclfs_channel_id *channelInstanceData;
412: Tcl_WideInt newOffset, fileSize;
413:
414: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
415:
416: newOffset = channelInstanceData->currentOffset;
417: fileSize = channelInstanceData->fileSize;
418:
419: switch (mode) {
420: case SEEK_CUR:
421: newOffset += offset;
422: break;
423: case SEEK_SET:
424: newOffset = offset;
425: break;
426: case SEEK_END:
427: newOffset = fileSize + offset;
428: break;
429: default:
430: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
431:
432: return(-1);
433: }
434:
435: /*
436: * We allow users to seek right up to the end of the buffer, but
437: * no further, this way if they want to seek backwards from there
438: * it is possible to do so.
439: */
440: if (newOffset < 0 || newOffset > fileSize) {
441: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
442:
443: return(-1);
444: }
445:
446: if (newOffset != channelInstanceData->currentOffset) {
447: channelInstanceData->eofMarked = 0;
448: channelInstanceData->currentOffset = newOffset;
449: }
450:
451: return(channelInstanceData->currentOffset);
452: }
453:
454: static void xvfs_tclfs_prepareChannelType(void) {
455: xvfs_tclfs_channelType.typeName = "xvfs";
456: xvfs_tclfs_channelType.version = TCL_CHANNEL_VERSION_2;
457: xvfs_tclfs_channelType.closeProc = xvfs_tclfs_closeChannel;
458: xvfs_tclfs_channelType.inputProc = xvfs_tclfs_readChannel;
459: xvfs_tclfs_channelType.outputProc = NULL;
460: xvfs_tclfs_channelType.watchProc = xvfs_tclfs_watchChannel;
461: xvfs_tclfs_channelType.getHandleProc = NULL;
462: xvfs_tclfs_channelType.seekProc = xvfs_tclfs_seekChannel;
463: xvfs_tclfs_channelType.setOptionProc = NULL;
464: xvfs_tclfs_channelType.getOptionProc = NULL;
465: xvfs_tclfs_channelType.close2Proc = NULL;
466: xvfs_tclfs_channelType.blockModeProc = NULL;
467: xvfs_tclfs_channelType.flushProc = NULL;
468: xvfs_tclfs_channelType.handlerProc = NULL;
469: xvfs_tclfs_channelType.wideSeekProc = NULL;
470: xvfs_tclfs_channelType.threadActionProc = NULL;
471: xvfs_tclfs_channelType.truncateProc = NULL;
472: }
473:
474: /*
475: * Internal Tcl_Filesystem functions, with the appropriate instance info
476: */
477: static int xvfs_tclfs_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr, struct xvfs_tclfs_instance_info *instanceInfo) {
478: const char *relativePath;
479: int retval;
480:
481: XVFS_DEBUG_ENTER;
482:
483: XVFS_DEBUG_PRINTF("Checking to see if path \"%s\" is in the filesystem ...", Tcl_GetString(path));
484:
485: path = xvfs_absolutePath(path);
486:
487: relativePath = xvfs_relativePath(path, instanceInfo);
488:
489: retval = TCL_OK;
490: if (!relativePath) {
491: retval = -1;
492: }
493:
494: Tcl_DecrRefCount(path);
495:
496: XVFS_DEBUG_PRINTF("... %s", retval == -1 ? "no" : "yes");
497:
498: XVFS_DEBUG_LEAVE;
499: return(retval);
500: }
501:
502: static int xvfs_tclfs_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf, struct xvfs_tclfs_instance_info *instanceInfo) {
503: const char *pathStr;
504: int retval;
505:
506: XVFS_DEBUG_ENTER;
507:
508: XVFS_DEBUG_PRINTF("Getting stat() on \"%s\" ...", Tcl_GetString(path));
509:
510: path = xvfs_absolutePath(path);
511:
512: pathStr = xvfs_relativePath(path, instanceInfo);
513:
514: retval = instanceInfo->fsInfo->getStatProc(pathStr, statBuf);
515: if (retval < 0) {
516: XVFS_DEBUG_PRINTF("... failed: %s", xvfs_strerror(retval));
517:
518: Tcl_SetErrno(xvfs_errorToErrno(retval));
519:
520: retval = -1;
521: } else {
522: XVFS_DEBUG_PUTS("... ok");
523: }
524:
525: Tcl_DecrRefCount(path);
526:
527: XVFS_DEBUG_LEAVE;
528: return(retval);
529: }
530:
531: static int xvfs_tclfs_access(Tcl_Obj *path, int mode, struct xvfs_tclfs_instance_info *instanceInfo) {
532: const char *pathStr;
533: Tcl_StatBuf fileInfo;
534: int statRetVal;
535:
536: XVFS_DEBUG_ENTER;
537:
538: XVFS_DEBUG_PRINTF("Getting access(..., %i) on \"%s\" ...", mode, Tcl_GetString(path));
539:
540: if (mode & W_OK) {
541: XVFS_DEBUG_PUTS("... no (not writable)");
542:
543: XVFS_DEBUG_LEAVE;
544: return(-1);
545: }
546:
547: path = xvfs_absolutePath(path);
548:
549: pathStr = xvfs_relativePath(path, instanceInfo);
550: if (!pathStr) {
551: XVFS_DEBUG_PUTS("... no (not in our path)");
552:
553: Tcl_DecrRefCount(path);
554:
555: XVFS_DEBUG_LEAVE;
556: return(-1);
557: }
558:
559: statRetVal = instanceInfo->fsInfo->getStatProc(pathStr, &fileInfo);
560: if (statRetVal < 0) {
561: XVFS_DEBUG_PUTS("... no (not statable)");
562:
563: Tcl_DecrRefCount(path);
564:
565: XVFS_DEBUG_LEAVE;
566: return(-1);
567: }
568:
569: if (mode & X_OK) {
570: if (!(fileInfo.st_mode & 040000)) {
571: XVFS_DEBUG_PUTS("... no (not a directory and X_OK specified)");
572:
573: Tcl_DecrRefCount(path);
574:
575: XVFS_DEBUG_LEAVE;
576: return(-1);
577: }
578: }
579:
580: Tcl_DecrRefCount(path);
581:
582: XVFS_DEBUG_PUTS("... ok");
583:
584: XVFS_DEBUG_LEAVE;
585: return(0);
586: }
587:
588: static Tcl_Channel xvfs_tclfs_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions, struct xvfs_tclfs_instance_info *instanceInfo) {
589: Tcl_Channel retval;
590: Tcl_Obj *pathRel;
591: const char *pathStr;
592:
593: XVFS_DEBUG_ENTER;
594:
595: XVFS_DEBUG_PRINTF("Asked to open(\"%s\", %x)...", Tcl_GetString(path), mode);
596:
597: if (mode & O_WRONLY) {
598: XVFS_DEBUG_PUTS("... failed (asked to open for writing)");
599:
600: xvfs_setresults_error(interp, XVFS_RV_ERR_EROFS);
601:
602: XVFS_DEBUG_LEAVE;
603: return(NULL);
604: }
605:
606: path = xvfs_absolutePath(path);
607:
608: pathStr = xvfs_relativePath(path, instanceInfo);
609:
610: pathRel = Tcl_NewStringObj(pathStr, -1);
611:
612: Tcl_DecrRefCount(path);
613:
614: XVFS_DEBUG_PUTS("... done, passing off to channel handler");
615:
616: retval = xvfs_tclfs_openChannel(interp, pathRel, instanceInfo);
617:
618: XVFS_DEBUG_LEAVE;
619: return(retval);
620: }
621:
622: static int xvfs_tclfs_verifyType(Tcl_Obj *path, Tcl_GlobTypeData *types, struct xvfs_tclfs_instance_info *instanceInfo) {
623: const char *pathStr;
624: Tcl_StatBuf fileInfo;
625: int statRetVal;
626:
627: XVFS_DEBUG_ENTER;
628:
629: if (types) {
630: XVFS_DEBUG_PRINTF("Asked to verify the existence and type of \"%s\" matches type=%i and perm=%i ...", Tcl_GetString(path), types->type, types->perm);
631: } else {
632: XVFS_DEBUG_PRINTF("Asked to verify the existence \"%s\" ...", Tcl_GetString(path));
633: }
634:
635: statRetVal = xvfs_tclfs_stat(path, &fileInfo, instanceInfo);
636: if (statRetVal != 0) {
637: XVFS_DEBUG_PUTS("... no (cannot stat)");
638:
639: XVFS_DEBUG_LEAVE;
640: return(0);
641: }
642:
643: if (!types) {
644: XVFS_DEBUG_PUTS("... yes");
645:
646: XVFS_DEBUG_LEAVE;
647: return(1);
648: }
649:
650: if (types->perm != TCL_GLOB_PERM_RONLY) {
651: if (types->perm & (TCL_GLOB_PERM_W | TCL_GLOB_PERM_HIDDEN)) {
652: XVFS_DEBUG_PUTS("... no (checked for writable or hidden, not supported)");
653:
654: XVFS_DEBUG_LEAVE;
655: return(0);
656: }
657:
658: if ((types->perm & TCL_GLOB_PERM_X) == TCL_GLOB_PERM_X) {
659: if (!(fileInfo.st_mode & 040000)) {
660: XVFS_DEBUG_PUTS("... no (checked for executable but not a directory)");
661:
662: XVFS_DEBUG_LEAVE;
663: return(0);
664: }
665: }
666: }
667:
668: if (types->type & (TCL_GLOB_TYPE_BLOCK | TCL_GLOB_TYPE_CHAR | TCL_GLOB_TYPE_PIPE | TCL_GLOB_TYPE_SOCK | TCL_GLOB_TYPE_LINK)) {
669: XVFS_DEBUG_PUTS("... no (checked for block, char, pipe, sock, or link, not supported)");
670:
671: XVFS_DEBUG_LEAVE;
672: return(0);
673: }
674:
675: if ((types->type & TCL_GLOB_TYPE_DIR) == TCL_GLOB_TYPE_DIR) {
676: if (!(fileInfo.st_mode & 040000)) {
677: XVFS_DEBUG_PUTS("... no (checked for directory but not a directory)");
678:
679: XVFS_DEBUG_LEAVE;
680: return(0);
681: }
682: }
683:
684: if ((types->type & TCL_GLOB_TYPE_FILE) == TCL_GLOB_TYPE_FILE) {
685: if (!(fileInfo.st_mode & 0100000)) {
686: XVFS_DEBUG_PUTS("... no (checked for file but not a file)");
687:
688: XVFS_DEBUG_LEAVE;
689: return(0);
690: }
691: }
692:
693: if ((types->type & TCL_GLOB_TYPE_MOUNT) == TCL_GLOB_TYPE_MOUNT) {
694: path = xvfs_absolutePath(path);
695: pathStr = xvfs_relativePath(path, instanceInfo);
696: if (!pathStr) {
697: XVFS_DEBUG_PUTS("... no (checked for mount but not able to resolve path)");
698:
699: Tcl_DecrRefCount(path);
700:
701: XVFS_DEBUG_LEAVE;
702: return(0);
703: }
704:
705: if (strlen(pathStr) != 0) {
706: XVFS_DEBUG_PUTS("... no (checked for mount but not our top-level directory)");
707:
708: Tcl_DecrRefCount(path);
709:
710: XVFS_DEBUG_LEAVE;
711: return(0);
712: }
713:
714: Tcl_DecrRefCount(path);
715: }
716:
717: XVFS_DEBUG_PUTS("... yes");
718:
719: XVFS_DEBUG_LEAVE;
720: return(1);
721: }
722:
723: 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) {
724: const char *pathStr;
725: const char **children, *child;
726: Tcl_WideInt childrenCount, idx;
727: Tcl_Obj *childObj;
728: int tclRetVal;
729:
730: if (pattern == NULL) {
731: if (xvfs_tclfs_verifyType(path, types, instanceInfo)) {
732: return(TCL_OK);
733: }
734:
735: return(TCL_ERROR);
736: }
737:
738: XVFS_DEBUG_ENTER;
739:
740: path = xvfs_absolutePath(path);
741:
742: if (types) {
743: XVFS_DEBUG_PRINTF("Checking for files matching %s in \"%s\" and type=%i and perm=%i ...", pattern, Tcl_GetString(path), types->type, types->perm);
744: } else {
745: XVFS_DEBUG_PRINTF("Checking for files matching %s in \"%s\" ...", pattern, Tcl_GetString(path));
746: }
747:
748: pathStr = xvfs_relativePath(path, instanceInfo);
749: if (!pathStr) {
750: XVFS_DEBUG_PUTS("... error (not in our VFS)");
751:
752: Tcl_DecrRefCount(path);
753:
754: xvfs_setresults_error(interp, XVFS_RV_ERR_ENOENT);
755:
756: XVFS_DEBUG_LEAVE;
757: return(TCL_OK);
758: }
759:
760: childrenCount = 0;
761: children = instanceInfo->fsInfo->getChildrenProc(pathStr, &childrenCount);
762: if (childrenCount < 0) {
763: XVFS_DEBUG_PRINTF("... error: %s", xvfs_strerror(childrenCount));
764:
765: Tcl_DecrRefCount(path);
766:
767: xvfs_setresults_error(interp, childrenCount);
768:
769: XVFS_DEBUG_LEAVE;
770: return(TCL_ERROR);
771: }
772:
773: for (idx = 0; idx < childrenCount; idx++) {
774: child = children[idx];
775:
776: if (!Tcl_StringMatch(child, pattern)) {
777: continue;
778: }
779:
780: childObj = Tcl_DuplicateObj(path);
781: Tcl_IncrRefCount(childObj);
782: Tcl_AppendStringsToObj(childObj, "/", child, NULL);
783:
784: if (!xvfs_tclfs_verifyType(childObj, types, instanceInfo)) {
785: Tcl_DecrRefCount(childObj);
786:
787: continue;
788: }
789:
790: tclRetVal = Tcl_ListObjAppendElement(interp, resultPtr, childObj);
791: Tcl_DecrRefCount(childObj);
792:
793: if (tclRetVal != TCL_OK) {
794: XVFS_DEBUG_PUTS("... error (lappend)");
795: Tcl_DecrRefCount(path);
796:
797: XVFS_DEBUG_LEAVE;
798: return(tclRetVal);
799: }
800: }
801:
802: Tcl_DecrRefCount(path);
803:
804: XVFS_DEBUG_PRINTF("... ok (returning items: %s)", Tcl_GetString(resultPtr));
805:
806: XVFS_DEBUG_LEAVE;
807: return(TCL_OK);
808: }
809: #endif /* XVFS_MODE_SERVER || XVFS_MODE_STANDALONE || XVFS_MODE_FLEIXBLE */
810:
811: #if defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
812: /*
813: * Tcl_Filesystem handlers for the standalone implementation
814: */
815: static struct xvfs_tclfs_instance_info xvfs_tclfs_standalone_info;
816: static int xvfs_tclfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) {
817: return(xvfs_tclfs_pathInFilesystem(path, dataPtr, &xvfs_tclfs_standalone_info));
818: }
819:
820: static int xvfs_tclfs_standalone_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) {
821: return(xvfs_tclfs_stat(path, statBuf, &xvfs_tclfs_standalone_info));
822: }
823:
824: static int xvfs_tclfs_standalone_access(Tcl_Obj *path, int mode) {
825: return(xvfs_tclfs_access(path, mode, &xvfs_tclfs_standalone_info));
826: }
827:
828: static Tcl_Channel xvfs_tclfs_standalone_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) {
829: return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, &xvfs_tclfs_standalone_info));
830: }
831:
832: static int xvfs_tclfs_standalone_matchInDir(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) {
833: return(xvfs_tclfs_matchInDir(interp, resultPtr, pathPtr, pattern, types, &xvfs_tclfs_standalone_info));
834: }
835:
836: /*
837: * There are three (3) modes of operation for Xvfs_Register:
838: * 1. standalone -- We register our own Tcl_Filesystem
839: * and handle requests under `//xvfs:/<fsName>`
840: * 2. client -- A single Tcl_Filesystem is registered for the
841: * interp to handle requests under `//xvfs:/` which
842: * then dispatches to the appropriate registered
843: * handler
844: * 3. flexible -- Attempts to find a core Xvfs instance for the
845: * process at runtime, if found do #2, otherwise
846: * fallback to #1
847: *
848: */
849: static Tcl_Filesystem xvfs_tclfs_standalone_fs;
850: static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
851: int tclRet;
852: static int registered = 0;
853:
854: /*
855: * Ensure this instance is not already registered
856: */
857: if (registered) {
858: return(TCL_OK);
859: }
860: registered = 1;
861:
862: /*
863: * In standalone mode, we only support the same protocol we are
864: * compiling for.
865: */
866: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
867: if (interp) {
868: Tcl_SetResult(interp, "Protocol mismatch", NULL);
869: }
870: return(TCL_ERROR);
871: }
872:
873: xvfs_tclfs_standalone_fs.typeName = "xvfsInstance";
874: xvfs_tclfs_standalone_fs.structureLength = sizeof(xvfs_tclfs_standalone_fs);
875: xvfs_tclfs_standalone_fs.version = TCL_FILESYSTEM_VERSION_1;
876: xvfs_tclfs_standalone_fs.pathInFilesystemProc = xvfs_tclfs_standalone_pathInFilesystem;
877: xvfs_tclfs_standalone_fs.dupInternalRepProc = NULL;
878: xvfs_tclfs_standalone_fs.freeInternalRepProc = NULL;
879: xvfs_tclfs_standalone_fs.internalToNormalizedProc = NULL;
880: xvfs_tclfs_standalone_fs.createInternalRepProc = NULL;
881: xvfs_tclfs_standalone_fs.normalizePathProc = NULL;
882: xvfs_tclfs_standalone_fs.filesystemPathTypeProc = NULL;
883: xvfs_tclfs_standalone_fs.filesystemSeparatorProc = NULL;
884: xvfs_tclfs_standalone_fs.statProc = xvfs_tclfs_standalone_stat;
885: xvfs_tclfs_standalone_fs.accessProc = xvfs_tclfs_standalone_access;
886: xvfs_tclfs_standalone_fs.openFileChannelProc = xvfs_tclfs_standalone_openFileChannel;
887: xvfs_tclfs_standalone_fs.matchInDirectoryProc = xvfs_tclfs_standalone_matchInDir;
888: xvfs_tclfs_standalone_fs.utimeProc = NULL;
889: xvfs_tclfs_standalone_fs.linkProc = NULL;
890: xvfs_tclfs_standalone_fs.listVolumesProc = NULL;
891: xvfs_tclfs_standalone_fs.fileAttrStringsProc = NULL;
892: xvfs_tclfs_standalone_fs.fileAttrsGetProc = NULL;
893: xvfs_tclfs_standalone_fs.fileAttrsSetProc = NULL;
894: xvfs_tclfs_standalone_fs.createDirectoryProc = NULL;
895: xvfs_tclfs_standalone_fs.removeDirectoryProc = NULL;
896: xvfs_tclfs_standalone_fs.deleteFileProc = NULL;
897: xvfs_tclfs_standalone_fs.copyFileProc = NULL;
898: xvfs_tclfs_standalone_fs.renameFileProc = NULL;
899: xvfs_tclfs_standalone_fs.copyDirectoryProc = NULL;
900: xvfs_tclfs_standalone_fs.lstatProc = NULL;
901: xvfs_tclfs_standalone_fs.loadFileProc = NULL;
902: xvfs_tclfs_standalone_fs.getCwdProc = NULL;
903: xvfs_tclfs_standalone_fs.chdirProc = NULL;
904:
905: xvfs_tclfs_standalone_info.fsInfo = fsInfo;
906: xvfs_tclfs_standalone_info.mountpoint = Tcl_NewObj();
907:
908: Tcl_IncrRefCount(xvfs_tclfs_standalone_info.mountpoint);
909: Tcl_AppendStringsToObj(xvfs_tclfs_standalone_info.mountpoint, XVFS_ROOT_MOUNTPOINT, fsInfo->name, NULL);
910:
911: tclRet = Tcl_FSRegister(NULL, &xvfs_tclfs_standalone_fs);
912: if (tclRet != TCL_OK) {
913: Tcl_DecrRefCount(xvfs_tclfs_standalone_info.mountpoint);
914:
915: if (interp) {
916: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
917: }
918:
919: return(tclRet);
920: }
921:
922: xvfs_tclfs_prepareChannelType();
923:
924: return(TCL_OK);
925: }
926: #endif /* XVFS_MODE_STANDALONE || XVFS_MODE_FLEXIBLE */
927:
928: #if defined(XVFS_MODE_FLEXIBLE)
929: static int xvfs_flexible_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
930: ClientData fsHandlerDataRaw;
931: struct xvfs_tclfs_server_info *fsHandlerData;
932: const Tcl_Filesystem *fsHandler;
933: int (*xvfs_register)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
934: Tcl_Obj *rootPathObj;
935:
936: XVFS_DEBUG_ENTER;
937:
938: xvfs_register = &xvfs_standalone_register;
939:
940: rootPathObj = Tcl_NewStringObj(XVFS_ROOT_MOUNTPOINT, -1);
941: if (!rootPathObj) {
942: XVFS_DEBUG_LEAVE;
943:
944: return(xvfs_register(interp, fsInfo));
945: }
946:
947: Tcl_IncrRefCount(rootPathObj);
948: fsHandler = Tcl_FSGetFileSystemForPath(rootPathObj);
949: Tcl_DecrRefCount(rootPathObj);
950:
951: if (!fsHandler) {
952: XVFS_DEBUG_LEAVE;
953:
954: return(xvfs_register(interp, fsInfo));
955: }
956:
957: fsHandlerDataRaw = Tcl_FSData(fsHandler);
958: if (!fsHandlerDataRaw) {
959: XVFS_DEBUG_LEAVE;
960:
961: return(xvfs_register(interp, fsInfo));
962: }
963:
964: fsHandlerData = (struct xvfs_tclfs_server_info *) fsHandlerDataRaw;
965:
966: /*
967: * XXX:TODO: What is the chance that the handler for //xvfs:/ hold
968: * client data smaller than XVFS_INTERNAL_SERVER_MAGIC_LEN ?
969: */
970: if (memcmp(fsHandlerData->magic, XVFS_INTERNAL_SERVER_MAGIC, sizeof(fsHandlerData->magic)) == 0) {
971: XVFS_DEBUG_PUTS("Found a server handler");
972: xvfs_register = fsHandlerData->registerProc;
973: }
974:
975: XVFS_DEBUG_LEAVE;
976:
977: return(xvfs_register(interp, fsInfo));
978: }
979: #endif /* XVFS_MODE_FLEXIBLE */
980:
981: #if defined(XVFS_MODE_SERVER)
982: static Tcl_Filesystem xvfs_tclfs_dispatch_fs;
983: static Tcl_HashTable xvfs_tclfs_dispatch_map;
984: static struct xvfs_tclfs_server_info xvfs_tclfs_dispatch_fsdata;
985:
986: static int xvfs_tclfs_dispatch_pathInFS(Tcl_Obj *path, ClientData *dataPtr) {
987: const char *pathStr, *rootStr;
988: int pathLen, rootLen;
989:
990: XVFS_DEBUG_ENTER;
991:
992: XVFS_DEBUG_PRINTF("Verifying that \"%s\" belongs in XVFS ...", Tcl_GetString(path));
993:
994: path = xvfs_absolutePath(path);
995:
996: rootStr = XVFS_ROOT_MOUNTPOINT;
997: rootLen = strlen(XVFS_ROOT_MOUNTPOINT);
998:
999: pathStr = Tcl_GetStringFromObj(path, &pathLen);
1000:
1001: if (pathLen < rootLen) {
1002: Tcl_DecrRefCount(path);
1003:
1004: XVFS_DEBUG_PUTS("... failed (length too short)");
1005: XVFS_DEBUG_LEAVE;
1006: return(-1);
1007: }
1008:
1009: if (memcmp(pathStr, rootStr, rootLen) != 0) {
1010: Tcl_DecrRefCount(path);
1011:
1012: XVFS_DEBUG_PUTS("... failed (incorrect prefix)");
1013: XVFS_DEBUG_LEAVE;
1014: return(-1);
1015: }
1016:
1017: Tcl_DecrRefCount(path);
1018:
1019: XVFS_DEBUG_PUTS("... yes");
1020:
1021: XVFS_DEBUG_LEAVE;
1022:
1023: return(TCL_OK);
1024: }
1025:
1026: static struct xvfs_tclfs_instance_info *xvfs_tclfs_dispatch_pathToInfo(Tcl_Obj *path) {
1027: Tcl_HashEntry *mapEntry;
1028: struct xvfs_tclfs_instance_info *retval;
1029: int rootLen;
1030: char *pathStr, *fsName, *fsNameEnds, origSep;
1031:
1032: XVFS_DEBUG_ENTER;
1033:
1034: path = xvfs_absolutePath(path);
1035:
1036: if (xvfs_tclfs_dispatch_pathInFS(path, NULL) != TCL_OK) {
1037: Tcl_DecrRefCount(path);
1038:
1039: XVFS_DEBUG_LEAVE;
1040:
1041: return(NULL);
1042: }
1043:
1044: rootLen = strlen(XVFS_ROOT_MOUNTPOINT);
1045: pathStr = Tcl_GetString(path);
1046:
1047: fsName = ((char *) pathStr) + rootLen;
1048:
1049: fsNameEnds = strchr(fsName, '/');
1050: if (fsNameEnds) {
1051: origSep = *fsNameEnds;
1052: *fsNameEnds = '\0';
1053: }
1054:
1055: XVFS_DEBUG_PRINTF("... fsName = %s...", fsName);
1056:
1057: mapEntry = Tcl_FindHashEntry(&xvfs_tclfs_dispatch_map, fsName);
1058:
1059: if (fsNameEnds) {
1060: *fsNameEnds = origSep;
1061: }
1062:
1063: if (mapEntry) {
1064: retval = (struct xvfs_tclfs_instance_info *) Tcl_GetHashValue(mapEntry);
1065: XVFS_DEBUG_PRINTF("... found a registered filesystem: %p", retval);
1066: } else {
1067: retval = NULL;
1068: XVFS_DEBUG_PUTS("... found no registered filesystem.");
1069: }
1070:
1071: Tcl_DecrRefCount(path);
1072:
1073: XVFS_DEBUG_LEAVE;
1074: return(retval);
1075:
1076: /*
1077: * UNREACH: We do no need the more specific check because we
1078: * claim everything under the root, but we want to suppress
1079: * a warning about it not being used.
1080: */
1081: xvfs_tclfs_pathInFilesystem(NULL, NULL, NULL);
1082: return(NULL);
1083: }
1084:
1085: static int xvfs_tclfs_dispatch_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) {
1086: struct xvfs_tclfs_instance_info *instanceInfo;
1087:
1088: instanceInfo = xvfs_tclfs_dispatch_pathToInfo(path);
1089: if (!instanceInfo) {
1090: Tcl_SetErrno(xvfs_errorToErrno(XVFS_RV_ERR_ENOENT));
1091:
1092: return(-1);
1093: }
1094:
1095: return(xvfs_tclfs_stat(path, statBuf, instanceInfo));
1096: }
1097:
1098: static int xvfs_tclfs_dispatch_access(Tcl_Obj *path, int mode) {
1099: struct xvfs_tclfs_instance_info *instanceInfo;
1100:
1101: instanceInfo = xvfs_tclfs_dispatch_pathToInfo(path);
1102: if (!instanceInfo) {
1103: return(-1);
1104: }
1105:
1106: return(xvfs_tclfs_access(path, mode, instanceInfo));
1107: }
1108:
1109: static Tcl_Channel xvfs_tclfs_dispatch_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) {
1110: struct xvfs_tclfs_instance_info *instanceInfo;
1111:
1112: instanceInfo = xvfs_tclfs_dispatch_pathToInfo(path);
1113: if (!instanceInfo) {
1114: return(NULL);
1115: }
1116:
1117: return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, instanceInfo));
1118: }
1119:
1120: static int xvfs_tclfs_dispatch_matchInDir(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) {
1121: struct xvfs_tclfs_instance_info *instanceInfo;
1122:
1123: instanceInfo = xvfs_tclfs_dispatch_pathToInfo(pathPtr);
1124: if (!instanceInfo) {
1125: return(TCL_ERROR);
1126: }
1127:
1128: return(xvfs_tclfs_matchInDir(interp, resultPtr, pathPtr, pattern, types, instanceInfo));
1129: }
1130:
1131: int Xvfs_Init(Tcl_Interp *interp) {
1132: static int registered = 0;
1133: int tclRet;
1134: #ifdef USE_TCL_STUBS
1135: const char *tclInitStubs_ret;
1136: #endif
1137:
1138: /* XXX:TODO: Make this thread-safe */
1139: if (registered) {
1140: return(TCL_OK);
1141: }
1142: registered = 1;
1143:
1144: #ifdef USE_TCL_STUBS
1145: /* Initialize Stubs */
1146: tclInitStubs_ret = Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0);
1147: if (!tclInitStubs_ret) {
1148: return(TCL_ERROR);
1149: }
1150: #endif
1151:
1152: xvfs_tclfs_dispatch_fs.typeName = "xvfsDispatch";
1153: xvfs_tclfs_dispatch_fs.structureLength = sizeof(xvfs_tclfs_dispatch_fs);
1154: xvfs_tclfs_dispatch_fs.version = TCL_FILESYSTEM_VERSION_1;
1155: xvfs_tclfs_dispatch_fs.pathInFilesystemProc = xvfs_tclfs_dispatch_pathInFS;
1156: xvfs_tclfs_dispatch_fs.dupInternalRepProc = NULL;
1157: xvfs_tclfs_dispatch_fs.freeInternalRepProc = NULL;
1158: xvfs_tclfs_dispatch_fs.internalToNormalizedProc = NULL;
1159: xvfs_tclfs_dispatch_fs.createInternalRepProc = NULL;
1160: xvfs_tclfs_dispatch_fs.normalizePathProc = NULL;
1161: xvfs_tclfs_dispatch_fs.filesystemPathTypeProc = NULL;
1162: xvfs_tclfs_dispatch_fs.filesystemSeparatorProc = NULL;
1163: xvfs_tclfs_dispatch_fs.statProc = xvfs_tclfs_dispatch_stat;
1164: xvfs_tclfs_dispatch_fs.accessProc = xvfs_tclfs_dispatch_access;
1165: xvfs_tclfs_dispatch_fs.openFileChannelProc = xvfs_tclfs_dispatch_openFileChannel;
1166: xvfs_tclfs_dispatch_fs.matchInDirectoryProc = xvfs_tclfs_dispatch_matchInDir;
1167: xvfs_tclfs_dispatch_fs.utimeProc = NULL;
1168: xvfs_tclfs_dispatch_fs.linkProc = NULL;
1169: xvfs_tclfs_dispatch_fs.listVolumesProc = NULL;
1170: xvfs_tclfs_dispatch_fs.fileAttrStringsProc = NULL;
1171: xvfs_tclfs_dispatch_fs.fileAttrsGetProc = NULL;
1172: xvfs_tclfs_dispatch_fs.fileAttrsSetProc = NULL;
1173: xvfs_tclfs_dispatch_fs.createDirectoryProc = NULL;
1174: xvfs_tclfs_dispatch_fs.removeDirectoryProc = NULL;
1175: xvfs_tclfs_dispatch_fs.deleteFileProc = NULL;
1176: xvfs_tclfs_dispatch_fs.copyFileProc = NULL;
1177: xvfs_tclfs_dispatch_fs.renameFileProc = NULL;
1178: xvfs_tclfs_dispatch_fs.copyDirectoryProc = NULL;
1179: xvfs_tclfs_dispatch_fs.lstatProc = NULL;
1180: xvfs_tclfs_dispatch_fs.loadFileProc = NULL;
1181: xvfs_tclfs_dispatch_fs.getCwdProc = NULL;
1182: xvfs_tclfs_dispatch_fs.chdirProc = NULL;
1183:
1184: memcpy(xvfs_tclfs_dispatch_fsdata.magic, XVFS_INTERNAL_SERVER_MAGIC, XVFS_INTERNAL_SERVER_MAGIC_LEN);
1185: xvfs_tclfs_dispatch_fsdata.registerProc = Xvfs_Register;
1186:
1187: tclRet = Tcl_FSRegister((ClientData) &xvfs_tclfs_dispatch_fsdata, &xvfs_tclfs_dispatch_fs);
1188: if (tclRet != TCL_OK) {
1189: if (interp) {
1190: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
1191: }
1192:
1193: return(tclRet);
1194: }
1195:
1196: /*
1197: * Initialize the channel type we will use for I/O
1198: */
1199: xvfs_tclfs_prepareChannelType();
1200:
1201: /*
1202: * Initialize the map to lookup paths to registered
1203: * filesystems
1204: */
1205: Tcl_InitHashTable(&xvfs_tclfs_dispatch_map, TCL_STRING_KEYS);
1206:
1207: return(TCL_OK);
1208: }
1209:
1210: int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
1211: Tcl_HashEntry *mapEntry;
1212: struct xvfs_tclfs_instance_info *instanceInfo;
1213: int dispatchInitRet;
1214: int new;
1215:
1216: dispatchInitRet = Xvfs_Init(interp);
1217: if (dispatchInitRet != TCL_OK) {
1218: return(dispatchInitRet);
1219: }
1220:
1221: /*
1222: * Verify this is for a protocol we support
1223: */
1224: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
1225: if (interp) {
1226: Tcl_SetResult(interp, "Protocol mismatch", NULL);
1227: }
1228: return(TCL_ERROR);
1229: }
1230:
1231: /*
1232: * Create the structure needed
1233: */
1234: instanceInfo = (struct xvfs_tclfs_instance_info *) Tcl_Alloc(sizeof(*instanceInfo));
1235: instanceInfo->fsInfo = fsInfo;
1236: instanceInfo->mountpoint = Tcl_ObjPrintf("%s%s", XVFS_ROOT_MOUNTPOINT, fsInfo->name);
1237: Tcl_IncrRefCount(instanceInfo->mountpoint);
1238:
1239: /*
1240: * Register a hash table entry for this name
1241: */
1242: new = 0;
1243: mapEntry = Tcl_CreateHashEntry(&xvfs_tclfs_dispatch_map, fsInfo->name, &new);
1244: Tcl_SetHashValue(mapEntry, instanceInfo);
1245:
1246: return(TCL_OK);
1247: }
1248: #endif /* XVFS_MODE_SERVER */
1249: #undef XVFS_DEBUG_PRINTF
1250: #undef XVFS_DEBUG_PUTS
1251: #undef XVFS_DEBUG_ENTER
1252: #undef XVFS_DEBUG_LEAVE
1253: #undef XVFS_INTERNAL_SERVER_MAGIC
1254: #undef XVFS_INTERNAL_SERVER_MAGIC_LEN
1255: #undef XVFS_ROOT_MOUNTPOINT