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..16f8a752d6d5eccd1276cc4d3ea183f0dc93733e |
--- /dev/null |
+++ b/client/libs/ar/reader.py |
@@ -0,0 +1,84 @@ |
+# 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 |
+ 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 |
M-A Ruel
2016/06/09 21:50:44
why?
mithro
2016/06/14 12:15:55
Speed. Looking up check in self repeatedly is quit
M-A Ruel
2016/06/14 13:26:16
We do not use python -O in practice so I don't kno
|
+ 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 header == '': |
M-A Ruel
2016/06/09 21:50:44
if not header:
mithro
2016/06/14 12:15:55
Done.
|
+ return |
+ |
+ name, modtime, uid, gid, mode, size, magic = struct.unpack( |
+ "16s 12s 6s 6s 8s 10s 2s", header) |
+ |
+ assert name.startswith("#1/"), name |
M-A Ruel
2016/06/09 21:50:44
use a real check + raise ValueError()
mithro
2016/06/14 12:15:55
Python -O causes these asserts to totally disappea
|
+ filename_size = int(name[3:]) |
+ if check: |
+ assert_eq(dmodtime, modtime) |
M-A Ruel
2016/06/09 21:50:44
same
mithro
2016/06/14 12:15:55
See above.
|
+ 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: |
+ self.ibuf.seek(file_size, os.SEEK_CUR) |
+ else: |
+ assert read == file_size |
+ |
+ if data_size % 2 != 0: |
+ padding = self.ibuf.read(1) |
+ assert padding == "\n" |
+ |
+ |
+if __name__ == "__main__": |
+ import doctest |
+ doctest.testmod() |