Merge pull request #368 from grissiom/romfs-next

Romfs next
This commit is contained in:
Bernard Xiong 2014-11-03 12:38:20 +08:00
commit 7cb6463253
2 changed files with 263 additions and 113 deletions

View File

@ -49,6 +49,14 @@ int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args)
return -DFS_STATUS_EIO;
}
rt_inline int check_dirent(struct romfs_dirent *dirent)
{
if (!(dirent->type == ROMFS_DIRENT_FILE || dirent->type == ROMFS_DIRENT_DIR) ||
(dirent->size == 0 || dirent->size == ~0))
return -1;
return 0;
}
struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size)
{
rt_size_t index, found;
@ -56,6 +64,10 @@ struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const ch
struct romfs_dirent *dirent;
rt_size_t dirent_size;
/* Check the root_dirent. */
if (check_dirent(root_dirent) != 0)
return RT_NULL;
if (path[0] == '/' && path[1] == '\0')
{
*size = root_dirent->size;
@ -82,6 +94,8 @@ struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const ch
/* search in folder */
for (index = 0; index < dirent_size; index ++)
{
if (check_dirent(&dirent[index]) != 0)
return RT_NULL;
if (rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0)
{
dirent_size = dirent[index].size;
@ -133,6 +147,11 @@ int dfs_romfs_read(struct dfs_fd *file, void *buf, rt_size_t count)
dirent = (struct romfs_dirent *)file->data;
RT_ASSERT(dirent != RT_NULL);
if (check_dirent(dirent) != 0)
{
return -DFS_STATUS_EIO;
}
if (count < file->size - file->pos)
length = count;
else
@ -172,6 +191,9 @@ int dfs_romfs_open(struct dfs_fd *file)
root_dirent = (struct romfs_dirent *)file->fs->data;
if (check_dirent(dirent) != 0)
return -DFS_STATUS_EIO;
if (file->flags & (DFS_O_CREAT | DFS_O_WRONLY | DFS_O_APPEND | DFS_O_TRUNC | DFS_O_RDWR))
return -DFS_STATUS_EINVAL;
@ -236,6 +258,8 @@ int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, rt_uint32_t cou
struct romfs_dirent *dirent, *sub_dirent;
dirent = (struct romfs_dirent *)file->data;
if (check_dirent(dirent) != 0)
return -DFS_STATUS_EIO;
RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
/* enter directory */

View File

@ -1,126 +1,252 @@
#!/usr/bin/env python
import sys
import os
import string
basename = ''
output = ''
sep = os.sep
import struct
from collections import namedtuple
import StringIO
def mkromfs_output(out):
# print '%s' % out,
output.write(out)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('rootdir', type=str, help='the path to rootfs')
parser.add_argument('output', type=argparse.FileType('wb'), nargs='?', help='output file name')
parser.add_argument('--dump', action='store_true', help='dump the fs hierarchy')
parser.add_argument('--binary', action='store_true', help='output binary file')
parser.add_argument('--addr', default='0', help='set the base address of the binary file, default to 0.')
def mkromfs_file(filename, arrayname):
f = file(filename, "rb")
arrayname = arrayname.replace('.', '_')
arrayname = arrayname.replace('-', '_')
mkromfs_output('const static unsigned char %s[] = {\n' % arrayname)
class File(object):
def __init__(self, name):
self._name = name
self._data = open(name, 'rb').read()
count = 0
while True:
byte = f.read(1)
@property
def name(self):
return self._name
if len(byte) != 1:
break
@property
def c_name(self):
return '_' + self._name.replace('.', '_')
mkromfs_output('0x%02x,' % ord(byte))
@property
def bin_name(self):
# Pad to 4 bytes boundary with \0
pad_len = 4
bn = self._name + '\0' * (pad_len - len(self._name) % pad_len)
return bn
count = count + 1
if count == 16:
count = 0
mkromfs_output('\n')
def c_data(self, prefix=''):
'''Get the C code represent of the file content.'''
head = 'static const rt_uint8_t %s[] = {\n' % \
(prefix + self.c_name)
tail = '\n};'
return head + ','.join(('0x%02x' % ord(i) for i in self._data)) + tail
if count == 0:
mkromfs_output('};\n\n')
else:
mkromfs_output('\n};\n\n')
@property
def entry_size(self):
return len(self._data)
f.close()
def bin_data(self, base_addr=0x0):
return bytes(self._data)
def mkromfs_dir(dirname, is_root = False):
list = os.listdir(dirname)
path = os.path.abspath(dirname)
def dump(self, indent=0):
print '%s%s' % (' ' * indent, self._name)
# make for directory
for item in list:
fullpath = os.path.join(path, item)
if os.path.isdir(fullpath):
# if it is an empty directory, ignore it
l = os.listdir(fullpath)
if len(l):
mkromfs_dir(fullpath)
class Folder(object):
bin_fmt = struct.Struct('IIII')
bin_item = namedtuple('dirent', 'type, name, data, size')
# make for files
for item in list:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
subpath = fullpath[len(basename):]
array = subpath.split(sep)
arrayname = string.join(array, '_')
mkromfs_file(fullpath, arrayname)
def __init__(self, name):
self._name = name
self._children = []
subpath = path[len(basename):]
dir = subpath.split(sep)
direntname = string.join(dir, '_')
if is_root:
mkromfs_output('const struct romfs_dirent _root_dirent[] = {\n')
else:
mkromfs_output(('const static struct romfs_dirent %s[] = {\n' % direntname))
@property
def name(self):
return self._name
for item in list:
fullpath = os.path.join(path, item)
fn = fullpath[len(dirname):]
if fn[0] == sep:
fn = fn[1:]
fn = fn.replace('\\', '/')
@property
def c_name(self):
# add _ to avoid conflict with C key words.
return '_' + self._name
subpath = fullpath[len(basename):]
items = subpath.split(sep)
item_name = string.join(items, '_')
item_name = item_name.replace('.', '_')
item_name = item_name.replace('-', '_')
subpath = subpath.replace('\\', '/')
if subpath[0] == '/':
subpath = subpath[1:]
@property
def bin_name(self):
# Pad to 4 bytes boundary with \0
pad_len = 4
bn = self._name + '\0' * (pad_len - len(self._name) % pad_len)
return bn
if not os.path.isfile(fullpath):
l = os.listdir(fullpath)
if len(l):
mkromfs_output(('\t{ROMFS_DIRENT_DIR, "%s", (rt_uint8_t*) %s, sizeof(%s)/sizeof(%s[0])},\n' % (fn, item_name, item_name, item_name)))
def walk(self):
# os.listdir will return unicode list if the argument is unicode.
# TODO: take care of the unicode names
for ent in os.listdir(u'.'):
if os.path.isdir(ent):
cwd = os.getcwdu()
d = Folder(ent)
# depth-first
os.chdir(os.path.join(cwd, ent))
d.walk()
# restore the cwd
os.chdir(cwd)
self._children.append(d)
else:
mkromfs_output(('\t{ROMFS_DIRENT_DIR, "%s", RT_NULL, 0},\n' % fn))
self._children.append(File(ent))
for item in list:
fullpath = os.path.join(path, item)
fn = fullpath[len(dirname):]
if fn[0] == sep:
fn = fn[1:]
fn = fn.replace('\\', '/')
def sort(self):
def _sort(x, y):
if x.name == y.name:
return 0
elif x.name > y.name:
return 1
else:
return -1
self._children.sort(cmp=_sort)
subpath = fullpath[len(basename):]
items = subpath.split(sep)
item_name = string.join(items, '_')
item_name = item_name.replace('.', '_')
item_name = item_name.replace('-', '_')
subpath = subpath.replace('\\', '/')
if subpath[0] == '/':
subpath = subpath[1:]
# sort recursively
for c in self._children:
if isinstance(c, Folder):
c.sort()
if os.path.isfile(fullpath):
mkromfs_output(('\t{ROMFS_DIRENT_FILE, "%s", %s, sizeof(%s)},\n' % (fn, item_name, item_name)))
def dump(self, indent=0):
print '%s%s' % (' ' * indent, self._name)
for c in self._children:
c.dump(indent + 1)
mkromfs_output('};\n\n')
def c_data(self, prefix=''):
'''get the C code represent of the folder.
if __name__ == "__main__":
try:
basename = os.path.abspath(sys.argv[1])
filename = os.path.abspath(sys.argv[2])
except IndexError:
print "Usage: %s <dirname> <filename>" % sys.argv[0]
raise SystemExit
It is recursive.'''
# make the current dirent
# static is good. Only root dirent is global visible.
dhead = 'static const struct romfs_dirent %s[] = {\n' % (prefix + self.c_name)
dtail = '\n};'
body_fmt = ' {{{type}, "{name}", (rt_uint8_t *){data}, sizeof({data})/sizeof({data}[0])}}'
# prefix of children
cpf = prefix+self.c_name
body_li = []
payload_li = []
for c in self._children:
if isinstance(c, File):
tp = 'ROMFS_DIRENT_FILE'
elif isinstance(c, Folder):
tp = 'ROMFS_DIRENT_DIR'
else:
assert False, 'Unkown instance:%s' % str(c)
body_li.append(body_fmt.format(type=tp,
name=c.name,
data=cpf+c.c_name))
payload_li.append(c.c_data(prefix=cpf))
output = file(filename, 'wt')
mkromfs_output("#include <dfs_romfs.h>\n\n")
mkromfs_dir(basename, is_root = True)
# All the data we need is defined in payload so we should append the
# dirent to it. It also meet the depth-first policy in this code.
payload_li.append(dhead + ',\n'.join(body_li) + dtail)
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")
return '\n\n'.join(payload_li)
@property
def entry_size(self):
return len(self._children)
def bin_data(self, base_addr=0x0):
'''Return StringIO object'''
# The binary layout is different from the C code layout. We put the
# dirent before the payload in this mode. But the idea is still simple:
# Depth-First.
#{
# rt_uint32_t type;
# const char *name;
# const rt_uint8_t *data;
# rt_size_t size;
#}
d_li = []
# payload base
p_base = base_addr + self.bin_fmt.size * self.entry_size
# the length to record how many data is in
v_len = p_base
# payload
p_li = []
for c in self._children:
if isinstance(c, File):
# ROMFS_DIRENT_FILE
tp = 0
elif isinstance(c, Folder):
# ROMFS_DIRENT_DIR
tp = 1
else:
assert False, 'Unkown instance:%s' % str(c)
name = bytes(c.bin_name)
name_addr = v_len
v_len += len(name)
data = c.bin_data(base_addr=v_len)
data_addr = v_len
# pad the data to 4 bytes boundary
pad_len = 4
if len(data) % pad_len != 0:
data += '\0' * (pad_len - len(data) % pad_len)
v_len += len(data)
d_li.append(self.bin_fmt.pack(*self.bin_item(
type=tp,
name=name_addr,
data=data_addr,
size=c.entry_size)))
p_li.extend((name, data))
return bytes().join(d_li) + bytes().join(p_li)
def get_c_data(tree):
# Handle the root dirent specially.
root_dirent_fmt = '''/* Generated by mkromfs. Edit with caution. */
#include <rtthread.h>
#include <dfs_romfs.h>
{data}
const struct romfs_dirent {name} = {{
ROMFS_DIRENT_DIR, "/", (rt_uint8_t *){rootdirent}, sizeof({rootdirent})/sizeof({rootdirent}[0])
}};
'''
return root_dirent_fmt.format(name='romfs_root',
rootdirent=tree.c_name,
data=tree.c_data())
def get_bin_data(tree, base_addr):
v_len = base_addr + Folder.bin_fmt.size
name = bytes('/\0\0\0')
name_addr = v_len
v_len += len(name)
data_addr = v_len
# root entry
data = Folder.bin_fmt.pack(*Folder.bin_item(type=1,
name=name_addr,
data=data_addr,
size=tree.entry_size))
return data + name + tree.bin_data(v_len)
if __name__ == '__main__':
args = parser.parse_args()
os.chdir(args.rootdir)
tree = Folder('romfs_root')
tree.walk()
tree.sort()
if args.dump:
tree.dump()
if args.binary:
data = get_bin_data(tree, int(args.addr, 16))
else:
data = get_c_data(tree)
output = args.output
if not output:
output = sys.stdout
output.write(data)