Implement support for block and char dev nodes, fifos and sockets.
[project/make_ext4fs.git] / libsparse / simg_dump.py
1 #! /usr/bin/env python
2
3 # Copyright (C) 2012 The Android Open Source Project
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 from __future__ import print_function
18 import getopt, posixpath, signal, struct, sys
19
20 def usage(argv0):
21   print("""
22 Usage: %s [-v] sparse_image_file ...
23  -v             verbose output
24 """ % ( argv0 ))
25   sys.exit(2)
26
27 def main():
28
29   signal.signal(signal.SIGPIPE, signal.SIG_DFL)
30
31   me = posixpath.basename(sys.argv[0])
32
33   # Parse the command line
34   verbose = 0                   # -v
35   try:
36     opts, args = getopt.getopt(sys.argv[1:],
37                                "v",
38                                ["verbose"])
39   except getopt.GetoptError, e:
40     print(e)
41     usage(me)
42   for o, a in opts:
43     if o in ("-v", "--verbose"):
44       verbose += 1
45     else:
46       print("Unrecognized option \"%s\"" % (o))
47       usage(me)
48
49   if len(args) == 0:
50     print("No sparse_image_file specified")
51     usage(me)
52
53   for path in args:
54     FH = open(path, 'rb')
55     header_bin = FH.read(28)
56     header = struct.unpack("<I4H4I", header_bin)
57
58     magic = header[0]
59     major_version = header[1]
60     minor_version = header[2]
61     file_hdr_sz = header[3]
62     chunk_hdr_sz = header[4]
63     blk_sz = header[5]
64     total_blks = header[6]
65     total_chunks = header[7]
66     image_checksum = header[8]
67
68     if magic != 0xED26FF3A:
69       print("%s: %s: Magic should be 0xED26FF3A but is 0x%08X"
70             % (me, path, magic))
71       continue
72     if major_version != 1 or minor_version != 0:
73       print("%s: %s: I only know about version 1.0, but this is version %u.%u"
74             % (me, path, major_version, minor_version))
75       continue
76     if file_hdr_sz != 28:
77       print("%s: %s: The file header size was expected to be 28, but is %u."
78             % (me, path, file_hdr_sz))
79       continue
80     if chunk_hdr_sz != 12:
81       print("%s: %s: The chunk header size was expected to be 12, but is %u."
82             % (me, path, chunk_hdr_sz))
83       continue
84
85     print("%s: Total of %u %u-byte output blocks in %u input chunks."
86           % (path, total_blks, blk_sz, total_chunks))
87
88     if image_checksum != 0:
89       print("checksum=0x%08X" % (image_checksum))
90
91     if not verbose:
92       continue
93     print("            input_bytes      output_blocks")
94     print("chunk    offset     number  offset  number")
95     offset = 0
96     for i in xrange(1,total_chunks+1):
97       header_bin = FH.read(12)
98       header = struct.unpack("<2H2I", header_bin)
99       chunk_type = header[0]
100       reserved1 = header[1]
101       chunk_sz = header[2]
102       total_sz = header[3]
103       data_sz = total_sz - 12
104
105       print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz),
106             end=" ")
107
108       if chunk_type == 0xCAC1:
109         if data_sz != (chunk_sz * blk_sz):
110           print("Raw chunk input size (%u) does not match output size (%u)"
111                 % (data_sz, chunk_sz * blk_sz))
112           break;
113         else:
114           print("Raw data", end="")
115           FH.read(data_sz)
116       elif chunk_type == 0xCAC2:
117         if data_sz != 4:
118           print("Fill chunk should have 4 bytes of fill, but this has %u"
119                 % (data_sz), end="")
120           break;
121         else:
122           fill_bin = FH.read(4)
123           fill = struct.unpack("<I", fill_bin)
124           print("Fill with 0x%08X" % (fill))
125       elif chunk_type == 0xCAC3:
126         if data_sz != 0:
127           print("Don't care chunk input size is non-zero (%u)" % (data_sz))
128           break;
129         else:
130           print("Don't care", end="")
131       elif chunk_type == 0xCAC4:
132         if data_sz != 4:
133           print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
134                 % (data_sz), end="")
135           break;
136         else:
137           crc_bin = FH.read(4)
138           crc = struct.unpack("<I", crc)
139           print("Unverified CRC32 0x%08X" % (crc))
140       else:
141           print("Unknown chunk type 0x%04X" % (chunk_type), end="")
142           break;
143
144       if verbose > 1:
145         header = struct.unpack("<12B", header_bin)
146         print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
147               % (header[0], header[1], header[2], header[3],
148                  header[4], header[5], header[6], header[7],
149                  header[8], header[9], header[10], header[11]))
150       else:
151         print()
152
153       offset += chunk_sz
154
155     print("     %10u            %7u         End" % (FH.tell(), offset))
156
157     if total_blks != offset:
158       print("The header said we should have %u output blocks, but we saw %u"
159             % (total_blks, offset))
160
161     junk_len = len(FH.read())
162     if junk_len:
163       print("There were %u bytes of extra data at the end of the file."
164             % (junk_len))
165
166   sys.exit(0)
167
168 if __name__ == "__main__":
169   main()