69e476dcd5 2019-05-02 1: #include <xvfs-core.h>
d121970301 2019-05-02 2: #include <string.h>
38bed7cee0 2019-09-13 3: #include <sys/stat.h>
38bed7cee0 2019-09-13 4: #include <errno.h>
38bed7cee0 2019-09-13 5: #include <fcntl.h>
69e476dcd5 2019-05-02 6: #include <tcl.h>
d92ba3d36d 2019-05-08 7:
d92ba3d36d 2019-05-08 8: #if defined(XVFS_MODE_FLEXIBLE) || defined(XVFS_MODE_SERVER)
d92ba3d36d 2019-05-08 9: #define XVFS_INTERNAL_SERVER_MAGIC "\xD4\xF3\x05\x96\x25\xCF\xAF\xFE"
d92ba3d36d 2019-05-08 10: #define XVFS_INTERNAL_SERVER_MAGIC_LEN 8
d92ba3d36d 2019-05-08 11:
d92ba3d36d 2019-05-08 12: struct xvfs_tclfs_server_info {
b586d5b0a1 2019-05-08 13: char magic[XVFS_INTERNAL_SERVER_MAGIC_LEN];
d92ba3d36d 2019-05-08 14: int (*registerProc)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
d92ba3d36d 2019-05-08 15: };
d92ba3d36d 2019-05-08 16: #endif /* XVFS_MODE_FLEXIBLE || XVFS_MODE_SERVER */
3e44e1def1 2019-05-02 17:
3e44e1def1 2019-05-02 18: #if defined(XVFS_MODE_SERVER) || defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
d121970301 2019-05-02 19: #define XVFS_ROOT_MOUNTPOINT "//xvfs:/"
d121970301 2019-05-02 20:
d121970301 2019-05-02 21: struct xvfs_tclfs_instance_info {
d121970301 2019-05-02 22: struct Xvfs_FSInfo *fsInfo;
d121970301 2019-05-02 23: Tcl_Obj *mountpoint;
d121970301 2019-05-02 24: };
d121970301 2019-05-02 25:
d121970301 2019-05-02 26: /*
d121970301 2019-05-02 27: * Internal Core Utilities
d121970301 2019-05-02 28: */
d121970301 2019-05-02 29: static const char *xvfs_relativePath(Tcl_Obj *path, struct xvfs_tclfs_instance_info *info) {
d121970301 2019-05-02 30: const char *pathStr, *rootStr;
d121970301 2019-05-02 31: int pathLen, rootLen;
38bed7cee0 2019-09-13 32:
d121970301 2019-05-02 33: pathStr = Tcl_GetStringFromObj(path, &pathLen);
d121970301 2019-05-02 34: rootStr = Tcl_GetStringFromObj(info->mountpoint, &rootLen);
38bed7cee0 2019-09-13 35:
d121970301 2019-05-02 36: if (pathLen < rootLen) {
d121970301 2019-05-02 37: return(NULL);
d121970301 2019-05-02 38: }
38bed7cee0 2019-09-13 39:
d121970301 2019-05-02 40: if (memcmp(pathStr, rootStr, rootLen) != 0) {
d121970301 2019-05-02 41: return(NULL);
d121970301 2019-05-02 42: }
38bed7cee0 2019-09-13 43:
d121970301 2019-05-02 44: if (pathLen == rootLen) {
d121970301 2019-05-02 45: return("");
d121970301 2019-05-02 46: }
d121970301 2019-05-02 47:
d121970301 2019-05-02 48: /* XXX:TODO: Should this use the native OS path separator ? */
d121970301 2019-05-02 49: if (pathStr[rootLen] != '/') {
d121970301 2019-05-02 50: return(NULL);
d121970301 2019-05-02 51: }
38bed7cee0 2019-09-13 52:
d121970301 2019-05-02 53: return(pathStr + rootLen + 1);
149aa89b7d 2019-09-13 54: }
149aa89b7d 2019-09-13 55:
38bed7cee0 2019-09-13 56: #if 0
38bed7cee0 2019-09-13 57: /*
38bed7cee0 2019-09-13 58: * Currently unused
38bed7cee0 2019-09-13 59: */
149aa89b7d 2019-09-13 60: static const char *xvfs_perror(int xvfs_error) {
149aa89b7d 2019-09-13 61: if (xvfs_error >= 0) {
149aa89b7d 2019-09-13 62: return("Not an error");
149aa89b7d 2019-09-13 63: }
149aa89b7d 2019-09-13 64:
149aa89b7d 2019-09-13 65: switch (xvfs_error) {
149aa89b7d 2019-09-13 66: case XVFS_RV_ERR_ENOENT:
149aa89b7d 2019-09-13 67: return("No such file or directory");
149aa89b7d 2019-09-13 68: case XVFS_RV_ERR_EINVAL:
149aa89b7d 2019-09-13 69: return("Invalid argument");
149aa89b7d 2019-09-13 70: case XVFS_RV_ERR_EISDIR:
149aa89b7d 2019-09-13 71: return("Is a directory");
149aa89b7d 2019-09-13 72: case XVFS_RV_ERR_ENOTDIR:
149aa89b7d 2019-09-13 73: return("Not a directory");
149aa89b7d 2019-09-13 74: case XVFS_RV_ERR_EFAULT:
149aa89b7d 2019-09-13 75: return("Bad address");
149aa89b7d 2019-09-13 76: default:
149aa89b7d 2019-09-13 77: return("Unknown error");
149aa89b7d 2019-09-13 78: }
149aa89b7d 2019-09-13 79: }
38bed7cee0 2019-09-13 80: #endif
38bed7cee0 2019-09-13 81:
38bed7cee0 2019-09-13 82: static int xvfs_errorToErrno(int xvfs_error) {
38bed7cee0 2019-09-13 83: if (xvfs_error >= 0) {
38bed7cee0 2019-09-13 84: return(0);
38bed7cee0 2019-09-13 85: }
38bed7cee0 2019-09-13 86:
38bed7cee0 2019-09-13 87: switch (xvfs_error) {
38bed7cee0 2019-09-13 88: case XVFS_RV_ERR_ENOENT:
38bed7cee0 2019-09-13 89: return(ENOENT);
38bed7cee0 2019-09-13 90: case XVFS_RV_ERR_EINVAL:
38bed7cee0 2019-09-13 91: return(EINVAL);
38bed7cee0 2019-09-13 92: case XVFS_RV_ERR_EISDIR:
38bed7cee0 2019-09-13 93: return(EISDIR);
38bed7cee0 2019-09-13 94: case XVFS_RV_ERR_ENOTDIR:
38bed7cee0 2019-09-13 95: return(ENOTDIR);
38bed7cee0 2019-09-13 96: case XVFS_RV_ERR_EFAULT:
38bed7cee0 2019-09-13 97: return(EFAULT);
38bed7cee0 2019-09-13 98: default:
38bed7cee0 2019-09-13 99: return(ERANGE);
38bed7cee0 2019-09-13 100: }
38bed7cee0 2019-09-13 101: }
38bed7cee0 2019-09-13 102:
38bed7cee0 2019-09-13 103: /*
38bed7cee0 2019-09-13 104: * Xvfs Memory Channel
38bed7cee0 2019-09-13 105: */
38bed7cee0 2019-09-13 106: struct xvfs_tclfs_channel_id {
38bed7cee0 2019-09-13 107: Tcl_Channel channel;
38bed7cee0 2019-09-13 108: struct xvfs_tclfs_instance_info *fsInstanceInfo;
38bed7cee0 2019-09-13 109: Tcl_Obj *path;
38bed7cee0 2019-09-13 110: Tcl_WideInt currentOffset;
38bed7cee0 2019-09-13 111: Tcl_WideInt fileSize;
7d74392642 2019-09-13 112: int eofMarked;
aa08a4a749 2019-09-14 113: int queuedEvents;
aa08a4a749 2019-09-14 114: int closed;
7d74392642 2019-09-13 115: };
7d74392642 2019-09-13 116: struct xvfs_tclfs_channel_event {
7d74392642 2019-09-13 117: Tcl_Event tcl;
7d74392642 2019-09-13 118: struct xvfs_tclfs_channel_id *channelInstanceData;
38bed7cee0 2019-09-13 119: };
38bed7cee0 2019-09-13 120: static Tcl_ChannelType xvfs_tclfs_channelType;
38bed7cee0 2019-09-13 121:
38bed7cee0 2019-09-13 122: static Tcl_Channel xvfs_tclfs_openChannel(Tcl_Obj *path, struct xvfs_tclfs_instance_info *instanceInfo) {
38bed7cee0 2019-09-13 123: struct xvfs_tclfs_channel_id *channelInstanceData;
38bed7cee0 2019-09-13 124: Tcl_Channel channel;
38bed7cee0 2019-09-13 125: Tcl_StatBuf fileInfo;
7d74392642 2019-09-13 126: Tcl_Obj *channelName;
38bed7cee0 2019-09-13 127: int statRet;
38bed7cee0 2019-09-13 128:
38bed7cee0 2019-09-13 129: statRet = instanceInfo->fsInfo->getStatProc(Tcl_GetString(path), &fileInfo);
38bed7cee0 2019-09-13 130: if (statRet < 0) {
38bed7cee0 2019-09-13 131: return(NULL);
38bed7cee0 2019-09-13 132: }
38bed7cee0 2019-09-13 133:
38bed7cee0 2019-09-13 134: channelInstanceData = (struct xvfs_tclfs_channel_id *) Tcl_Alloc(sizeof(*channelInstanceData));
38bed7cee0 2019-09-13 135: channelInstanceData->currentOffset = 0;
7d74392642 2019-09-13 136: channelInstanceData->eofMarked = 0;
aa08a4a749 2019-09-14 137: channelInstanceData->queuedEvents = 0;
aa08a4a749 2019-09-14 138: channelInstanceData->closed = 0;
38bed7cee0 2019-09-13 139: channelInstanceData->channel = NULL;
38bed7cee0 2019-09-13 140:
7d74392642 2019-09-13 141: channelName = Tcl_ObjPrintf("xvfs0x%llx", (unsigned long long) channelInstanceData);
7d74392642 2019-09-13 142: if (!channelName) {
7d74392642 2019-09-13 143: Tcl_Free((char *) channelInstanceData);
7d74392642 2019-09-13 144:
7d74392642 2019-09-13 145: return(NULL);
7d74392642 2019-09-13 146: }
7d74392642 2019-09-13 147: Tcl_IncrRefCount(channelName);
7d74392642 2019-09-13 148:
38bed7cee0 2019-09-13 149: channelInstanceData->fsInstanceInfo = instanceInfo;
38bed7cee0 2019-09-13 150: channelInstanceData->fileSize = fileInfo.st_size;
7d74392642 2019-09-13 151: channelInstanceData->path = path;
38bed7cee0 2019-09-13 152: Tcl_IncrRefCount(path);
38bed7cee0 2019-09-13 153:
7d74392642 2019-09-13 154: channel = Tcl_CreateChannel(&xvfs_tclfs_channelType, Tcl_GetString(channelName), channelInstanceData, TCL_READABLE);
7d74392642 2019-09-13 155: Tcl_DecrRefCount(channelName);
38bed7cee0 2019-09-13 156: if (!channel) {
38bed7cee0 2019-09-13 157: Tcl_DecrRefCount(path);
38bed7cee0 2019-09-13 158: Tcl_Free((char *) channelInstanceData);
38bed7cee0 2019-09-13 159:
38bed7cee0 2019-09-13 160: return(NULL);
38bed7cee0 2019-09-13 161: }
38bed7cee0 2019-09-13 162:
38bed7cee0 2019-09-13 163: channelInstanceData->channel = channel;
38bed7cee0 2019-09-13 164:
38bed7cee0 2019-09-13 165: return(channel);
38bed7cee0 2019-09-13 166: }
38bed7cee0 2019-09-13 167:
aa08a4a749 2019-09-14 168: static int xvfs_tclfs_closeChannel(ClientData channelInstanceData_p, Tcl_Interp *interp);
aa08a4a749 2019-09-14 169: static int xvfs_tclfs_closeChannelEvent(Tcl_Event *event_p, int flags) {
aa08a4a749 2019-09-14 170: struct xvfs_tclfs_channel_id *channelInstanceData;
aa08a4a749 2019-09-14 171: struct xvfs_tclfs_channel_event *event;
aa08a4a749 2019-09-14 172:
aa08a4a749 2019-09-14 173: event = (struct xvfs_tclfs_channel_event *) event_p;
aa08a4a749 2019-09-14 174: channelInstanceData = event->channelInstanceData;
aa08a4a749 2019-09-14 175:
aa08a4a749 2019-09-14 176: channelInstanceData->queuedEvents--;
aa08a4a749 2019-09-14 177:
aa08a4a749 2019-09-14 178: xvfs_tclfs_closeChannel((ClientData) channelInstanceData, NULL);
aa08a4a749 2019-09-14 179:
aa08a4a749 2019-09-14 180: return(1);
aa08a4a749 2019-09-14 181: }
aa08a4a749 2019-09-14 182:
38bed7cee0 2019-09-13 183: static int xvfs_tclfs_closeChannel(ClientData channelInstanceData_p, Tcl_Interp *interp) {
38bed7cee0 2019-09-13 184: struct xvfs_tclfs_channel_id *channelInstanceData;
aa08a4a749 2019-09-14 185: struct xvfs_tclfs_channel_event *event;
38bed7cee0 2019-09-13 186:
38bed7cee0 2019-09-13 187: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
aa08a4a749 2019-09-14 188:
aa08a4a749 2019-09-14 189: channelInstanceData->closed = 1;
aa08a4a749 2019-09-14 190:
aa08a4a749 2019-09-14 191: if (channelInstanceData->queuedEvents != 0) {
aa08a4a749 2019-09-14 192: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
aa08a4a749 2019-09-14 193: event->tcl.proc = xvfs_tclfs_closeChannelEvent;
aa08a4a749 2019-09-14 194: event->tcl.nextPtr = NULL;
aa08a4a749 2019-09-14 195: event->channelInstanceData = channelInstanceData;
aa08a4a749 2019-09-14 196:
aa08a4a749 2019-09-14 197: channelInstanceData->queuedEvents++;
aa08a4a749 2019-09-14 198:
aa08a4a749 2019-09-14 199: Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
aa08a4a749 2019-09-14 200:
aa08a4a749 2019-09-14 201: return(0);
aa08a4a749 2019-09-14 202: }
38bed7cee0 2019-09-13 203:
38bed7cee0 2019-09-13 204: Tcl_DecrRefCount(channelInstanceData->path);
38bed7cee0 2019-09-13 205: Tcl_Free((char *) channelInstanceData);
38bed7cee0 2019-09-13 206:
38bed7cee0 2019-09-13 207: return(0);
38bed7cee0 2019-09-13 208: }
38bed7cee0 2019-09-13 209:
38bed7cee0 2019-09-13 210: static int xvfs_tclfs_readChannel(ClientData channelInstanceData_p, char *buf, int bufSize, int *errorCodePtr) {
38bed7cee0 2019-09-13 211: struct xvfs_tclfs_channel_id *channelInstanceData;
38bed7cee0 2019-09-13 212: const unsigned char *data;
38bed7cee0 2019-09-13 213: Tcl_WideInt offset, length;
38bed7cee0 2019-09-13 214: char *path;
38bed7cee0 2019-09-13 215:
38bed7cee0 2019-09-13 216: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
38bed7cee0 2019-09-13 217:
7d74392642 2019-09-13 218: /*
7d74392642 2019-09-13 219: * If we are already at the end of the file we can skip
7d74392642 2019-09-13 220: * attempting to read it
7d74392642 2019-09-13 221: */
7d74392642 2019-09-13 222: if (channelInstanceData->eofMarked) {
7d74392642 2019-09-13 223: return(0);
7d74392642 2019-09-13 224: }
7d74392642 2019-09-13 225:
38bed7cee0 2019-09-13 226: path = Tcl_GetString(channelInstanceData->path);
38bed7cee0 2019-09-13 227: offset = channelInstanceData->currentOffset;
38bed7cee0 2019-09-13 228: length = bufSize;
38bed7cee0 2019-09-13 229:
38bed7cee0 2019-09-13 230: data = channelInstanceData->fsInstanceInfo->fsInfo->getDataProc(path, offset, &length);
38bed7cee0 2019-09-13 231:
38bed7cee0 2019-09-13 232: if (length < 0) {
38bed7cee0 2019-09-13 233: *errorCodePtr = xvfs_errorToErrno(length);
38bed7cee0 2019-09-13 234:
38bed7cee0 2019-09-13 235: return(-1);
38bed7cee0 2019-09-13 236: }
38bed7cee0 2019-09-13 237:
7d74392642 2019-09-13 238: if (length == 0) {
7d74392642 2019-09-13 239: channelInstanceData->eofMarked = 1;
7d74392642 2019-09-13 240: } else {
7d74392642 2019-09-13 241: memcpy(buf, data, length);
38bed7cee0 2019-09-13 242:
7d74392642 2019-09-13 243: channelInstanceData->currentOffset += length;
7d74392642 2019-09-13 244: }
38bed7cee0 2019-09-13 245:
38bed7cee0 2019-09-13 246: return(length);
38bed7cee0 2019-09-13 247: }
38bed7cee0 2019-09-13 248:
7d74392642 2019-09-13 249: static int xvfs_tclfs_watchChannelEvent(Tcl_Event *event_p, int flags) {
7d74392642 2019-09-13 250: struct xvfs_tclfs_channel_id *channelInstanceData;
7d74392642 2019-09-13 251: struct xvfs_tclfs_channel_event *event;
7d74392642 2019-09-13 252:
7d74392642 2019-09-13 253: event = (struct xvfs_tclfs_channel_event *) event_p;
7d74392642 2019-09-13 254: channelInstanceData = event->channelInstanceData;
7d74392642 2019-09-13 255:
aa08a4a749 2019-09-14 256: channelInstanceData->queuedEvents--;
aa08a4a749 2019-09-14 257:
aa08a4a749 2019-09-14 258: if (channelInstanceData->closed) {
aa08a4a749 2019-09-14 259: return(1);
aa08a4a749 2019-09-14 260: }
aa08a4a749 2019-09-14 261:
7d74392642 2019-09-13 262: Tcl_NotifyChannel(channelInstanceData->channel, TCL_READABLE);
7d74392642 2019-09-13 263:
aa08a4a749 2019-09-14 264: return(1);
7d74392642 2019-09-13 265: }
7d74392642 2019-09-13 266:
38bed7cee0 2019-09-13 267: static void xvfs_tclfs_watchChannel(ClientData channelInstanceData_p, int mask) {
7d74392642 2019-09-13 268: struct xvfs_tclfs_channel_id *channelInstanceData;
7d74392642 2019-09-13 269: struct xvfs_tclfs_channel_event *event;
7d74392642 2019-09-13 270:
38bed7cee0 2019-09-13 271: if ((mask & TCL_READABLE) != TCL_READABLE) {
38bed7cee0 2019-09-13 272: return;
38bed7cee0 2019-09-13 273: }
38bed7cee0 2019-09-13 274:
7d74392642 2019-09-13 275: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
7d74392642 2019-09-13 276:
7d74392642 2019-09-13 277: /*
7d74392642 2019-09-13 278: * If the read call has marked that we have reached EOF,
7d74392642 2019-09-13 279: * do not signal any further
7d74392642 2019-09-13 280: */
7d74392642 2019-09-13 281: if (channelInstanceData->eofMarked) {
7d74392642 2019-09-13 282: return;
7d74392642 2019-09-13 283: }
7d74392642 2019-09-13 284:
7d74392642 2019-09-13 285: event = (struct xvfs_tclfs_channel_event *) Tcl_Alloc(sizeof(*event));
7d74392642 2019-09-13 286: event->tcl.proc = xvfs_tclfs_watchChannelEvent;
7d74392642 2019-09-13 287: event->tcl.nextPtr = NULL;
7d74392642 2019-09-13 288: event->channelInstanceData = channelInstanceData;
aa08a4a749 2019-09-14 289:
aa08a4a749 2019-09-14 290: channelInstanceData->queuedEvents++;
7d74392642 2019-09-13 291:
7d74392642 2019-09-13 292: Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
7d74392642 2019-09-13 293:
38bed7cee0 2019-09-13 294: return;
38bed7cee0 2019-09-13 295: }
38bed7cee0 2019-09-13 296:
38bed7cee0 2019-09-13 297: static int xvfs_tclfs_seekChannel(ClientData channelInstanceData_p, long offset, int mode, int *errorCodePtr) {
38bed7cee0 2019-09-13 298: struct xvfs_tclfs_channel_id *channelInstanceData;
38bed7cee0 2019-09-13 299: Tcl_WideInt newOffset, fileSize;
38bed7cee0 2019-09-13 300:
38bed7cee0 2019-09-13 301: channelInstanceData = (struct xvfs_tclfs_channel_id *) channelInstanceData_p;
38bed7cee0 2019-09-13 302:
38bed7cee0 2019-09-13 303: newOffset = channelInstanceData->currentOffset;
38bed7cee0 2019-09-13 304: fileSize = channelInstanceData->fileSize;
38bed7cee0 2019-09-13 305:
38bed7cee0 2019-09-13 306: switch (mode) {
38bed7cee0 2019-09-13 307: case SEEK_CUR:
38bed7cee0 2019-09-13 308: newOffset += offset;
38bed7cee0 2019-09-13 309: break;
38bed7cee0 2019-09-13 310: case SEEK_SET:
38bed7cee0 2019-09-13 311: newOffset = offset;
38bed7cee0 2019-09-13 312: break;
38bed7cee0 2019-09-13 313: case SEEK_END:
38bed7cee0 2019-09-13 314: newOffset = fileSize + offset;
38bed7cee0 2019-09-13 315: break;
38bed7cee0 2019-09-13 316: default:
38bed7cee0 2019-09-13 317: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
38bed7cee0 2019-09-13 318:
38bed7cee0 2019-09-13 319: return(-1);
38bed7cee0 2019-09-13 320: }
38bed7cee0 2019-09-13 321:
38bed7cee0 2019-09-13 322: /*
38bed7cee0 2019-09-13 323: * We allow users to seek right up to the end of the buffer, but
38bed7cee0 2019-09-13 324: * no further, this way if they want to seek backwards from there
38bed7cee0 2019-09-13 325: * it is possible to do so.
38bed7cee0 2019-09-13 326: */
38bed7cee0 2019-09-13 327: if (newOffset < 0 || newOffset > fileSize) {
38bed7cee0 2019-09-13 328: *errorCodePtr = xvfs_errorToErrno(XVFS_RV_ERR_EINVAL);
38bed7cee0 2019-09-13 329:
38bed7cee0 2019-09-13 330: return(-1);
38bed7cee0 2019-09-13 331: }
38bed7cee0 2019-09-13 332:
7d74392642 2019-09-13 333: if (newOffset != channelInstanceData->currentOffset) {
7d74392642 2019-09-13 334: channelInstanceData->eofMarked = 0;
7d74392642 2019-09-13 335: channelInstanceData->currentOffset = newOffset;
7d74392642 2019-09-13 336: }
38bed7cee0 2019-09-13 337:
38bed7cee0 2019-09-13 338: return(channelInstanceData->currentOffset);
38bed7cee0 2019-09-13 339: }
38bed7cee0 2019-09-13 340:
38bed7cee0 2019-09-13 341: static void xvfs_tclfs_prepareChannelType(void) {
38bed7cee0 2019-09-13 342: xvfs_tclfs_channelType.typeName = "xvfs";
38bed7cee0 2019-09-13 343: xvfs_tclfs_channelType.version = TCL_CHANNEL_VERSION_2;
38bed7cee0 2019-09-13 344: xvfs_tclfs_channelType.closeProc = xvfs_tclfs_closeChannel;
38bed7cee0 2019-09-13 345: xvfs_tclfs_channelType.inputProc = xvfs_tclfs_readChannel;
38bed7cee0 2019-09-13 346: xvfs_tclfs_channelType.outputProc = NULL;
38bed7cee0 2019-09-13 347: xvfs_tclfs_channelType.watchProc = xvfs_tclfs_watchChannel;
38bed7cee0 2019-09-13 348: xvfs_tclfs_channelType.getHandleProc = NULL;
38bed7cee0 2019-09-13 349: xvfs_tclfs_channelType.seekProc = xvfs_tclfs_seekChannel;
38bed7cee0 2019-09-13 350: xvfs_tclfs_channelType.setOptionProc = NULL;
38bed7cee0 2019-09-13 351: xvfs_tclfs_channelType.getOptionProc = NULL;
38bed7cee0 2019-09-13 352: xvfs_tclfs_channelType.close2Proc = NULL;
38bed7cee0 2019-09-13 353: xvfs_tclfs_channelType.blockModeProc = NULL;
38bed7cee0 2019-09-13 354: xvfs_tclfs_channelType.flushProc = NULL;
38bed7cee0 2019-09-13 355: xvfs_tclfs_channelType.handlerProc = NULL;
38bed7cee0 2019-09-13 356: xvfs_tclfs_channelType.wideSeekProc = NULL;
38bed7cee0 2019-09-13 357: xvfs_tclfs_channelType.threadActionProc = NULL;
38bed7cee0 2019-09-13 358: xvfs_tclfs_channelType.truncateProc = NULL;
38bed7cee0 2019-09-13 359: }
d121970301 2019-05-02 360:
d121970301 2019-05-02 361: /*
d121970301 2019-05-02 362: * Internal Tcl_Filesystem functions, with the appropriate instance info
d121970301 2019-05-02 363: */
d121970301 2019-05-02 364: static int xvfs_tclfs_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr, struct xvfs_tclfs_instance_info *instanceInfo) {
d121970301 2019-05-02 365: const char *relativePath;
38bed7cee0 2019-09-13 366:
d121970301 2019-05-02 367: relativePath = xvfs_relativePath(path, instanceInfo);
d121970301 2019-05-02 368: if (!relativePath) {
d121970301 2019-05-02 369: return(-1);
d121970301 2019-05-02 370: }
38bed7cee0 2019-09-13 371:
d121970301 2019-05-02 372: return(TCL_OK);
d121970301 2019-05-02 373: }
d121970301 2019-05-02 374:
d121970301 2019-05-02 375: static int xvfs_tclfs_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf, struct xvfs_tclfs_instance_info *instanceInfo) {
d121970301 2019-05-02 376: const char *pathStr;
d121970301 2019-05-02 377: int retval;
d121970301 2019-05-02 378:
d121970301 2019-05-02 379: pathStr = xvfs_relativePath(path, instanceInfo);
38bed7cee0 2019-09-13 380:
daf25f5222 2019-05-03 381: retval = instanceInfo->fsInfo->getStatProc(pathStr, statBuf);
149aa89b7d 2019-09-13 382: if (retval < 0) {
149aa89b7d 2019-09-13 383: retval = -1;
149aa89b7d 2019-09-13 384: }
38bed7cee0 2019-09-13 385:
d121970301 2019-05-02 386: return(retval);
d121970301 2019-05-02 387: }
d121970301 2019-05-02 388:
d121970301 2019-05-02 389: static Tcl_Obj *xvfs_tclfs_listVolumes(struct xvfs_tclfs_instance_info *instanceInfo) {
d121970301 2019-05-02 390: return(NULL);
d121970301 2019-05-02 391: }
d121970301 2019-05-02 392:
d121970301 2019-05-02 393: static Tcl_Channel xvfs_tclfs_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions, struct xvfs_tclfs_instance_info *instanceInfo) {
d121970301 2019-05-02 394: const char *pathStr;
d121970301 2019-05-02 395:
d121970301 2019-05-02 396: pathStr = xvfs_relativePath(path, instanceInfo);
149aa89b7d 2019-09-13 397:
38bed7cee0 2019-09-13 398: if (mode & O_WRONLY) {
38bed7cee0 2019-09-13 399: return(NULL);
38bed7cee0 2019-09-13 400: }
9d3052c6f1 2019-05-08 401:
38bed7cee0 2019-09-13 402: return(xvfs_tclfs_openChannel(Tcl_NewStringObj(pathStr, -1), instanceInfo));
d121970301 2019-05-02 403: }
3e44e1def1 2019-05-02 404: #endif /* XVFS_MODE_SERVER || XVFS_MODE_STANDALONE || XVFS_MODE_FLEIXBLE */
d121970301 2019-05-02 405:
88f96696b7 2019-05-03 406: #if defined(XVFS_MODE_STANDALONE) || defined(XVFS_MODE_FLEXIBLE)
d121970301 2019-05-02 407: /*
d121970301 2019-05-02 408: * Tcl_Filesystem handlers for the standalone implementation
d121970301 2019-05-02 409: */
acfc5037c6 2019-05-02 410: static struct xvfs_tclfs_instance_info xvfs_tclfs_standalone_info;
d121970301 2019-05-02 411: static int xvfs_tclfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) {
d121970301 2019-05-02 412: return(xvfs_tclfs_pathInFilesystem(path, dataPtr, &xvfs_tclfs_standalone_info));
d121970301 2019-05-02 413: }
d121970301 2019-05-02 414:
d121970301 2019-05-02 415: static int xvfs_tclfs_standalone_stat(Tcl_Obj *path, Tcl_StatBuf *statBuf) {
d121970301 2019-05-02 416: return(xvfs_tclfs_stat(path, statBuf, &xvfs_tclfs_standalone_info));
e5b6962adf 2019-05-02 417: }
e5b6962adf 2019-05-02 418:
d121970301 2019-05-02 419: static Tcl_Obj *xvfs_tclfs_standalone_listVolumes(void) {
d121970301 2019-05-02 420: return(xvfs_tclfs_listVolumes(&xvfs_tclfs_standalone_info));
e5b6962adf 2019-05-02 421: }
e5b6962adf 2019-05-02 422:
d121970301 2019-05-02 423: static Tcl_Channel xvfs_tclfs_standalone_openFileChannel(Tcl_Interp *interp, Tcl_Obj *path, int mode, int permissions) {
d121970301 2019-05-02 424: return(xvfs_tclfs_openFileChannel(interp, path, mode, permissions, &xvfs_tclfs_standalone_info));
e5b6962adf 2019-05-02 425: }
32b55a907b 2019-05-02 426:
32b55a907b 2019-05-02 427: /*
32b55a907b 2019-05-02 428: * There are three (3) modes of operation for Xvfs_Register:
32b55a907b 2019-05-02 429: * 1. standalone -- We register our own Tcl_Filesystem
32b55a907b 2019-05-02 430: * and handle requests under `//xvfs:/<fsName>`
32b55a907b 2019-05-02 431: * 2. client -- A single Tcl_Filesystem is registered for the
32b55a907b 2019-05-02 432: * interp to handle requests under `//xvfs:/` which
32b55a907b 2019-05-02 433: * then dispatches to the appropriate registered
32b55a907b 2019-05-02 434: * handler
32b55a907b 2019-05-02 435: * 3. flexible -- Attempts to find a core Xvfs instance for the
32b55a907b 2019-05-02 436: * process at runtime, if found do #2, otherwise
32b55a907b 2019-05-02 437: * fallback to #1
32b55a907b 2019-05-02 438: *
32b55a907b 2019-05-02 439: */
cb77ecfb24 2019-05-06 440: static Tcl_Filesystem xvfs_tclfs_standalone_fs;
b8cca3a6b4 2019-05-08 441: static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
e5b6962adf 2019-05-02 442: int tcl_ret;
d121970301 2019-05-02 443: static int registered = 0;
38bed7cee0 2019-09-13 444:
d121970301 2019-05-02 445: /*
d121970301 2019-05-02 446: * Ensure this instance is not already registered
d121970301 2019-05-02 447: */
d121970301 2019-05-02 448: if (registered) {
d121970301 2019-05-02 449: return(TCL_OK);
d121970301 2019-05-02 450: }
d121970301 2019-05-02 451: registered = 1;
d121970301 2019-05-02 452:
e5b6962adf 2019-05-02 453: /*
e5b6962adf 2019-05-02 454: * In standalone mode, we only support the same protocol we are
e5b6962adf 2019-05-02 455: * compiling for.
e5b6962adf 2019-05-02 456: */
e5b6962adf 2019-05-02 457: if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) {
e5b6962adf 2019-05-02 458: if (interp) {
e5b6962adf 2019-05-02 459: Tcl_SetResult(interp, "Protocol mismatch", NULL);
e5b6962adf 2019-05-02 460: }
e5b6962adf 2019-05-02 461: return(TCL_ERROR);
e5b6962adf 2019-05-02 462: }
38bed7cee0 2019-09-13 463:
cb77ecfb24 2019-05-06 464: xvfs_tclfs_standalone_fs.typeName = "xvfs";
cb77ecfb24 2019-05-06 465: xvfs_tclfs_standalone_fs.structureLength = sizeof(xvfs_tclfs_standalone_fs);
cb77ecfb24 2019-05-06 466: xvfs_tclfs_standalone_fs.version = TCL_FILESYSTEM_VERSION_1;
cb77ecfb24 2019-05-06 467: xvfs_tclfs_standalone_fs.pathInFilesystemProc = xvfs_tclfs_standalone_pathInFilesystem;
cb77ecfb24 2019-05-06 468: xvfs_tclfs_standalone_fs.dupInternalRepProc = NULL;
cb77ecfb24 2019-05-06 469: xvfs_tclfs_standalone_fs.freeInternalRepProc = NULL;
cb77ecfb24 2019-05-06 470: xvfs_tclfs_standalone_fs.internalToNormalizedProc = NULL;
cb77ecfb24 2019-05-06 471: xvfs_tclfs_standalone_fs.createInternalRepProc = NULL;
cb77ecfb24 2019-05-06 472: xvfs_tclfs_standalone_fs.normalizePathProc = NULL;
cb77ecfb24 2019-05-06 473: xvfs_tclfs_standalone_fs.filesystemPathTypeProc = NULL;
cb77ecfb24 2019-05-06 474: xvfs_tclfs_standalone_fs.filesystemSeparatorProc = NULL;
cb77ecfb24 2019-05-06 475: xvfs_tclfs_standalone_fs.statProc = xvfs_tclfs_standalone_stat;
cb77ecfb24 2019-05-06 476: xvfs_tclfs_standalone_fs.accessProc = NULL;
cb77ecfb24 2019-05-06 477: xvfs_tclfs_standalone_fs.openFileChannelProc = xvfs_tclfs_standalone_openFileChannel;
38bed7cee0 2019-09-13 478: xvfs_tclfs_standalone_fs.matchInDirectoryProc = NULL; /* XXX:TODO */
cb77ecfb24 2019-05-06 479: xvfs_tclfs_standalone_fs.utimeProc = NULL;
cb77ecfb24 2019-05-06 480: xvfs_tclfs_standalone_fs.linkProc = NULL;
cb77ecfb24 2019-05-06 481: xvfs_tclfs_standalone_fs.listVolumesProc = xvfs_tclfs_standalone_listVolumes;
cb77ecfb24 2019-05-06 482: xvfs_tclfs_standalone_fs.fileAttrStringsProc = NULL;
cb77ecfb24 2019-05-06 483: xvfs_tclfs_standalone_fs.fileAttrsGetProc = NULL;
cb77ecfb24 2019-05-06 484: xvfs_tclfs_standalone_fs.fileAttrsSetProc = NULL;
cb77ecfb24 2019-05-06 485: xvfs_tclfs_standalone_fs.createDirectoryProc = NULL;
cb77ecfb24 2019-05-06 486: xvfs_tclfs_standalone_fs.removeDirectoryProc = NULL;
cb77ecfb24 2019-05-06 487: xvfs_tclfs_standalone_fs.deleteFileProc = NULL;
cb77ecfb24 2019-05-06 488: xvfs_tclfs_standalone_fs.copyFileProc = NULL;
cb77ecfb24 2019-05-06 489: xvfs_tclfs_standalone_fs.renameFileProc = NULL;
cb77ecfb24 2019-05-06 490: xvfs_tclfs_standalone_fs.copyDirectoryProc = NULL;
cb77ecfb24 2019-05-06 491: xvfs_tclfs_standalone_fs.lstatProc = NULL;
cb77ecfb24 2019-05-06 492: xvfs_tclfs_standalone_fs.loadFileProc = NULL;
cb77ecfb24 2019-05-06 493: xvfs_tclfs_standalone_fs.getCwdProc = NULL;
cb77ecfb24 2019-05-06 494: xvfs_tclfs_standalone_fs.chdirProc = NULL;
d121970301 2019-05-02 495:
d121970301 2019-05-02 496: xvfs_tclfs_standalone_info.fsInfo = fsInfo;
d121970301 2019-05-02 497: xvfs_tclfs_standalone_info.mountpoint = Tcl_NewObj();
d121970301 2019-05-02 498: Tcl_AppendStringsToObj(xvfs_tclfs_standalone_info.mountpoint, XVFS_ROOT_MOUNTPOINT, fsInfo->name, NULL);
38bed7cee0 2019-09-13 499:
cb77ecfb24 2019-05-06 500: tcl_ret = Tcl_FSRegister(NULL, &xvfs_tclfs_standalone_fs);
e5b6962adf 2019-05-02 501: if (tcl_ret != TCL_OK) {
e5b6962adf 2019-05-02 502: if (interp) {
e5b6962adf 2019-05-02 503: Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL);
e5b6962adf 2019-05-02 504: }
38bed7cee0 2019-09-13 505:
e5b6962adf 2019-05-02 506: return(tcl_ret);
e5b6962adf 2019-05-02 507: }
38bed7cee0 2019-09-13 508:
38bed7cee0 2019-09-13 509: xvfs_tclfs_prepareChannelType();
38bed7cee0 2019-09-13 510:
e5b6962adf 2019-05-02 511: return(TCL_OK);
e5b6962adf 2019-05-02 512: }
d92ba3d36d 2019-05-08 513: #endif /* XVFS_MODE_STANDALONE || XVFS_MODE_FLEXIBLE */
88f96696b7 2019-05-03 514:
88f96696b7 2019-05-03 515: #if defined(XVFS_MODE_FLEXIBLE)
b8cca3a6b4 2019-05-08 516: static int xvfs_flexible_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
9bcf758fef 2019-05-08 517: ClientData fsHandlerDataRaw;
9bcf758fef 2019-05-08 518: struct xvfs_tclfs_server_info *fsHandlerData;
9bcf758fef 2019-05-08 519: const Tcl_Filesystem *fsHandler;
9bcf758fef 2019-05-08 520: int (*xvfs_register)(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo);
9bcf758fef 2019-05-08 521: Tcl_Obj *rootPathObj;
9bcf758fef 2019-05-08 522:
9bcf758fef 2019-05-08 523: xvfs_register = &xvfs_standalone_register;
9bcf758fef 2019-05-08 524:
9bcf758fef 2019-05-08 525: rootPathObj = Tcl_NewStringObj(XVFS_ROOT_MOUNTPOINT, -1);
9bcf758fef 2019-05-08 526: if (!rootPathObj) {
9bcf758fef 2019-05-08 527: return(xvfs_register(interp, fsInfo));
9bcf758fef 2019-05-08 528: }
9bcf758fef 2019-05-08 529:
9bcf758fef 2019-05-08 530: Tcl_IncrRefCount(rootPathObj);
9bcf758fef 2019-05-08 531: fsHandler = Tcl_FSGetFileSystemForPath(rootPathObj);
9bcf758fef 2019-05-08 532: Tcl_DecrRefCount(rootPathObj);
9bcf758fef 2019-05-08 533:
9bcf758fef 2019-05-08 534: if (!fsHandler) {
9bcf758fef 2019-05-08 535: return(xvfs_register(interp, fsInfo));
9bcf758fef 2019-05-08 536: }
9bcf758fef 2019-05-08 537:
9bcf758fef 2019-05-08 538: fsHandlerDataRaw = Tcl_FSData(fsHandler);
9bcf758fef 2019-05-08 539: if (!fsHandlerDataRaw) {
9bcf758fef 2019-05-08 540: return(xvfs_register(interp, fsInfo));
9bcf758fef 2019-05-08 541: }
9bcf758fef 2019-05-08 542:
9bcf758fef 2019-05-08 543: fsHandlerData = (struct xvfs_tclfs_server_info *) fsHandlerDataRaw;
88f96696b7 2019-05-03 544:
88f96696b7 2019-05-03 545: /*
9bcf758fef 2019-05-08 546: * XXX:TODO: What is the chance that the handler for //xvfs:/ hold
b586d5b0a1 2019-05-08 547: * client data smaller than XVFS_INTERNAL_SERVER_MAGIC_LEN ?
88f96696b7 2019-05-03 548: */
b586d5b0a1 2019-05-08 549: if (memcmp(fsHandlerData->magic, XVFS_INTERNAL_SERVER_MAGIC, sizeof(fsHandlerData->magic)) == 0) {
9bcf758fef 2019-05-08 550: xvfs_register = fsHandlerData->registerProc;
88f96696b7 2019-05-03 551: }
9bcf758fef 2019-05-08 552:
88f96696b7 2019-05-03 553: return(xvfs_register(interp, fsInfo));
88f96696b7 2019-05-03 554: }
d92ba3d36d 2019-05-08 555: #endif /* XVFS_MODE_FLEXIBLE */
3e44e1def1 2019-05-02 556:
3e44e1def1 2019-05-02 557: #if defined(XVFS_MODE_SERVER)
e5b6962adf 2019-05-02 558: int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) {
acfc5037c6 2019-05-02 559: return(TCL_ERROR);
69e476dcd5 2019-05-02 560: }
d92ba3d36d 2019-05-08 561: #endif /* XVFS_MODE_SERVER */