1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
+
+
+
+
+
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include <xvfs-core.h>
#include <unistd.h>
#include <string.h>
#include <tcl.h>
#define XVFS_NAME_LOOKUP_ERROR (-1)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
typedef enum {
XVFS_FILE_TYPE_REG,
XVFS_FILE_TYPE_DIR
} xvfs_file_type_t;
typedef Tcl_WideInt xvfs_size_t;
struct xvfs_file_data {
const char *name;
xvfs_file_type_t type;
xvfs_size_t size;
union {
const unsigned char *data;
const unsigned char *fileContents;
const char **dirChildren;
} data;
};
<?
package require xvfs
xvfs::main $argv
?>
static long xvfs_<?= $::xvfs::fsName ?>_nameToIndex(const char *path) {
if (path == NULL) {
return(XVFS_NAME_LOOKUP_ERROR);
static const char **xvfs_<?= $::xvfs::fsName ?>_getChildren(const char *path, Tcl_WideInt limit) {
return(NULL);
}
static const unsigned char *xvfs_<?= $::xvfs::fsName ?>_getData(const char *path, Tcl_WideInt start, Tcl_WideInt length) {
return(NULL);
}
}
<? for {set index 0} {$index < [llength $::xvfs::outputFiles]} {incr index} {
set outputFile [lindex $::xvfs::outputFiles $index]
?>
if (strcmp(path, "<?= [::xvfs::sanitizeCString $outputFile] ?>") == 0) {
return(<?= $index ?>);
}
<? } ?>
return(XVFS_NAME_LOOKUP_ERROR);
}
static const char **xvfs_<?= $::xvfs::fsName ?>_getChildren(const char *path, Tcl_WideInt *count) {
struct xvfs_file_data *fileInfo;
long inode;
/*
* Validate input parameters
*/
if (count == NULL) {
return(NULL);
}
/*
* Get the inode from the lookup function
*/
inode = xvfs_<?= $::xvfs::fsName ?>_nameToIndex(path);
if (inode == XVFS_NAME_LOOKUP_ERROR) {
return(NULL);
}
fileInfo = &xvfs_<?= $::xvfs::fsName ?>_data[inode];
/*
* Ensure this is a directory
*/
if (fileInfo->type != XVFS_FILE_TYPE_DIR) {
return(NULL);
}
*count = fileInfo->size;
return(fileInfo->data.dirChildren);
}
static const unsigned char *xvfs_<?= $::xvfs::fsName ?>_getData(const char *path, Tcl_WideInt start, Tcl_WideInt *length) {
struct xvfs_file_data *fileInfo;
Tcl_WideInt resultLength;
long inode;
/*
* Validate input parameters
*/
if (start < 0) {
return(NULL);
}
if (length == NULL) {
return(NULL);
}
if (*length < 0) {
return(NULL);
}
/*
* Get the inode from the lookup function
*/
inode = xvfs_<?= $::xvfs::fsName ?>_nameToIndex(path);
if (inode == XVFS_NAME_LOOKUP_ERROR) {
return(NULL);
}
fileInfo = &xvfs_<?= $::xvfs::fsName ?>_data[inode];
/*
* Ensure this is a file that can be read
*/
if (fileInfo->type != XVFS_FILE_TYPE_REG) {
return(NULL);
}
/*
* Validate the length
*/
if (start > fileInfo->size) {
*length = -1;
return(NULL);
}
if (*length == 0) {
resultLength = fileInfo->size - start;
} else {
resultLength = MIN(fileInfo->size - start, *length);
}
*length = resultLength;
/*
* Return the data
*/
return(fileInfo->data.fileContents + start);
}
int Xvfs_<?= $::xvfs::fsName ?>_Init(Tcl_Interp *interp) {
int register_ret;
/* XXX:TODO: Stubs */
register_ret = Xvfs_Register(interp, "<?= $::xvfs::fsName ?>", XVFS_PROTOCOL_VERSION, xvfs_<?= $::xvfs::fsName ?>_getChildren, xvfs_<?= $::xvfs::fsName ?>_getData);
if (register_ret != TCL_OK) {
return(register_ret);
}
return(TCL_OK);
|