Home | History | Annotate | Download | only in libsparse
      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_bin)
    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()
    170