1ecab39ce5 2019-05-02 1: #include <xvfs-core.h>
9d3052c6f1 2019-05-08 2: #include <sys/stat.h>
303b2de493 2019-05-02 3: #include <unistd.h>
32b55a907b 2019-05-02 4: #include <string.h>
303b2de493 2019-05-02 5: #include <tcl.h>
32b55a907b 2019-05-02 6:
32b55a907b 2019-05-02 7: #define XVFS_NAME_LOOKUP_ERROR (-1)
fb9dd5d783 2019-05-03 8: #define XVFS_FILE_BLOCKSIZE 1024
9d3052c6f1 2019-05-08 9:
3a68a54e44 2019-09-17 10: /*
3a68a54e44 2019-09-17 11: * XXX:TODO: Determine this automatically rather than
3a68a54e44 2019-09-17 12: * by heuristics
3a68a54e44 2019-09-17 13: */
3a68a54e44 2019-09-17 14: #define HAVE_STRUCT_STAT_ST_BLKSIZE 1
3a68a54e44 2019-09-17 15: #define HAVE_STRUCT_STAT_ST_BLOCKS 1
3a68a54e44 2019-09-17 16: #ifdef WIN32
3a68a54e44 2019-09-17 17: # undef HAVE_STRUCT_STAT_ST_BLKSIZE
3a68a54e44 2019-09-17 18: # undef HAVE_STRUCT_STAT_ST_BLOCKS
3a68a54e44 2019-09-17 19: #endif
3a68a54e44 2019-09-17 20:
32b55a907b 2019-05-02 21: #define MIN(a, b) (((a) < (b)) ? (a) : (b))
303b2de493 2019-05-02 22:
303b2de493 2019-05-02 23: typedef enum {
303b2de493 2019-05-02 24: XVFS_FILE_TYPE_REG,
303b2de493 2019-05-02 25: XVFS_FILE_TYPE_DIR
303b2de493 2019-05-02 26: } xvfs_file_type_t;
303b2de493 2019-05-02 27:
303b2de493 2019-05-02 28: typedef Tcl_WideInt xvfs_size_t;
303b2de493 2019-05-02 29:
303b2de493 2019-05-02 30: struct xvfs_file_data {
303b2de493 2019-05-02 31: const char *name;
303b2de493 2019-05-02 32: xvfs_file_type_t type;
303b2de493 2019-05-02 33: xvfs_size_t size;
32b55a907b 2019-05-02 34: union {
32b55a907b 2019-05-02 35: const unsigned char *fileContents;
32b55a907b 2019-05-02 36: const char **dirChildren;
32b55a907b 2019-05-02 37: } data;
303b2de493 2019-05-02 38: };
47dcf5fc27 2019-05-01 39:
47dcf5fc27 2019-05-01 40: <?
47dcf5fc27 2019-05-01 41: package require xvfs
c1c3fa70b5 2019-09-17 42:
c1c3fa70b5 2019-09-17 43: set ::xvfs::hashNameThreshold 3
c1c3fa70b5 2019-09-17 44: if {[info exists ::env(XVFS_CREATE_HASH_NAME_THRESHOLD)]} {
c1c3fa70b5 2019-09-17 45: set ::xvfs::hashNameThreshold $::env(XVFS_CREATE_HASH_NAME_THRESHOLD)
c1c3fa70b5 2019-09-17 46: }
69e476dcd5 2019-05-02 47: xvfs::main $argv
c1c3fa70b5 2019-09-17 48:
c1c3fa70b5 2019-09-17 49: proc emitFilenameVerification {indentLevel outputFileNameLen outputFileIndexes} {
c1c3fa70b5 2019-09-17 50: set indent [string repeat "\t" $indentLevel]
c1c3fa70b5 2019-09-17 51: foreach outputFileIndex $outputFileIndexes {
c1c3fa70b5 2019-09-17 52: ?><?= $indent ?>if (memcmp(path, xvfs_<?= $::xvfs::fsName ?>_data[<?= $outputFileIndex ?>].name, <?= $outputFileNameLen ?>) == 0) {
c1c3fa70b5 2019-09-17 53: <?= $indent ?> return(<?= $outputFileIndex ?>);
c1c3fa70b5 2019-09-17 54: <?= $indent ?>}
c1c3fa70b5 2019-09-17 55: <?
c1c3fa70b5 2019-09-17 56: }
c1c3fa70b5 2019-09-17 57: }
69e476dcd5 2019-05-02 58: ?>
32b55a907b 2019-05-02 59: static long xvfs_<?= $::xvfs::fsName ?>_nameToIndex(const char *path) {
c1c3fa70b5 2019-09-17 60: <?
c1c3fa70b5 2019-09-17 61: for {set index 0} {$index < [llength $::xvfs::outputFiles]} {incr index} {
c1c3fa70b5 2019-09-17 62: set outputFileName [lindex $::xvfs::outputFiles $index]
c1c3fa70b5 2019-09-17 63: set outputFileNameLen [string length $outputFileName]
c1c3fa70b5 2019-09-17 64: set outputFileNameHash [zlib adler32 $outputFileName 0]
c1c3fa70b5 2019-09-17 65: lappend outputFileNameHashToIndex([list $outputFileNameLen $outputFileNameHash]) $index
c1c3fa70b5 2019-09-17 66: lappend outputFileNameLenToIndex($outputFileNameLen) $index
c1c3fa70b5 2019-09-17 67: }
c1c3fa70b5 2019-09-17 68:
c1c3fa70b5 2019-09-17 69: set needZlib false
c1c3fa70b5 2019-09-17 70: foreach {outputFileNameLen outputFileIndexes} [lsort -stride 2 -dictionary [array get outputFileNameLenToIndex]] {
c1c3fa70b5 2019-09-17 71: if {[llength $outputFileIndexes] > $::xvfs::hashNameThreshold} {
c1c3fa70b5 2019-09-17 72: set needZlib true
c1c3fa70b5 2019-09-17 73: break;
c1c3fa70b5 2019-09-17 74: }
c1c3fa70b5 2019-09-17 75: }
c1c3fa70b5 2019-09-17 76: ?><?
c1c3fa70b5 2019-09-17 77: if {$needZlib} {
c1c3fa70b5 2019-09-17 78: ?> unsigned int pathHash;
c1c3fa70b5 2019-09-17 79: <? } ?> size_t pathLen;
fb9dd5d783 2019-05-03 80:
32b55a907b 2019-05-02 81: if (path == NULL) {
32b55a907b 2019-05-02 82: return(XVFS_NAME_LOOKUP_ERROR);
32b55a907b 2019-05-02 83: }
73cbe7370b 2019-05-03 84:
38bed7cee0 2019-09-13 85: pathLen = strlen(path);
c1c3fa70b5 2019-09-17 86: switch (pathLen) {
c1c3fa70b5 2019-09-17 87: <?
c1c3fa70b5 2019-09-17 88:
c1c3fa70b5 2019-09-17 89: foreach {outputFileNameLen outputFileIndexes} [lsort -stride 2 -dictionary [array get outputFileNameLenToIndex]] {
c1c3fa70b5 2019-09-17 90: ?> case <?= $outputFileNameLen ?>:
c1c3fa70b5 2019-09-17 91: <?
c1c3fa70b5 2019-09-17 92: if {[llength $outputFileIndexes] > $::xvfs::hashNameThreshold} {
c1c3fa70b5 2019-09-17 93: ?> pathHash = Tcl_ZlibAdler32(0, (const unsigned char *) path, <?= $outputFileNameLen ?>);
c1c3fa70b5 2019-09-17 94: switch (pathHash) {
c1c3fa70b5 2019-09-17 95: <?
c1c3fa70b5 2019-09-17 96: foreach {key outputFileIndexes} [lsort -stride 2 -dictionary [array get outputFileNameHashToIndex [list $outputFileNameLen *]]] {
c1c3fa70b5 2019-09-17 97: set outputFileNameHash [lindex $key 1]
c1c3fa70b5 2019-09-17 98: ?> case <?= $outputFileNameHash ?>:
c1c3fa70b5 2019-09-17 99: <?
c1c3fa70b5 2019-09-17 100: emitFilenameVerification 5 $outputFileNameLen $outputFileIndexes
c1c3fa70b5 2019-09-17 101: ?> break;
c1c3fa70b5 2019-09-17 102: <?
c1c3fa70b5 2019-09-17 103: }
c1c3fa70b5 2019-09-17 104: ?> }
c1c3fa70b5 2019-09-17 105: <?
c1c3fa70b5 2019-09-17 106: } else {
c1c3fa70b5 2019-09-17 107: emitFilenameVerification 3 $outputFileNameLen $outputFileIndexes
fb9dd5d783 2019-05-03 108: }
fb9dd5d783 2019-05-03 109: ?> break;
c1c3fa70b5 2019-09-17 110: <? } ?> }
fb9dd5d783 2019-05-03 111:
32b55a907b 2019-05-02 112: return(XVFS_NAME_LOOKUP_ERROR);
32b55a907b 2019-05-02 113: }
32b55a907b 2019-05-02 114:
32b55a907b 2019-05-02 115: static const char **xvfs_<?= $::xvfs::fsName ?>_getChildren(const char *path, Tcl_WideInt *count) {
32b55a907b 2019-05-02 116: struct xvfs_file_data *fileInfo;
32b55a907b 2019-05-02 117: long inode;
32b55a907b 2019-05-02 118:
32b55a907b 2019-05-02 119: /*
32b55a907b 2019-05-02 120: * Validate input parameters
32b55a907b 2019-05-02 121: */
32b55a907b 2019-05-02 122: if (count == NULL) {
32b55a907b 2019-05-02 123: return(NULL);
32b55a907b 2019-05-02 124: }
32b55a907b 2019-05-02 125:
32b55a907b 2019-05-02 126: /*
32b55a907b 2019-05-02 127: * Get the inode from the lookup function
32b55a907b 2019-05-02 128: */
32b55a907b 2019-05-02 129: inode = xvfs_<?= $::xvfs::fsName ?>_nameToIndex(path);
32b55a907b 2019-05-02 130: if (inode == XVFS_NAME_LOOKUP_ERROR) {
149aa89b7d 2019-09-13 131: *count = XVFS_RV_ERR_ENOENT;
32b55a907b 2019-05-02 132: return(NULL);
32b55a907b 2019-05-02 133: }
32b55a907b 2019-05-02 134:
32b55a907b 2019-05-02 135: fileInfo = &xvfs_<?= $::xvfs::fsName ?>_data[inode];
32b55a907b 2019-05-02 136:
32b55a907b 2019-05-02 137: /*
32b55a907b 2019-05-02 138: * Ensure this is a directory
32b55a907b 2019-05-02 139: */
32b55a907b 2019-05-02 140: if (fileInfo->type != XVFS_FILE_TYPE_DIR) {
149aa89b7d 2019-09-13 141: *count = XVFS_RV_ERR_ENOTDIR;
32b55a907b 2019-05-02 142: return(NULL);
32b55a907b 2019-05-02 143: }
32b55a907b 2019-05-02 144:
32b55a907b 2019-05-02 145: *count = fileInfo->size;
32b55a907b 2019-05-02 146: return(fileInfo->data.dirChildren);
32b55a907b 2019-05-02 147: }
32b55a907b 2019-05-02 148:
32b55a907b 2019-05-02 149: static const unsigned char *xvfs_<?= $::xvfs::fsName ?>_getData(const char *path, Tcl_WideInt start, Tcl_WideInt *length) {
32b55a907b 2019-05-02 150: struct xvfs_file_data *fileInfo;
32b55a907b 2019-05-02 151: Tcl_WideInt resultLength;
32b55a907b 2019-05-02 152: long inode;
32b55a907b 2019-05-02 153:
32b55a907b 2019-05-02 154: /*
32b55a907b 2019-05-02 155: * Validate input parameters
32b55a907b 2019-05-02 156: */
149aa89b7d 2019-09-13 157: if (length == NULL) {
32b55a907b 2019-05-02 158: return(NULL);
32b55a907b 2019-05-02 159: }
32b55a907b 2019-05-02 160:
149aa89b7d 2019-09-13 161: if (start < 0) {
149aa89b7d 2019-09-13 162: *length = XVFS_RV_ERR_EINVAL;
32b55a907b 2019-05-02 163: return(NULL);
32b55a907b 2019-05-02 164: }
32b55a907b 2019-05-02 165:
32b55a907b 2019-05-02 166: if (*length < 0) {
149aa89b7d 2019-09-13 167: *length = XVFS_RV_ERR_EINVAL;
32b55a907b 2019-05-02 168: return(NULL);
32b55a907b 2019-05-02 169: }
32b55a907b 2019-05-02 170:
32b55a907b 2019-05-02 171: /*
32b55a907b 2019-05-02 172: * Get the inode from the lookup function
32b55a907b 2019-05-02 173: */
32b55a907b 2019-05-02 174: inode = xvfs_<?= $::xvfs::fsName ?>_nameToIndex(path);
32b55a907b 2019-05-02 175: if (inode == XVFS_NAME_LOOKUP_ERROR) {
149aa89b7d 2019-09-13 176: *length = XVFS_RV_ERR_ENOENT;
32b55a907b 2019-05-02 177: return(NULL);
32b55a907b 2019-05-02 178: }
32b55a907b 2019-05-02 179:
32b55a907b 2019-05-02 180: fileInfo = &xvfs_<?= $::xvfs::fsName ?>_data[inode];
32b55a907b 2019-05-02 181:
32b55a907b 2019-05-02 182: /*
32b55a907b 2019-05-02 183: * Ensure this is a file that can be read
32b55a907b 2019-05-02 184: */
32b55a907b 2019-05-02 185: if (fileInfo->type != XVFS_FILE_TYPE_REG) {
149aa89b7d 2019-09-13 186: *length = XVFS_RV_ERR_EISDIR;
32b55a907b 2019-05-02 187: return(NULL);
32b55a907b 2019-05-02 188: }
32b55a907b 2019-05-02 189:
32b55a907b 2019-05-02 190: /*
32b55a907b 2019-05-02 191: * Validate the length
32b55a907b 2019-05-02 192: */
32b55a907b 2019-05-02 193: if (start > fileInfo->size) {
149aa89b7d 2019-09-13 194: *length = XVFS_RV_ERR_EFAULT;
32b55a907b 2019-05-02 195: return(NULL);
32b55a907b 2019-05-02 196: }
32b55a907b 2019-05-02 197:
32b55a907b 2019-05-02 198: if (*length == 0) {
32b55a907b 2019-05-02 199: resultLength = fileInfo->size - start;
32b55a907b 2019-05-02 200: } else {
32b55a907b 2019-05-02 201: resultLength = MIN(fileInfo->size - start, *length);
32b55a907b 2019-05-02 202: }
32b55a907b 2019-05-02 203: *length = resultLength;
48adf54b98 2019-09-13 204:
32b55a907b 2019-05-02 205: /*
32b55a907b 2019-05-02 206: * Return the data
32b55a907b 2019-05-02 207: */
32b55a907b 2019-05-02 208: return(fileInfo->data.fileContents + start);
32b55a907b 2019-05-02 209: }
32b55a907b 2019-05-02 210:
daf25f5222 2019-05-03 211: static int xvfs_<?= $::xvfs::fsName ?>_getStat(const char *path, Tcl_StatBuf *statBuf) {
d121970301 2019-05-02 212: struct xvfs_file_data *fileInfo;
d121970301 2019-05-02 213: long inode;
d121970301 2019-05-02 214:
d121970301 2019-05-02 215: /*
d121970301 2019-05-02 216: * Validate input parameters
d121970301 2019-05-02 217: */
d121970301 2019-05-02 218: if (!statBuf) {
149aa89b7d 2019-09-13 219: return(XVFS_RV_ERR_EINVAL);
d121970301 2019-05-02 220: }
d121970301 2019-05-02 221:
d121970301 2019-05-02 222: /*
d121970301 2019-05-02 223: * Get the inode from the lookup function
d121970301 2019-05-02 224: */
d121970301 2019-05-02 225: inode = xvfs_<?= $::xvfs::fsName ?>_nameToIndex(path);
d121970301 2019-05-02 226: if (inode == XVFS_NAME_LOOKUP_ERROR) {
149aa89b7d 2019-09-13 227: return(XVFS_RV_ERR_ENOENT);
d121970301 2019-05-02 228: }
d121970301 2019-05-02 229:
d121970301 2019-05-02 230: fileInfo = &xvfs_<?= $::xvfs::fsName ?>_data[inode];
d121970301 2019-05-02 231:
f7a81bb10b 2019-09-17 232: statBuf->st_dev = <?= [zlib adler32 $::xvfs::fsName] ?>;
f7a81bb10b 2019-09-17 233: statBuf->st_rdev = <?= [zlib adler32 $::xvfs::fsName] ?>;
d121970301 2019-05-02 234: statBuf->st_ino = inode;
f7a81bb10b 2019-09-17 235: statBuf->st_uid = 0;
f7a81bb10b 2019-09-17 236: statBuf->st_gid = 0;
d121970301 2019-05-02 237: statBuf->st_atime = 0;
d121970301 2019-05-02 238: statBuf->st_ctime = 0;
d121970301 2019-05-02 239: statBuf->st_mtime = 0;
3a68a54e44 2019-09-17 240: #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
fb9dd5d783 2019-05-03 241: statBuf->st_blksize = XVFS_FILE_BLOCKSIZE;
3a68a54e44 2019-09-17 242: #endif
d121970301 2019-05-02 243:
d121970301 2019-05-02 244: if (fileInfo->type == XVFS_FILE_TYPE_REG) {
6b8ea28911 2019-09-16 245: statBuf->st_mode = 0100444;
d121970301 2019-05-02 246: statBuf->st_nlink = 1;
d121970301 2019-05-02 247: statBuf->st_size = fileInfo->size;
3a68a54e44 2019-09-17 248: #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
d121970301 2019-05-02 249: statBuf->st_blocks = (fileInfo->size + statBuf->st_blksize - 1) / statBuf->st_blksize;
3a68a54e44 2019-09-17 250: #endif
d121970301 2019-05-02 251: } else if (fileInfo->type == XVFS_FILE_TYPE_DIR) {
6b8ea28911 2019-09-16 252: statBuf->st_mode = 040555;
d121970301 2019-05-02 253: statBuf->st_nlink = fileInfo->size;
d121970301 2019-05-02 254: statBuf->st_size = fileInfo->size;
3a68a54e44 2019-09-17 255: #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
d121970301 2019-05-02 256: statBuf->st_blocks = 1;
3a68a54e44 2019-09-17 257: #endif
d121970301 2019-05-02 258: }
d121970301 2019-05-02 259:
d121970301 2019-05-02 260: return(0);
d121970301 2019-05-02 261: }
d121970301 2019-05-02 262:
d121970301 2019-05-02 263: static struct Xvfs_FSInfo xvfs_<?= $::xvfs::fsName ?>_fsInfo = {
d121970301 2019-05-02 264: .protocolVersion = XVFS_PROTOCOL_VERSION,
d121970301 2019-05-02 265: .name = "<?= $::xvfs::fsName ?>",
d121970301 2019-05-02 266: .getChildrenProc = xvfs_<?= $::xvfs::fsName ?>_getChildren,
d121970301 2019-05-02 267: .getDataProc = xvfs_<?= $::xvfs::fsName ?>_getData,
daf25f5222 2019-05-03 268: .getStatProc = xvfs_<?= $::xvfs::fsName ?>_getStat
d121970301 2019-05-02 269: };
d121970301 2019-05-02 270:
69e476dcd5 2019-05-02 271: int Xvfs_<?= $::xvfs::fsName ?>_Init(Tcl_Interp *interp) {
69e476dcd5 2019-05-02 272: int register_ret;
e5b6962adf 2019-05-02 273:
e5b6962adf 2019-05-02 274: #ifdef USE_TCL_STUBS
e5b6962adf 2019-05-02 275: const char *tclInitStubs_ret;
e5b6962adf 2019-05-02 276: /* Initialize Stubs */
e5b6962adf 2019-05-02 277: tclInitStubs_ret = Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0);
e5b6962adf 2019-05-02 278: if (!tclInitStubs_ret) {
e5b6962adf 2019-05-02 279: return(TCL_ERROR);
e5b6962adf 2019-05-02 280: }
e5b6962adf 2019-05-02 281: #endif
69e476dcd5 2019-05-02 282:
d121970301 2019-05-02 283: register_ret = Xvfs_Register(interp, &xvfs_<?= $::xvfs::fsName ?>_fsInfo);
f74a2e47ab 2019-05-02 284: if (register_ret != TCL_OK) {
f74a2e47ab 2019-05-02 285: return(register_ret);
f74a2e47ab 2019-05-02 286: }
f74a2e47ab 2019-05-02 287:
f74a2e47ab 2019-05-02 288: return(TCL_OK);
f74a2e47ab 2019-05-02 289: }
5f2895faba 2019-09-17 290: #undef XVFS_NAME_LOOKUP_ERROR
5f2895faba 2019-09-17 291: #undef XVFS_FILE_BLOCKSIZE