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