Revision f390685d tools/psend
b/tools/psend | ||
---|---|---|
1 | 1 |
#!/usr/bin/env python |
2 | 2 |
|
3 |
import os |
|
4 |
import hashlib |
|
5 | 3 |
import sys |
4 |
import os |
|
6 | 5 |
|
7 |
from binascii import hexlify, unhexlify |
|
8 |
from cStringIO import StringIO |
|
9 |
|
|
10 |
from lib.client import Pithos_Client, Fault |
|
6 |
from lib.client import Pithos_Client |
|
11 | 7 |
from lib.util import get_user, get_auth, get_server, get_api |
12 |
|
|
8 |
from lib.transfer import smart_upload |
|
13 | 9 |
|
14 | 10 |
# XXX Get these from container... |
15 | 11 |
BLOCK_SIZE = 4 * 1024 * 1024 |
16 | 12 |
BLOCK_HASH = 'sha256' |
17 | 13 |
|
18 |
|
|
19 |
def file_read_iterator(fp, size=1024): |
|
20 |
while True: |
|
21 |
data = fp.read(size) |
|
22 |
if not data: |
|
23 |
break |
|
24 |
yield data |
|
25 |
|
|
26 |
|
|
27 |
class HashMap(list): |
|
28 |
|
|
29 |
def __init__(self, f): |
|
30 |
super(HashMap, self).__init__() |
|
31 |
self.load(f) |
|
32 |
|
|
33 |
def _hash_raw(self, v): |
|
34 |
h = hashlib.new(BLOCK_HASH) |
|
35 |
h.update(v) |
|
36 |
return h.digest() |
|
37 |
|
|
38 |
def _hash_block(self, v): |
|
39 |
return self._hash_raw(v.rstrip('\x00')) |
|
40 |
|
|
41 |
def hash(self): |
|
42 |
if len(self) == 0: |
|
43 |
return self._hash_raw('') |
|
44 |
if len(self) == 1: |
|
45 |
return self.__getitem__(0) |
|
46 |
|
|
47 |
h = list(self) |
|
48 |
s = 2 |
|
49 |
while s < len(h): |
|
50 |
s = s * 2 |
|
51 |
h += [('\x00' * len(h[0]))] * (s - len(h)) |
|
52 |
while len(h) > 1: |
|
53 |
h = [self._hash_raw(h[x] + h[x + 1]) for x in range(0, len(h), 2)] |
|
54 |
return h[0] |
|
55 |
|
|
56 |
def load(self, f): |
|
57 |
with open(f) as fp: |
|
58 |
for block in file_read_iterator(fp, BLOCK_SIZE): |
|
59 |
self.append(self._hash_block(block)) |
|
60 |
|
|
61 |
|
|
62 |
def smart_upload(client, file): |
|
63 |
dest_container = 'pithos' |
|
64 |
dest_object = os.path.split(file)[-1] |
|
65 |
|
|
66 |
size = os.path.getsize(file) |
|
67 |
hashes = HashMap(sys.argv[1]) |
|
68 |
map = {'bytes': size, 'hashes': [hexlify(x) for x in hashes]} |
|
69 |
|
|
70 |
try: |
|
71 |
client.create_object_by_hashmap(dest_container, dest_object, map) |
|
72 |
except Fault, fault: |
|
73 |
if fault.status != 409: |
|
74 |
raise |
|
75 |
else: |
|
76 |
return |
|
77 |
|
|
78 |
missing = fault.data.split('\n') |
|
79 |
if '' in missing: |
|
80 |
del missing[missing.index(''):] |
|
81 |
|
|
82 |
with open(file) as fp: |
|
83 |
for hash in missing: |
|
84 |
offset = hashes.index(unhexlify(hash)) * BLOCK_SIZE |
|
85 |
fp.seek(offset) |
|
86 |
block = fp.read(BLOCK_SIZE) |
|
87 |
client.create_object('pithos', '.upload', StringIO(block)) |
|
88 |
|
|
89 |
client.create_object_by_hashmap(dest_container, dest_object, map) |
|
90 |
|
|
91 |
|
|
92 | 14 |
if __name__ == '__main__': |
93 | 15 |
if len(sys.argv) != 2 or not os.path.isfile(sys.argv[1]): |
94 | 16 |
print 'syntax: %s <file>' % sys.argv[0] |
95 | 17 |
sys.exit(1) |
96 | 18 |
|
97 | 19 |
client = Pithos_Client(get_server(), get_auth(), get_user()) |
98 |
smart_upload(client, sys.argv[1]) |
|
20 |
smart_upload(client, sys.argv[1], BLOCK_SIZE, BLOCK_HASH) |
Also available in: Unified diff