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