|
| 1 | +#!/usr/bin/env python |
| 2 | + |
1 | 3 | import sys
|
2 | 4 | import os
|
3 |
| -import string |
4 |
| - |
5 |
| -basename = '' |
6 |
| -output = '' |
7 |
| -sep = os.sep |
8 |
| - |
9 |
| -def mkromfs_output(out): |
10 |
| - # print '%s' % out, |
11 |
| - output.write(out) |
12 |
| - |
13 |
| -def mkromfs_file(filename, arrayname): |
14 |
| - f = file(filename, "rb") |
15 |
| - arrayname = arrayname.replace('.', '_') |
16 |
| - arrayname = arrayname.replace('-', '_') |
17 |
| - mkromfs_output('const static unsigned char %s[] = {\n' % arrayname) |
18 |
| - |
19 |
| - count = 0 |
20 |
| - while True: |
21 |
| - byte = f.read(1) |
22 |
| - |
23 |
| - if len(byte) != 1: |
24 |
| - break |
25 |
| - |
26 |
| - mkromfs_output('0x%02x,' % ord(byte)) |
27 |
| - |
28 |
| - count = count + 1 |
29 |
| - if count == 16: |
30 |
| - count = 0 |
31 |
| - mkromfs_output('\n') |
32 |
| - |
33 |
| - if count == 0: |
34 |
| - mkromfs_output('};\n\n') |
35 |
| - else: |
36 |
| - mkromfs_output('\n};\n\n') |
37 |
| - |
38 |
| - f.close() |
39 |
| - |
40 |
| -def mkromfs_dir(dirname, is_root = False): |
41 |
| - list = os.listdir(dirname) |
42 |
| - path = os.path.abspath(dirname) |
43 |
| - |
44 |
| - # make for directory |
45 |
| - for item in list: |
46 |
| - fullpath = os.path.join(path, item) |
47 |
| - if os.path.isdir(fullpath): |
48 |
| - # if it is an empty directory, ignore it |
49 |
| - l = os.listdir(fullpath) |
50 |
| - if len(l): |
51 |
| - mkromfs_dir(fullpath) |
52 |
| - |
53 |
| - # make for files |
54 |
| - for item in list: |
55 |
| - fullpath = os.path.join(path, item) |
56 |
| - if os.path.isfile(fullpath): |
57 |
| - subpath = fullpath[len(basename):] |
58 |
| - array = subpath.split(sep) |
59 |
| - arrayname = string.join(array, '_') |
60 |
| - mkromfs_file(fullpath, arrayname) |
61 |
| - |
62 |
| - subpath = path[len(basename):] |
63 |
| - dir = subpath.split(sep) |
64 |
| - direntname = string.join(dir, '_') |
65 |
| - if is_root: |
66 |
| - mkromfs_output('const struct romfs_dirent _root_dirent[] = {\n') |
67 |
| - else: |
68 |
| - mkromfs_output(('const static struct romfs_dirent %s[] = {\n' % direntname)) |
69 |
| - |
70 |
| - for item in list: |
71 |
| - fullpath = os.path.join(path, item) |
72 |
| - fn = fullpath[len(dirname):] |
73 |
| - if fn[0] == sep: |
74 |
| - fn = fn[1:] |
75 |
| - fn = fn.replace('\\', '/') |
76 |
| - |
77 |
| - subpath = fullpath[len(basename):] |
78 |
| - items = subpath.split(sep) |
79 |
| - item_name = string.join(items, '_') |
80 |
| - item_name = item_name.replace('.', '_') |
81 |
| - item_name = item_name.replace('-', '_') |
82 |
| - subpath = subpath.replace('\\', '/') |
83 |
| - if subpath[0] == '/': |
84 |
| - subpath = subpath[1:] |
85 |
| - |
86 |
| - if not os.path.isfile(fullpath): |
87 |
| - l = os.listdir(fullpath) |
88 |
| - if len(l): |
89 |
| - mkromfs_output(('\t{ROMFS_DIRENT_DIR, "%s", (rt_uint8_t*) %s, sizeof(%s)/sizeof(%s[0])},\n' % (fn, item_name, item_name, item_name))) |
| 5 | + |
| 6 | +import struct |
| 7 | +from collections import namedtuple |
| 8 | +import StringIO |
| 9 | + |
| 10 | +import argparse |
| 11 | +parser = argparse.ArgumentParser() |
| 12 | +parser.add_argument('rootdir', type=str, help='the path to rootfs') |
| 13 | +parser.add_argument('output', type=argparse.FileType('wb'), nargs='?', help='output file name') |
| 14 | +parser.add_argument('--dump', action='store_true', help='dump the fs hierarchy') |
| 15 | +parser.add_argument('--binary', action='store_true', help='output binary file') |
| 16 | +parser.add_argument('--addr', default='0', help='set the base address of the binary file, default to 0.') |
| 17 | + |
| 18 | +class File(object): |
| 19 | + def __init__(self, name): |
| 20 | + self._name = name |
| 21 | + self._data = open(name, 'rb').read() |
| 22 | + |
| 23 | + @property |
| 24 | + def name(self): |
| 25 | + return self._name |
| 26 | + |
| 27 | + @property |
| 28 | + def c_name(self): |
| 29 | + return '_' + self._name.replace('.', '_') |
| 30 | + |
| 31 | + @property |
| 32 | + def bin_name(self): |
| 33 | + # Pad to 4 bytes boundary with \0 |
| 34 | + pad_len = 4 |
| 35 | + bn = self._name + '\0' * (pad_len - len(self._name) % pad_len) |
| 36 | + return bn |
| 37 | + |
| 38 | + def c_data(self, prefix=''): |
| 39 | + '''Get the C code represent of the file content.''' |
| 40 | + head = 'static const rt_uint8_t %s[] = {\n' % \ |
| 41 | + (prefix + self.c_name) |
| 42 | + tail = '\n};' |
| 43 | + return head + ','.join(('0x%02x' % ord(i) for i in self._data)) + tail |
| 44 | + |
| 45 | + @property |
| 46 | + def entry_size(self): |
| 47 | + return len(self._data) |
| 48 | + |
| 49 | + def bin_data(self, base_addr=0x0): |
| 50 | + return bytes(self._data) |
| 51 | + |
| 52 | + def dump(self, indent=0): |
| 53 | + print '%s%s' % (' ' * indent, self._name) |
| 54 | + |
| 55 | +class Folder(object): |
| 56 | + bin_fmt = struct.Struct('IIII') |
| 57 | + bin_item = namedtuple('dirent', 'type, name, data, size') |
| 58 | + |
| 59 | + def __init__(self, name): |
| 60 | + self._name = name |
| 61 | + self._children = [] |
| 62 | + |
| 63 | + @property |
| 64 | + def name(self): |
| 65 | + return self._name |
| 66 | + |
| 67 | + @property |
| 68 | + def c_name(self): |
| 69 | + # add _ to avoid conflict with C key words. |
| 70 | + return '_' + self._name |
| 71 | + |
| 72 | + @property |
| 73 | + def bin_name(self): |
| 74 | + # Pad to 4 bytes boundary with \0 |
| 75 | + pad_len = 4 |
| 76 | + bn = self._name + '\0' * (pad_len - len(self._name) % pad_len) |
| 77 | + return bn |
| 78 | + |
| 79 | + def walk(self): |
| 80 | + # os.listdir will return unicode list if the argument is unicode. |
| 81 | + # TODO: take care of the unicode names |
| 82 | + for ent in os.listdir(u'.'): |
| 83 | + if os.path.isdir(ent): |
| 84 | + cwd = os.getcwdu() |
| 85 | + d = Folder(ent) |
| 86 | + # depth-first |
| 87 | + os.chdir(os.path.join(cwd, ent)) |
| 88 | + d.walk() |
| 89 | + # restore the cwd |
| 90 | + os.chdir(cwd) |
| 91 | + self._children.append(d) |
| 92 | + else: |
| 93 | + self._children.append(File(ent)) |
| 94 | + |
| 95 | + def sort(self): |
| 96 | + def _sort(x, y): |
| 97 | + if x.name == y.name: |
| 98 | + return 0 |
| 99 | + elif x.name > y.name: |
| 100 | + return 1 |
| 101 | + else: |
| 102 | + return -1 |
| 103 | + self._children.sort(cmp=_sort) |
| 104 | + |
| 105 | + # sort recursively |
| 106 | + for c in self._children: |
| 107 | + if isinstance(c, Folder): |
| 108 | + c.sort() |
| 109 | + |
| 110 | + def dump(self, indent=0): |
| 111 | + print '%s%s' % (' ' * indent, self._name) |
| 112 | + for c in self._children: |
| 113 | + c.dump(indent + 1) |
| 114 | + |
| 115 | + def c_data(self, prefix=''): |
| 116 | + '''get the C code represent of the folder. |
| 117 | +
|
| 118 | + It is recursive.''' |
| 119 | + # make the current dirent |
| 120 | + # static is good. Only root dirent is global visible. |
| 121 | + dhead = 'static const struct romfs_dirent %s[] = {\n' % (prefix + self.c_name) |
| 122 | + dtail = '\n};' |
| 123 | + body_fmt = ' {{{type}, "{name}", (rt_uint8_t *){data}, sizeof({data})/sizeof({data}[0])}}' |
| 124 | + # prefix of children |
| 125 | + cpf = prefix+self.c_name |
| 126 | + body_li = [] |
| 127 | + payload_li = [] |
| 128 | + for c in self._children: |
| 129 | + if isinstance(c, File): |
| 130 | + tp = 'ROMFS_DIRENT_FILE' |
| 131 | + elif isinstance(c, Folder): |
| 132 | + tp = 'ROMFS_DIRENT_DIR' |
| 133 | + else: |
| 134 | + assert False, 'Unkown instance:%s' % str(c) |
| 135 | + body_li.append(body_fmt.format(type=tp, |
| 136 | + name=c.name, |
| 137 | + data=cpf+c.c_name)) |
| 138 | + payload_li.append(c.c_data(prefix=cpf)) |
| 139 | + |
| 140 | + # All the data we need is defined in payload so we should append the |
| 141 | + # dirent to it. It also meet the depth-first policy in this code. |
| 142 | + payload_li.append(dhead + ',\n'.join(body_li) + dtail) |
| 143 | + |
| 144 | + return '\n\n'.join(payload_li) |
| 145 | + |
| 146 | + @property |
| 147 | + def entry_size(self): |
| 148 | + return len(self._children) |
| 149 | + |
| 150 | + def bin_data(self, base_addr=0x0): |
| 151 | + '''Return StringIO object''' |
| 152 | + # The binary layout is different from the C code layout. We put the |
| 153 | + # dirent before the payload in this mode. But the idea is still simple: |
| 154 | + # Depth-First. |
| 155 | + |
| 156 | + #{ |
| 157 | + # rt_uint32_t type; |
| 158 | + # const char *name; |
| 159 | + # const rt_uint8_t *data; |
| 160 | + # rt_size_t size; |
| 161 | + #} |
| 162 | + d_li = [] |
| 163 | + # payload base |
| 164 | + p_base = base_addr + self.bin_fmt.size * self.entry_size |
| 165 | + # the length to record how many data is in |
| 166 | + v_len = p_base |
| 167 | + # payload |
| 168 | + p_li = [] |
| 169 | + for c in self._children: |
| 170 | + if isinstance(c, File): |
| 171 | + # ROMFS_DIRENT_FILE |
| 172 | + tp = 0 |
| 173 | + elif isinstance(c, Folder): |
| 174 | + # ROMFS_DIRENT_DIR |
| 175 | + tp = 1 |
90 | 176 | else:
|
91 |
| - mkromfs_output(('\t{ROMFS_DIRENT_DIR, "%s", RT_NULL, 0},\n' % fn)) |
92 |
| - |
93 |
| - for item in list: |
94 |
| - fullpath = os.path.join(path, item) |
95 |
| - fn = fullpath[len(dirname):] |
96 |
| - if fn[0] == sep: |
97 |
| - fn = fn[1:] |
98 |
| - fn = fn.replace('\\', '/') |
99 |
| - |
100 |
| - subpath = fullpath[len(basename):] |
101 |
| - items = subpath.split(sep) |
102 |
| - item_name = string.join(items, '_') |
103 |
| - item_name = item_name.replace('.', '_') |
104 |
| - item_name = item_name.replace('-', '_') |
105 |
| - subpath = subpath.replace('\\', '/') |
106 |
| - if subpath[0] == '/': |
107 |
| - subpath = subpath[1:] |
108 |
| - |
109 |
| - if os.path.isfile(fullpath): |
110 |
| - mkromfs_output(('\t{ROMFS_DIRENT_FILE, "%s", %s, sizeof(%s)},\n' % (fn, item_name, item_name))) |
111 |
| - |
112 |
| - mkromfs_output('};\n\n') |
113 |
| - |
114 |
| -if __name__ == "__main__": |
115 |
| - try: |
116 |
| - basename = os.path.abspath(sys.argv[1]) |
117 |
| - filename = os.path.abspath(sys.argv[2]) |
118 |
| - except IndexError: |
119 |
| - print "Usage: %s <dirname> <filename>" % sys.argv[0] |
120 |
| - raise SystemExit |
121 |
| - |
122 |
| - output = file(filename, 'wt') |
123 |
| - mkromfs_output("#include <dfs_romfs.h>\n\n") |
124 |
| - mkromfs_dir(basename, is_root = True) |
125 |
| - |
126 |
| - mkromfs_output("const struct romfs_dirent romfs_root = {ROMFS_DIRENT_DIR, \"/\", (rt_uint8_t*) _root_dirent, sizeof(_root_dirent)/sizeof(_root_dirent[0])};\n\n") |
| 177 | + assert False, 'Unkown instance:%s' % str(c) |
| 178 | + |
| 179 | + name = bytes(c.bin_name) |
| 180 | + name_addr = v_len |
| 181 | + v_len += len(name) |
| 182 | + |
| 183 | + data = c.bin_data(base_addr=v_len) |
| 184 | + data_addr = v_len |
| 185 | + # pad the data to 4 bytes boundary |
| 186 | + pad_len = 4 |
| 187 | + if len(data) % pad_len != 0: |
| 188 | + data += '\0' * (pad_len - len(data) % pad_len) |
| 189 | + v_len += len(data) |
| 190 | + |
| 191 | + d_li.append(self.bin_fmt.pack(*self.bin_item( |
| 192 | + type=tp, |
| 193 | + name=name_addr, |
| 194 | + data=data_addr, |
| 195 | + size=c.entry_size))) |
| 196 | + |
| 197 | + p_li.extend((name, data)) |
| 198 | + |
| 199 | + return bytes().join(d_li) + bytes().join(p_li) |
| 200 | + |
| 201 | +def get_c_data(tree): |
| 202 | + # Handle the root dirent specially. |
| 203 | + root_dirent_fmt = '''/* Generated by mkromfs. Edit with caution. */ |
| 204 | +#include <rtthread.h> |
| 205 | +#include <dfs_romfs.h> |
| 206 | +
|
| 207 | +{data} |
| 208 | +
|
| 209 | +const struct romfs_dirent {name} = {{ |
| 210 | + ROMFS_DIRENT_DIR, "/", (rt_uint8_t *){rootdirent}, sizeof({rootdirent})/sizeof({rootdirent}[0]) |
| 211 | +}}; |
| 212 | +''' |
| 213 | + |
| 214 | + return root_dirent_fmt.format(name='romfs_root', |
| 215 | + rootdirent=tree.c_name, |
| 216 | + data=tree.c_data()) |
| 217 | + |
| 218 | +def get_bin_data(tree, base_addr): |
| 219 | + v_len = base_addr + Folder.bin_fmt.size |
| 220 | + name = bytes('/\0\0\0') |
| 221 | + name_addr = v_len |
| 222 | + v_len += len(name) |
| 223 | + data_addr = v_len |
| 224 | + # root entry |
| 225 | + data = Folder.bin_fmt.pack(*Folder.bin_item(type=1, |
| 226 | + name=name_addr, |
| 227 | + data=data_addr, |
| 228 | + size=tree.entry_size)) |
| 229 | + return data + name + tree.bin_data(v_len) |
| 230 | + |
| 231 | +if __name__ == '__main__': |
| 232 | + args = parser.parse_args() |
| 233 | + |
| 234 | + os.chdir(args.rootdir) |
| 235 | + |
| 236 | + tree = Folder('romfs_root') |
| 237 | + tree.walk() |
| 238 | + tree.sort() |
| 239 | + |
| 240 | + if args.dump: |
| 241 | + tree.dump() |
| 242 | + |
| 243 | + if args.binary: |
| 244 | + data = get_bin_data(tree, int(args.addr, 16)) |
| 245 | + else: |
| 246 | + data = get_c_data(tree) |
| 247 | + |
| 248 | + output = args.output |
| 249 | + if not output: |
| 250 | + output = sys.stdout |
| 251 | + |
| 252 | + output.write(data) |
0 commit comments