Annotation For xvfs-core.c

Lines of xvfs-core.c from check-in 717062426a that are changed by the sequence of edits moving toward check-in d17d8bb449:

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