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