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() |