Skip to content

Commit b435738

Browse files
committed
romfs: rewrite mkromfs.py
1 parent e882597 commit b435738

File tree

1 file changed

+249
-123
lines changed

1 file changed

+249
-123
lines changed
Lines changed: 249 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,252 @@
1+
#!/usr/bin/env python
2+
13
import sys
24
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
90176
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

Comments
 (0)