Lines of
xvfs-core.c
from check-in bdabc41e51
that are changed by the sequence of edits moving toward
check-in 4221e5dcbc:
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)
bdabc41e51 2019-09-18 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: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
397: event->tcl.proc = xvfs_tclfs_watchChannelEvent;
398: event->tcl.nextPtr = NULL;
399: event->channelInstanceData = channelInstanceData;
400:
401: channelInstanceData->queuedEvents++;
402:
403: Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
404:
405: return;
406: }
407:
408: static int xvfs_tclfs_seekChannel(ClientData channelInstanceData_p, long offset, int mode, int *errorCodePtr) {
409: struct xvfs_tclfs_channel_id *channelInstanceData;
410: Tcl_WideInt newOffset, fileSize;
411:
412: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
413:
414: newOffset = channelInstanceData->currentOffset;
415: fileSize = channelInstanceData->fileSize;
416:
417: switch (mode) {
418: case SEEK_CUR:
419: newOffset += offset;
420: break;
421: case SEEK_SET:
422: newOffset = offset;
423: break;
424: case SEEK_END:
425: newOffset = fileSize + offset;
426: break;
427: default:
428: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
429:
430: return(-1);
431: }
432:
433: /*
434: * We allow users to seek right up to the end of the buffer, but
435: * no further, this way if they want to seek backwards from there
436: * it is possible to do so.
437: */
438: if (newOffset < 0 || newOffset > fileSize) {
439: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
440:
441: return(-1);
442: }
443:
444: if (newOffset != channelInstanceData->currentOffset) {
445: channelInstanceData->eofMarked = 0;
446: channelInstanceData->currentOffset = newOffset;
447: }
448:
449: return(channelInstanceData->currentOffset);
450: }
451:
452: static void xvfs_tclfs_prepareChannelType(void) {
453: xvfs_tclfs_channelType.typeName = "xvfs";
454: xvfs_tclfs_channelType.version = TCL_CHANNEL_VERSION_2;
455: xvfs_tclfs_channelType.closeProc = xvfs_tclfs_closeChannel;
456: xvfs_tclfs_channelType.inputProc = xvfs_tclfs_readChannel;
457: xvfs_tclfs_channelType.outputProc = NULL;
458: xvfs_tclfs_channelType.watchProc = xvfs_tclfs_watchChannel;
459: xvfs_tclfs_channelType.getHandleProc = NULL;
460: xvfs_tclfs_channelType.seekProc = xvfs_tclfs_seekChannel;
461: xvfs_tclfs_channelType.setOptionProc = NULL;
462: xvfs_tclfs_channelType.getOptionProc = NULL;
463: xvfs_tclfs_channelType.close2Proc = NULL;
464: xvfs_tclfs_channelType.blockModeProc = NULL;
465: xvfs_tclfs_channelType.flushProc = NULL;
466: xvfs_tclfs_channelType.handlerProc = NULL;
467: xvfs_tclfs_channelType.wideSeekProc = NULL;
468: xvfs_tclfs_channelType.threadActionProc = NULL;
469: xvfs_tclfs_channelType.truncateProc = NULL;
470: }
471:
472: /*
473: * Internal Tcl_Filesystem functions, with the appropriate instance info
474: */
475: static int xvfs_tclfs_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr, struct xvfs_tclfs_instance_info *instanceInfo) {
476: const char *relativePath;
477: int retval;
478:
479: XVFS_DEBUG_ENTER;
480:
481: XVFS_DEBUG_PRINTF("Checking to see if path \"%s\" is in the filesystem ...", Tcl_GetString(path));
482:
483: path = xvfs_absolutePath(path);
484:
485: relativePath = xvfs_relativePath(path, instanceInfo);
486:
487: retval = TCL_OK;
488: if (!relativePath) {
489: retval = -1;
490: }
491:
492: Tcl_DecrRefCount(path);
493:
494: XVFS_DEBUG_PRINTF("... %s", retval == -1 ? "no" : "yes");
495:
496: XVFS_DEBUG_LEAVE;
497: return(retval);
498: }
499:
500: static int xvfs_tclfs_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf, struct xvfs_tclfs_instance_info *instanceInfo) {
501: const char *pathStr;
502: int retval;
503:
504: XVFS_DEBUG_ENTER;
505:
506: XVFS_DEBUG_PRINTF("Getting stat() on \"%s\" ...", Tcl_GetString(path));
507:
508: path = xvfs_absolutePath(path);
509:
510: pathStr = xvfs_relativePath(path, instanceInfo);
511:
512: retval = instanceInfo->fsInfo->getStatProc(pathStr, statBuf);
513: if (retval < 0) {
514: XVFS_DEBUG_PRINTF("... failed: %s", xvfs_strerror(retval));
515:
516: Tcl_SetErrno(xvfs_errorToErrno(retval));
517:
518: retval = -1;
519: } else {
520: XVFS_DEBUG_PUTS("... ok");
521: }
522:
523: Tcl_DecrRefCount(path);
524:
525: XVFS_DEBUG_LEAVE;
526: return(retval);
527: }
528:
529: static int xvfs_tclfs_access(Tcl_Obj *path, int mode, struct xvfs_tclfs_instance_info *instanceInfo) {
530: const char *pathStr;
531: Tcl_StatBuf fileInfo;
532: int statRetVal;
533:
534: XVFS_DEBUG_ENTER;
535:
536: XVFS_DEBUG_PRINTF("Getting access(..., %i) on \"%s\" ...", mode, Tcl_GetString(path));
537:
538: if (mode & W_OK) {
539: XVFS_DEBUG_PUTS("... no (not writable)");
540:
541: XVFS_DEBUG_LEAVE;
542: return(-1);
543: }
544:
545: path = xvfs_absolutePath(path);
546:
547: pathStr = xvfs_relativePath(path, instanceInfo);
548: if (!pathStr) {
549: XVFS_DEBUG_PUTS("... no (not in our path)");
550:
551: Tcl_DecrRefCount(path);
552:
553: XVFS_DEBUG_LEAVE;
554: return(-1);
555: }
556:
557: statRetVal = instanceInfo->fsInfo->getStatProc(pathStr, &fileInfo);
558: if (statRetVal < 0) {
559: XVFS_DEBUG_PUTS("... no (not statable)");
560:
561: Tcl_DecrRefCount(path);
562:
563: XVFS_DEBUG_LEAVE;
564: return(-1);
565: }
566:
567: if (mode & X_OK) {
568: if (!(fileInfo.st_mode & 040000)) {
569: XVFS_DEBUG_PUTS("... no (not a directory and X_OK specified)");
570:
571: Tcl_DecrRefCount(path);
572:
573: XVFS_DEBUG_LEAVE;
574: return(-1);
575: }
576: }
577:
578: Tcl_DecrRefCount(path);
579:
580: XVFS_DEBUG_PUTS("... ok");
581:
582: XVFS_DEBUG_LEAVE;
583: return(0);
584: }
585:
586: static Tcl_Channel xvfs_tclfs_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions, struct xvfs_tclfs_instance_info *instanceInfo) {
587: Tcl_Channel retval;
588: Tcl_Obj *pathRel;
589: const char *pathStr;
590:
591: XVFS_DEBUG_ENTER;
592:
593: XVFS_DEBUG_PRINTF("Asked to open(\"%s\", %x)...", Tcl_GetString(path), mode);
594:
595: if (mode & O_WRONLY) {
596: XVFS_DEBUG_PUTS("... failed (asked to open for writing)");
597:
598: xvfs_setresults_error(interp, XVFS_RV_ERR_EROFS);
599:
600: XVFS_DEBUG_LEAVE;
601: return(NULL);
602: }
603:
604: path = xvfs_absolutePath(path);
605:
606: pathStr = xvfs_relativePath(path, instanceInfo);
607:
608: pathRel = Tcl_NewStringObj(pathStr, -1);
609:
610: Tcl_DecrRefCount(path);
611:
612: XVFS_DEBUG_PUTS("... done, passing off to channel handler");
613:
614: retval = xvfs_tclfs_openChannel(interp, pathRel, instanceInfo);
615:
616: XVFS_DEBUG_LEAVE;
617: return(retval);
618: }
619:
620: static int xvfs_tclfs_verifyType(Tcl_Obj *path, Tcl_GlobTypeData *types, struct xvfs_tclfs_instance_info *instanceInfo) {
621: const char *pathStr;
622: Tcl_StatBuf fileInfo;
623: int statRetVal;
624:
625: XVFS_DEBUG_ENTER;
626:
627: if (types) {
628: 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);
629: } else {
630: XVFS_DEBUG_PRINTF("Asked to verify the existence \"%s\" ...", Tcl_GetString(path));
631: }
632:
633: statRetVal = xvfs_tclfs_stat(path, &fileInfo, instanceInfo);
634: if (statRetVal != 0) {
635: XVFS_DEBUG_PUTS("... no (cannot stat)");
636:
637: XVFS_DEBUG_LEAVE;
638: return(0);
639: }
640:
641: if (!types) {
642: XVFS_DEBUG_PUTS("... yes");
643:
644: XVFS_DEBUG_LEAVE;
645: return(1);
646: }
647:
648: if (types->perm != TCL_GLOB_PERM_RONLY) {
649: if (types->perm & (TCL_GLOB_PERM_W | TCL_GLOB_PERM_HIDDEN)) {
650: XVFS_DEBUG_PUTS("... no (checked for writable or hidden, not supported)");
651:
652: XVFS_DEBUG_LEAVE;
653: return(0);
654: }
655:
656: if ((types->perm & TCL_GLOB_PERM_X) == TCL_GLOB_PERM_X) {
657: if (!(fileInfo.st_mode & 040000)) {
658: XVFS_DEBUG_PUTS("... no (checked for executable but not a directory)");
659:
660: XVFS_DEBUG_LEAVE;
661: return(0);
662: }
663: }
664: }
665:
666: if (types->type & (TCL_GLOB_TYPE_BLOCK | TCL_GLOB_TYPE_CHAR | TCL_GLOB_TYPE_PIPE | TCL_GLOB_TYPE_SOCK | TCL_GLOB_TYPE_LINK)) {
667: XVFS_DEBUG_PUTS("... no (checked for block, char, pipe, sock, or link, not supported)");
668:
669: XVFS_DEBUG_LEAVE;
670: return(0);
671: }
672:
673: if ((types->type & TCL_GLOB_TYPE_DIR) == TCL_GLOB_TYPE_DIR) {
674: if (!(fileInfo.st_mode & 040000)) {
675: XVFS_DEBUG_PUTS("... no (checked for directory but not a directory)");
676:
677: XVFS_DEBUG_LEAVE;
678: return(0);
679: }
680: }
681:
682: if ((types->type & TCL_GLOB_TYPE_FILE) == TCL_GLOB_TYPE_FILE) {
683: if (!(fileInfo.st_mode & 0100000)) {
684: XVFS_DEBUG_PUTS("... no (checked for file but not a file)");
685:
686: XVFS_DEBUG_LEAVE;
687: return(0);
688: }
689: }
690:
691: if ((types->type & TCL_GLOB_TYPE_MOUNT) == TCL_GLOB_TYPE_MOUNT) {
692: path = xvfs_absolutePath(path);
693: pathStr = xvfs_relativePath(path, instanceInfo);
694: if (!pathStr) {
695: XVFS_DEBUG_PUTS("... no (checked for mount but not able to resolve path)");
696:
697: Tcl_DecrRefCount(path);
698:
699: XVFS_DEBUG_LEAVE;
700: return(0);
701: }
702:
703: if (strlen(pathStr) != 0) {
704: XVFS_DEBUG_PUTS("... no (checked for mount but not our top-level directory)");
705:
706: Tcl_DecrRefCount(path);
707:
708: XVFS_DEBUG_LEAVE;
709: return(0);
710: }
711:
712: Tcl_DecrRefCount(path);
713: }
714:
715: XVFS_DEBUG_PUTS("... yes");
716:
717: XVFS_DEBUG_LEAVE;
718: return(1);
719: }
720:
721: 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) {
722: const char *pathStr;
723: const char **children, *child;
724: Tcl_WideInt childrenCount, idx;
725: Tcl_Obj *childObj;
726: int tclRetVal;
727:
728: if (pattern == NULL) {
729: if (xvfs_tclfs_verifyType(path, types, instanceInfo)) {
730: return(TCL_OK);
731: }
732:
733: return(TCL_ERROR);
734: }
735:
736: XVFS_DEBUG_ENTER;
737:
738: path = xvfs_absolutePath(path);
739:
740: if (types) {
741: XVFS_DEBUG_PRINTF("Checking for files matching %s in \"%s\" and type=%i and perm=%i ...", pattern, Tcl_GetString(path), types->type, types->perm);
742: } else {
743: XVFS_DEBUG_PRINTF("Checking for files matching %s in \"%s\" ...", pattern, Tcl_GetString(path));
744: }
745:
746: pathStr = xvfs_relativePath(path, instanceInfo);
747: if (!pathStr) {
748: XVFS_DEBUG_PUTS("... error (not in our VFS)");
749:
750: Tcl_DecrRefCount(path);
751:
752: xvfs_setresults_error(interp, XVFS_RV_ERR_ENOENT);
753:
754: XVFS_DEBUG_LEAVE;
755: return(TCL_OK);
756: }
757:
758: childrenCount = 0;
759: children = instanceInfo->fsInfo->getChildrenProc(pathStr, &childrenCount);
760: if (childrenCount < 0) {
761: XVFS_DEBUG_PRINTF("... error: %s", xvfs_strerror(childrenCount));
762:
763: Tcl_DecrRefCount(path);
764:
765: xvfs_setresults_error(interp, childrenCount);
766:
767: XVFS_DEBUG_LEAVE;
768: return(TCL_ERROR);
769: }
770:
771: for (idx = 0; idx < childrenCount; idx++) {
772: child = children[idx];
773:
774: if (!Tcl_StringMatch(child, pattern)) {
775: continue;
776: }
777:
778: childObj = Tcl_DuplicateObj(path);
779: Tcl_IncrRefCount(childObj);
780: Tcl_AppendStringsToObj(childObj, "/", child, NULL);
781:
782: if (!xvfs_tclfs_verifyType(childObj, types, instanceInfo)) {
783: Tcl_DecrRefCount(childObj);
784:
785: continue;
786: }
787:
788: tclRetVal = Tcl_ListObjAppendElement(interp, resultPtr, childObj);
789: Tcl_DecrRefCount(childObj);
790:
791: if (tclRetVal != TCL_OK) {
792: XVFS_DEBUG_PUTS("... error (lappend)");
793: Tcl_DecrRefCount(path);
794:
795: XVFS_DEBUG_LEAVE;
796: return(tclRetVal);
797: }
798: }
799:
800: Tcl_DecrRefCount(path);
801:
802: XVFS_DEBUG_PRINTF("... ok (returning items: %s)", Tcl_GetString(resultPtr));
803:
804: XVFS_DEBUG_LEAVE;
805: return(TCL_OK);
806: }
807: #endif /* XVFS_MODE_SERVER || XVFS_MODE_STANDALONE || XVFS_MODE_FLEIXBLE */
808:
809: #if defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
810: /*
811: * Tcl_Filesystem handlers for the standalone implementation
812: */
813: static struct xvfs_tclfs_instance_info xvfs_tclfs_standalone_info;
814: static int xvfs_tclfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) {
815: return(xvfs_tclfs_pathInFilesystem(path, dataPtr, &xvfs_tclfs_standalone_info));
816: }
817:
818: static int xvfs_tclfs_standalone_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) {
819: return(xvfs_tclfs_stat(path, statBuf, &xvfs_tclfs_standalone_info));
820: }
821:
822: static int xvfs_tclfs_standalone_access(Tcl_Obj *path, int mode) {
823: return(xvfs_tclfs_access(path, mode, &xvfs_tclfs_standalone_info));
824: }
825:
826: static Tcl_Channel xvfs_tclfs_standalone_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) {
827: return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, &xvfs_tclfs_standalone_info));
828: }
829:
830: static int xvfs_tclfs_standalone_matchInDir(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) {
831: return(xvfs_tclfs_matchInDir(interp, resultPtr, pathPtr, pattern, types, &xvfs_tclfs_standalone_info));
832: }
833:
834: /*
835: * There are three (3) modes of operation for Xvfs_Register:
836: * 1. standalone -- We register our own Tcl_Filesystem
837: * and handle requests under `//xvfs:/<fsName>`
838: * 2. client -- A single Tcl_Filesystem is registered for the
839: * interp to handle requests under `//xvfs:/` which
840: * then dispatches to the appropriate registered
841: * handler
842: * 3. flexible -- Attempts to find a core Xvfs instance for the
843: * process at runtime, if found do #2, otherwise
844: * fallback to #1
845: *
846: */
847: static Tcl_Filesystem xvfs_tclfs_standalone_fs;
848: static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
849: int tclRet;
850: static int registered = 0;
851:
852: /*
853: * Ensure this instance is not already registered
854: */
855: if (registered) {
856: return(TCL_OK);
857: }
858: registered = 1;
859:
860: /*
861: * In standalone mode, we only support the same protocol we are
862: * compiling for.
863: */
864: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
865: if (interp) {
866: Tcl_SetResult(interp, "Protocol mismatch", NULL);
867: }
868: return(TCL_ERROR);
869: }
870:
871: xvfs_tclfs_standalone_fs.typeName = "xvfsInstance";
872: xvfs_tclfs_standalone_fs.structureLength = sizeof(xvfs_tclfs_standalone_fs);
873: xvfs_tclfs_standalone_fs.version = TCL_FILESYSTEM_VERSION_1;
874: xvfs_tclfs_standalone_fs.pathInFilesystemProc = xvfs_tclfs_standalone_pathInFilesystem;
875: xvfs_tclfs_standalone_fs.dupInternalRepProc = NULL;
876: xvfs_tclfs_standalone_fs.freeInternalRepProc = NULL;
877: xvfs_tclfs_standalone_fs.internalToNormalizedProc = NULL;
878: xvfs_tclfs_standalone_fs.createInternalRepProc = NULL;
879: xvfs_tclfs_standalone_fs.normalizePathProc = NULL;
880: xvfs_tclfs_standalone_fs.filesystemPathTypeProc = NULL;
881: xvfs_tclfs_standalone_fs.filesystemSeparatorProc = NULL;
882: xvfs_tclfs_standalone_fs.statProc = xvfs_tclfs_standalone_stat;
883: xvfs_tclfs_standalone_fs.accessProc = xvfs_tclfs_standalone_access;
884: xvfs_tclfs_standalone_fs.openFileChannelProc = xvfs_tclfs_standalone_openFileChannel;
885: xvfs_tclfs_standalone_fs.matchInDirectoryProc = xvfs_tclfs_standalone_matchInDir;
886: xvfs_tclfs_standalone_fs.utimeProc = NULL;
887: xvfs_tclfs_standalone_fs.linkProc = NULL;
888: xvfs_tclfs_standalone_fs.listVolumesProc = NULL;
889: xvfs_tclfs_standalone_fs.fileAttrStringsProc = NULL;
890: xvfs_tclfs_standalone_fs.fileAttrsGetProc = NULL;
891: xvfs_tclfs_standalone_fs.fileAttrsSetProc = NULL;
892: xvfs_tclfs_standalone_fs.createDirectoryProc = NULL;
893: xvfs_tclfs_standalone_fs.removeDirectoryProc = NULL;
894: xvfs_tclfs_standalone_fs.deleteFileProc = NULL;
895: xvfs_tclfs_standalone_fs.copyFileProc = NULL;
896: xvfs_tclfs_standalone_fs.renameFileProc = NULL;
897: xvfs_tclfs_standalone_fs.copyDirectoryProc = NULL;
898: xvfs_tclfs_standalone_fs.lstatProc = NULL;
899: xvfs_tclfs_standalone_fs.loadFileProc = NULL;
900: xvfs_tclfs_standalone_fs.getCwdProc = NULL;
901: xvfs_tclfs_standalone_fs.chdirProc = NULL;
902:
903: xvfs_tclfs_standalone_info.fsInfo = fsInfo;
904: xvfs_tclfs_standalone_info.mountpoint = Tcl_NewObj();
905:
906: Tcl_IncrRefCount(xvfs_tclfs_standalone_info.mountpoint);
907: Tcl_AppendStringsToObj(xvfs_tclfs_standalone_info.mountpoint, XVFS_ROOT_MOUNTPOINT, fsInfo->name, NULL);
908:
909: tclRet = Tcl_FSRegister(NULL, &xvfs_tclfs_standalone_fs);
910: if (tclRet != TCL_OK) {
911: Tcl_DecrRefCount(xvfs_tclfs_standalone_info.mountpoint);
912:
913: if (interp) {
914: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
915: }
916:
917: return(tclRet);
918: }
919:
920: xvfs_tclfs_prepareChannelType();
921:
922: return(TCL_OK);
923: }
924: #endif /* XVFS_MODE_STANDALONE || XVFS_MODE_FLEXIBLE */
925:
926: #if defined(XVFS_MODE_FLEXIBLE)
927: static int xvfs_flexible_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
928: ClientData fsHandlerDataRaw;
929: struct xvfs_tclfs_server_info *fsHandlerData;
930: const Tcl_Filesystem *fsHandler;
931: int (*xvfs_register)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
932: Tcl_Obj *rootPathObj;
933:
934: XVFS_DEBUG_ENTER;
935:
936: xvfs_register = &xvfs_standalone_register;
937:
938: rootPathObj = Tcl_NewStringObj(XVFS_ROOT_MOUNTPOINT, -1);
939: if (!rootPathObj) {
940: XVFS_DEBUG_LEAVE;
941:
942: return(xvfs_register(interp, fsInfo));
943: }
944:
945: Tcl_IncrRefCount(rootPathObj);
946: fsHandler = Tcl_FSGetFileSystemForPath(rootPathObj);
947: Tcl_DecrRefCount(rootPathObj);
948:
949: if (!fsHandler) {
950: XVFS_DEBUG_LEAVE;
951:
952: return(xvfs_register(interp, fsInfo));
953: }
954:
955: fsHandlerDataRaw = Tcl_FSData(fsHandler);
956: if (!fsHandlerDataRaw) {
957: XVFS_DEBUG_LEAVE;
958:
959: return(xvfs_register(interp, fsInfo));
960: }
961:
962: fsHandlerData = (struct xvfs_tclfs_server_info *) fsHandlerDataRaw;
963:
964: /*
965: * XXX:TODO: What is the chance that the handler for //xvfs:/ hold
966: * client data smaller than XVFS_INTERNAL_SERVER_MAGIC_LEN ?
967: */
968: if (memcmp(fsHandlerData->magic, XVFS_INTERNAL_SERVER_MAGIC, sizeof(fsHandlerData->magic)) == 0) {
969: XVFS_DEBUG_PUTS("Found a server handler");
970: xvfs_register = fsHandlerData->registerProc;
971: }
972:
973: XVFS_DEBUG_LEAVE;
974:
975: return(xvfs_register(interp, fsInfo));
976: }
977: #endif /* XVFS_MODE_FLEXIBLE */
978:
979: #if defined(XVFS_MODE_SERVER)
980: static Tcl_Filesystem xvfs_tclfs_dispatch_fs;
981: static Tcl_HashTable xvfs_tclfs_dispatch_map;
982: static struct xvfs_tclfs_server_info xvfs_tclfs_dispatch_fsdata;
983:
984: static int xvfs_tclfs_dispatch_pathInFS(Tcl_Obj *path, ClientData *dataPtr) {
985: const char *pathStr, *rootStr;
986: int pathLen, rootLen;
987:
988: XVFS_DEBUG_ENTER;
989:
990: XVFS_DEBUG_PRINTF("Verifying that \"%s\" belongs in XVFS ...", Tcl_GetString(path));
bdabc41e51 2019-09-18 991:
992: rootStr = XVFS_ROOT_MOUNTPOINT;
993: rootLen = strlen(XVFS_ROOT_MOUNTPOINT);
994:
995: pathStr = Tcl_GetStringFromObj(path, &pathLen);
996:
997: if (pathLen < rootLen) {
998: XVFS_DEBUG_PUTS("... failed (length too short)");
999: XVFS_DEBUG_LEAVE;
1000: return(-1);
1001: }
1002:
1003: if (memcmp(pathStr, rootStr, rootLen) != 0) {
1004: XVFS_DEBUG_PUTS("... failed (incorrect prefix)");
1005: XVFS_DEBUG_LEAVE;
1006: return(-1);
1007: }
1008:
1009: XVFS_DEBUG_PUTS("... yes");
1010:
1011: XVFS_DEBUG_LEAVE;
1012:
1013: return(TCL_OK);
1014: }
1015:
1016: static struct xvfs_tclfs_instance_info *xvfs_tclfs_dispatch_pathToInfo(Tcl_Obj *path) {
1017: Tcl_HashEntry *mapEntry;
1018: struct xvfs_tclfs_instance_info *retval;
1019: int rootLen;
1020: char *pathStr, *fsName, *fsNameEnds, origSep;
1021:
1022: XVFS_DEBUG_ENTER;
1023:
1024: if (xvfs_tclfs_dispatch_pathInFS(path, NULL) != TCL_OK) {
1025: XVFS_DEBUG_LEAVE;
1026:
1027: return(NULL);
1028: }
1029:
1030: rootLen = strlen(XVFS_ROOT_MOUNTPOINT);
1031: pathStr = Tcl_GetString(path);
1032:
1033: fsName = ((char *) pathStr) + rootLen;
1034:
1035: fsNameEnds = strchr(fsName, '/');
1036: if (fsNameEnds) {
1037: origSep = *fsNameEnds;
1038: *fsNameEnds = '\0';
1039: }
1040:
1041: XVFS_DEBUG_PRINTF("... fsName = %s...", fsName);
1042:
1043: mapEntry = Tcl_FindHashEntry(&xvfs_tclfs_dispatch_map, fsName);
1044:
1045: if (fsNameEnds) {
1046: *fsNameEnds = origSep;
1047: }
1048:
1049: if (mapEntry) {
1050: retval = (struct xvfs_tclfs_instance_info *) Tcl_GetHashValue(mapEntry);
1051: XVFS_DEBUG_PRINTF("... found a registered filesystem: %p", retval);
1052: } else {
1053: retval = NULL;
1054: XVFS_DEBUG_PUTS("... found no registered filesystem.");
1055: }
1056:
1057: XVFS_DEBUG_LEAVE;
1058: return(retval);
1059:
1060: /*
1061: * UNREACH: We do no need the more specific check because we
1062: * claim everything under the root, but we want to suppress
1063: * a warning about it not being used.
1064: */
1065: xvfs_tclfs_pathInFilesystem(NULL, NULL, NULL);
1066: return(NULL);
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;
1118: #ifdef USE_TCL_STUBS
1119: const char *tclInitStubs_ret;
1120: #endif
1121:
1122: /* XXX:TODO: Make this thread-safe */
1123: if (registered) {
1124: return(TCL_OK);
1125: }
1126: registered = 1;
1127:
1128: #ifdef USE_TCL_STUBS
1129: /* Initialize Stubs */
1130: tclInitStubs_ret = Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0);
1131: if (!tclInitStubs_ret) {
1132: return(TCL_ERROR);
1133: }
1134: #endif
1135:
1136: xvfs_tclfs_dispatch_fs.typeName = "xvfsDispatch";
1137: xvfs_tclfs_dispatch_fs.structureLength = sizeof(xvfs_tclfs_dispatch_fs);
1138: xvfs_tclfs_dispatch_fs.version = TCL_FILESYSTEM_VERSION_1;
1139: xvfs_tclfs_dispatch_fs.pathInFilesystemProc = xvfs_tclfs_dispatch_pathInFS;
1140: xvfs_tclfs_dispatch_fs.dupInternalRepProc = NULL;
1141: xvfs_tclfs_dispatch_fs.freeInternalRepProc = NULL;
1142: xvfs_tclfs_dispatch_fs.internalToNormalizedProc = NULL;
1143: xvfs_tclfs_dispatch_fs.createInternalRepProc = NULL;
1144: xvfs_tclfs_dispatch_fs.normalizePathProc = NULL;
1145: xvfs_tclfs_dispatch_fs.filesystemPathTypeProc = NULL;
1146: xvfs_tclfs_dispatch_fs.filesystemSeparatorProc = NULL;
1147: xvfs_tclfs_dispatch_fs.statProc = xvfs_tclfs_dispatch_stat;
1148: xvfs_tclfs_dispatch_fs.accessProc = xvfs_tclfs_dispatch_access;
1149: xvfs_tclfs_dispatch_fs.openFileChannelProc = xvfs_tclfs_dispatch_openFileChannel;
1150: xvfs_tclfs_dispatch_fs.matchInDirectoryProc = xvfs_tclfs_dispatch_matchInDir;
1151: xvfs_tclfs_dispatch_fs.utimeProc = NULL;
1152: xvfs_tclfs_dispatch_fs.linkProc = NULL;
1153: xvfs_tclfs_dispatch_fs.listVolumesProc = NULL;
1154: xvfs_tclfs_dispatch_fs.fileAttrStringsProc = NULL;
1155: xvfs_tclfs_dispatch_fs.fileAttrsGetProc = NULL;
1156: xvfs_tclfs_dispatch_fs.fileAttrsSetProc = NULL;
1157: xvfs_tclfs_dispatch_fs.createDirectoryProc = NULL;
1158: xvfs_tclfs_dispatch_fs.removeDirectoryProc = NULL;
1159: xvfs_tclfs_dispatch_fs.deleteFileProc = NULL;
1160: xvfs_tclfs_dispatch_fs.copyFileProc = NULL;
1161: xvfs_tclfs_dispatch_fs.renameFileProc = NULL;
1162: xvfs_tclfs_dispatch_fs.copyDirectoryProc = NULL;
1163: xvfs_tclfs_dispatch_fs.lstatProc = NULL;
1164: xvfs_tclfs_dispatch_fs.loadFileProc = NULL;
1165: xvfs_tclfs_dispatch_fs.getCwdProc = NULL;
1166: xvfs_tclfs_dispatch_fs.chdirProc = NULL;
1167:
1168: memcpy(xvfs_tclfs_dispatch_fsdata.magic, XVFS_INTERNAL_SERVER_MAGIC, XVFS_INTERNAL_SERVER_MAGIC_LEN);
1169: xvfs_tclfs_dispatch_fsdata.registerProc = Xvfs_Register;
1170:
1171: tclRet = Tcl_FSRegister((ClientData) &xvfs_tclfs_dispatch_fsdata, &xvfs_tclfs_dispatch_fs);
1172: if (tclRet != TCL_OK) {
1173: if (interp) {
1174: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
1175: }
1176:
1177: return(tclRet);
1178: }
1179:
1180: /*
1181: * Initialize the channel type we will use for I/O
1182: */
1183: xvfs_tclfs_prepareChannelType();
1184:
1185: /*
1186: * Initialize the map to lookup paths to registered
1187: * filesystems
1188: */
1189: Tcl_InitHashTable(&xvfs_tclfs_dispatch_map, TCL_STRING_KEYS);
1190:
1191: return(TCL_OK);
1192: }
1193:
1194: int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
1195: Tcl_HashEntry *mapEntry;
1196: struct xvfs_tclfs_instance_info *instanceInfo;
1197: int dispatchInitRet;
1198: int new;
1199:
1200: dispatchInitRet = Xvfs_Init(interp);
1201: if (dispatchInitRet != TCL_OK) {
1202: return(dispatchInitRet);
1203: }
1204:
1205: /*
1206: * Verify this is for a protocol we support
1207: */
1208: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
1209: if (interp) {
1210: Tcl_SetResult(interp, "Protocol mismatch", NULL);
1211: }
1212: return(TCL_ERROR);
1213: }
1214:
1215: /*
1216: * Create the structure needed
1217: */
1218: instanceInfo = (struct xvfs_tclfs_instance_info *) Tcl_Alloc(sizeof(*instanceInfo));
1219: instanceInfo->fsInfo = fsInfo;
1220: instanceInfo->mountpoint = Tcl_ObjPrintf("%s%s", XVFS_ROOT_MOUNTPOINT, fsInfo->name);
1221: Tcl_IncrRefCount(instanceInfo->mountpoint);
1222:
1223: /*
1224: * Register a hash table entry for this name
1225: */
1226: new = 0;
1227: mapEntry = Tcl_CreateHashEntry(&xvfs_tclfs_dispatch_map, fsInfo->name, &new);
1228: Tcl_SetHashValue(mapEntry, instanceInfo);
1229:
1230: return(TCL_OK);
1231: }
1232: #endif /* XVFS_MODE_SERVER */
1233: #undef XVFS_DEBUG_PRINTF
1234: #undef XVFS_DEBUG_PUTS
1235: #undef XVFS_DEBUG_ENTER
1236: #undef XVFS_DEBUG_LEAVE
1237: #undef XVFS_INTERNAL_SERVER_MAGIC
1238: #undef XVFS_INTERNAL_SERVER_MAGIC_LEN
1239: #undef XVFS_ROOT_MOUNTPOINT