Chromium Code Reviews| Index: client/libs/ar/reader.py |
| diff --git a/client/libs/ar/reader.py b/client/libs/ar/reader.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4e0a3f803c86368d37c1f015c846240ef8d3c71a |
| --- /dev/null |
| +++ b/client/libs/ar/reader.py |
| @@ -0,0 +1,91 @@ |
| +# Copyright 2016 The LUCI Authors. All rights reserved. |
| +# Use of this source code is governed under the Apache License, Version 2.0 |
| +# that can be found in the LICENSE file. |
| + |
| +import os |
| +import struct |
| + |
| +from .writer import ArDefaultWriter |
| + |
| +def assert_eq(e, a): |
| + """ |
| + >>> assert_eq(1, 1) |
| + >>> assert_eq(1, 2) |
| + Traceback (most recent call last): |
| + ... |
| + AssertionError: 1 (1) != 2 (2) |
| + >>> assert_eq(1, "1") |
| + Traceback (most recent call last): |
| + ... |
| + AssertionError: 1 (1) != 1 ('1') |
| + """ |
| + assert e == a, "%s (%r) != %s (%r)" % (e, e, a, a) |
| + |
| + |
| +class ArDefaultReader(object): |
| + """Read an ar archive created with default values.""" |
| + |
| + # BSD Variant AR file |
| + |
| + def __init__(self, ibuf, check=False): |
| + self.check = check |
|
M-A Ruel
2016/06/14 13:26:17
I'd prefer self._check and self._ibuf
mithro
2016/06/16 11:37:11
Obsolete.
|
| + if self.check: |
| + try: |
| + assert False |
| + raise ValueError('check mode can\'t be used when asserts are disabled') |
| + except AssertionError: |
| + pass |
| + |
| + self.ibuf = ibuf |
| + assert self.ibuf.read(8) == "!<arch>\n" |
| + |
| + def __iter__(self): |
| + # We generate the default values because comparing strings is cheaper then |
| + # parsing them. |
| + check = self.check |
| + if check: |
| + dmodtime = "%-6i" % ArDefaultWriter.DEFAULT_MODTIME |
| + duid = "%-6i" % ArDefaultWriter.DEFAULT_USER |
| + dgid = "%-6i" % ArDefaultWriter.DEFAULT_GROUP |
| + dmode = "%-6i" % ArDefaultWriter.DEFAULT_MODE |
| + |
| + while True: |
| + header = self.ibuf.read(60) |
| + if not header: |
| + return |
| + |
| + name, modtime, uid, gid, mode, size, magic = struct.unpack( |
| + "16s 12s 6s 6s 8s 10s 2s", header) |
| + |
| + assert name.startswith("#1/"), name |
| + filename_size = int(name[3:]) |
| + if check: |
| + assert_eq(dmodtime, modtime) |
|
M-A Ruel
2016/06/14 13:26:16
+2
mithro
2016/06/16 11:37:11
Obsolete.
|
| + assert_eq(duid, uid) |
| + assert_eq(dgid, gid) |
| + assert_eq(dmode, mode) |
| + data_size = int(size) |
| + assert_eq("\x60\n", magic) |
| + |
| + file_size = data_size - filename_size |
| + fp = self.ibuf.read(filename_size) |
| + |
| + start = self.ibuf.tell() |
| + yield fp, file_size, self.ibuf |
| + end = self.ibuf.tell() |
| + |
| + read = end - start |
| + # If the reader didn't touch the input buffer, seek past the file. |
| + if read == 0: |
|
M-A Ruel
2016/06/14 13:26:17
if not read:
|
| + self.ibuf.seek(file_size, os.SEEK_CUR) |
| + else: |
| + assert read == file_size |
| + |
| + if data_size % 2 != 0: |
|
M-A Ruel
2016/06/14 13:26:17
if data_size % 2:
|
| + padding = self.ibuf.read(1) |
| + assert padding == "\n" |
| + |
| + |
| +if __name__ == "__main__": |
| + import doctest |
| + doctest.testmod() |