-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathj4fs_extract.py
executable file
·98 lines (67 loc) · 2.59 KB
/
j4fs_extract.py
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
#!/usr/bin/python2
import argparse, struct, sys, os
S_INODE = '8I128s'
J4FS_MAGIC = 0x87654321
J4FS_FILE_MAGIC = 0x12345678
def write_file(filename, length, fp):
""" Write file data to file """
if not os.path.isdir(args.dir):
os.mkdir(args.dir)
path = os.path.join(args.dir, filename)
print path
ofp = open(path, 'w')
while length > 0:
nbyte = min(8192, length)
ofp.write(fp.read(nbyte))
length -= nbyte
ofp.close()
def j4fs_inode_is_valid(inode):
""" Determine whether specified inode is valid (ie. not deleted) """
flags = inode[4]
return (flags & 0x01) == ((flags & 0x02) >> 1)
def j4fs_inode_is_last(inode):
""" Determine whether specified inode is the last one """
link = inode[0]
flags = inode[4]
return (link == 0xffffffff and (flags & 0x01) == 0x01) or \
(link == 0x00000000 and (flags & 0x01) == 0x00)
def j4fs_extract(fp):
# first ro entry is past mst
link = args.block_size
inode = None
while not inode or not j4fs_inode_is_last(inode):
inode_pos = link
fp.seek(link)
inode_data = fp.read(struct.calcsize(S_INODE))
inode = list(struct.unpack(S_INODE, inode_data))
# inode (link, size, type, offset, flags, stroff, id, length, filename)
link, _, type, _, flags, _, _, length, filename = inode
assert type == J4FS_FILE_MAGIC, 'Unknown inode type'
filename = filename.split('\x00')[0]
# data is at inode_pos + page_size
fp.seek(inode_pos + args.page_size)
write_file(filename, length, fp)
def j4fs_image_valid(fp):
""" Check whether fp is a valid j4fs image """
fp.seek(0)
magic, = struct.unpack('I', fp.read(4))
return (magic == J4FS_MAGIC)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Extract j4fs/lfs images')
parser.add_argument('file', help='input image')
parser.add_argument('-o', dest='dir', help='output directory', default='out')
parser.add_argument('-p', dest='page_size', type=int, help='page size (default 4096)', default=4096)
parser.add_argument('-b', dest='block_size', type=int, help='block size (default 262144)', default=262144)
args = parser.parse_args()
fp = None
try:
fp = open(args.file)
if not j4fs_image_valid(fp):
print >> sys.stderr, 'Error: input file does not appear to contain a valid j4fs filesystem'
sys.exit(1)
except IOError, e:
print >> sys.stderr, e
sys.exit(1)
print 'Writing files to %r\n' % args.dir
j4fs_extract(fp)
fp.close()