| ... | ... |
@@ -18,7 +18,7 @@ import sys |
| 18 | 18 |
import glob |
| 19 | 19 |
import copy |
| 20 | 20 |
|
| 21 |
-__all__ = ["fetch_local_list", "fetch_remote_list", "compare_filelists", "filter_exclude_include", "parse_attrs_header"] |
|
| 21 |
+__all__ = ["fetch_local_list", "fetch_remote_list", "compare_filelists", "filter_exclude_include"] |
|
| 22 | 22 |
|
| 23 | 23 |
def _fswalk_follow_symlinks(path): |
| 24 | 24 |
''' |
| ... | ... |
@@ -307,12 +307,12 @@ def fetch_remote_list(args, require_attribs = False, recursive = None): |
| 307 | 307 |
'md5': response['headers']['etag'].strip('"\''),
|
| 308 | 308 |
'timestamp' : dateRFC822toUnix(response['headers']['date']) |
| 309 | 309 |
}) |
| 310 |
- # get md5 from header if it's present. We would have set that during upload |
|
| 311 |
- if response['headers'].has_key('x-amz-meta-s3cmd-attrs'):
|
|
| 312 |
- attrs = parse_attrs_header(response['headers']['x-amz-meta-s3cmd-attrs']) |
|
| 313 |
- if attrs.has_key('md5'):
|
|
| 314 |
- remote_item.update({'md5': attrs['md5']})
|
|
| 315 |
- debug(u"retreived md5=%s from headers" % (attrs['md5'])) |
|
| 310 |
+ try: |
|
| 311 |
+ md5 = response['s3cmd-attrs']['md5'] |
|
| 312 |
+ remote_item.update({'md5': md5})
|
|
| 313 |
+ debug(u"retreived md5=%s from headers" % md5) |
|
| 314 |
+ except KeyError: |
|
| 315 |
+ pass |
|
| 316 | 316 |
|
| 317 | 317 |
def _get_filelist_remote(remote_uri, recursive = True): |
| 318 | 318 |
## If remote_uri ends with '/' then all remote files will have |
| ... | ... |
@@ -432,13 +432,6 @@ def fetch_remote_list(args, require_attribs = False, recursive = None): |
| 432 | 432 |
remote_list.record_md5(key, md5) |
| 433 | 433 |
return remote_list |
| 434 | 434 |
|
| 435 |
-def parse_attrs_header(attrs_header): |
|
| 436 |
- attrs = {}
|
|
| 437 |
- for attr in attrs_header.split("/"):
|
|
| 438 |
- key, val = attr.split(":")
|
|
| 439 |
- attrs[key] = val |
|
| 440 |
- return attrs |
|
| 441 |
- |
|
| 442 | 435 |
|
| 443 | 436 |
def compare_filelists(src_list, dst_list, src_remote, dst_remote, delay_updates = False): |
| 444 | 437 |
def __direction_str(is_remote): |
| ... | ... |
@@ -669,6 +669,9 @@ class S3(object): |
| 669 | 669 |
response["reason"] = http_response.reason |
| 670 | 670 |
response["headers"] = convertTupleListToDict(http_response.getheaders()) |
| 671 | 671 |
response["data"] = http_response.read() |
| 672 |
+ if response["headers"].has_key("x-amz-meta-s3cmd-attrs"):
|
|
| 673 |
+ attrs = parse_attrs_header(response["headers"]["x-amz-meta-s3cmd-attrs"]) |
|
| 674 |
+ response["s3cmd-attrs"] = attrs |
|
| 672 | 675 |
debug("Response: " + str(response))
|
| 673 | 676 |
ConnMan.put(conn) |
| 674 | 677 |
except ParameterError, e: |
| ... | ... |
@@ -975,4 +978,10 @@ class S3(object): |
| 975 | 975 |
return response |
| 976 | 976 |
__all__.append("S3")
|
| 977 | 977 |
|
| 978 |
+def parse_attrs_header(attrs_header): |
|
| 979 |
+ attrs = {}
|
|
| 980 |
+ for attr in attrs_header.split("/"):
|
|
| 981 |
+ key, val = attr.split(":")
|
|
| 982 |
+ attrs[key] = val |
|
| 983 |
+ return attrs |
|
| 978 | 984 |
# vim:et:ts=4:sts=4:ai |
| ... | ... |
@@ -155,12 +155,22 @@ def subcmd_bucket_list(s3, uri): |
| 155 | 155 |
"uri": uri.compose_uri(bucket, prefix["Prefix"])}) |
| 156 | 156 |
|
| 157 | 157 |
for object in response["list"]: |
| 158 |
+ md5 = object['ETag'].strip('"')
|
|
| 159 |
+ if cfg.list_md5: |
|
| 160 |
+ if md5.find('-') >= 0: # need to get md5 from the object
|
|
| 161 |
+ object_uri = uri.compose_uri(bucket, object["Key"]) |
|
| 162 |
+ info_response = s3.object_info(S3Uri(object_uri)) |
|
| 163 |
+ try: |
|
| 164 |
+ md5 = info_response['s3cmd-attrs']['md5'] |
|
| 165 |
+ except KeyError: |
|
| 166 |
+ pass |
|
| 167 |
+ |
|
| 158 | 168 |
size, size_coeff = formatSize(object["Size"], Config().human_readable_sizes) |
| 159 | 169 |
output(format_string % {
|
| 160 | 170 |
"timestamp": formatDateTime(object["LastModified"]), |
| 161 | 171 |
"size" : str(size), |
| 162 | 172 |
"coeff": size_coeff, |
| 163 |
- "md5" : object['ETag'].strip('"'),
|
|
| 173 |
+ "md5" : md5, |
|
| 164 | 174 |
"uri": uri.compose_uri(bucket, object["Key"]), |
| 165 | 175 |
}) |
| 166 | 176 |
|
| ... | ... |
@@ -319,6 +329,10 @@ def cmd_object_put(args): |
| 319 | 319 |
seq_label = "[%d of %d]" % (seq, local_count) |
| 320 | 320 |
if Config().encrypt: |
| 321 | 321 |
exitcode, full_name, extra_headers["x-amz-meta-s3tools-gpgenc"] = gpg_encrypt(full_name_orig) |
| 322 |
+ if cfg.preserve_attrs or local_list[key]['size'] > (cfg.multipart_chunk_size_mb * 1024 * 1024): |
|
| 323 |
+ attr_header = _build_attr_header(local_list, key) |
|
| 324 |
+ debug(u"attr_header: %s" % attr_header) |
|
| 325 |
+ extra_headers.update(attr_header) |
|
| 322 | 326 |
try: |
| 323 | 327 |
response = s3.object_put(full_name, uri_final, extra_headers, extra_label = seq_label) |
| 324 | 328 |
except S3UploadError, e: |
| ... | ... |
@@ -606,7 +620,12 @@ def cmd_info(args): |
| 606 | 606 |
output(u" File size: %s" % info['headers']['content-length']) |
| 607 | 607 |
output(u" Last mod: %s" % info['headers']['last-modified']) |
| 608 | 608 |
output(u" MIME type: %s" % info['headers']['content-type']) |
| 609 |
- output(u" MD5 sum: %s" % info['headers']['etag'].strip('"'))
|
|
| 609 |
+ md5 = info['headers']['etag'].strip('"')
|
|
| 610 |
+ try: |
|
| 611 |
+ md5 = info['s3cmd-attrs']['md5'] |
|
| 612 |
+ except KeyError: |
|
| 613 |
+ pass |
|
| 614 |
+ output(u" MD5 sum: %s" % md5) |
|
| 610 | 615 |
else: |
| 611 | 616 |
info = s3.bucket_info(uri) |
| 612 | 617 |
output(u"%s (bucket):" % uri.uri()) |
| ... | ... |
@@ -863,8 +882,8 @@ def cmd_sync_remote2local(args): |
| 863 | 863 |
os.chmod(dst_file, mode); |
| 864 | 864 |
|
| 865 | 865 |
debug(u"renamed chkptfname=%s to dst_file=%s" % (unicodise(chkptfname), unicodise(dst_file))) |
| 866 |
- if response['headers'].has_key('x-amz-meta-s3cmd-attrs') and cfg.preserve_attrs:
|
|
| 867 |
- attrs = parse_attrs_header(response['headers']['x-amz-meta-s3cmd-attrs']) |
|
| 866 |
+ if response.has_key('s3cmd-attrs') and cfg.preserve_attrs:
|
|
| 867 |
+ attrs = response['s3cmd-attrs'] |
|
| 868 | 868 |
if attrs.has_key('mode'):
|
| 869 | 869 |
os.chmod(dst_file, int(attrs['mode'])) |
| 870 | 870 |
if attrs.has_key('mtime') or attrs.has_key('atime'):
|
| ... | ... |
@@ -984,41 +1003,42 @@ def remote_copy(s3, copy_pairs, destination_base): |
| 984 | 984 |
raise |
| 985 | 985 |
return (len(copy_pairs), saved_bytes) |
| 986 | 986 |
|
| 987 |
+def _build_attr_header(local_list, src): |
|
| 988 |
+ import pwd, grp |
|
| 989 |
+ attrs = {}
|
|
| 990 |
+ for attr in cfg.preserve_attrs_list: |
|
| 991 |
+ if attr == 'uname': |
|
| 992 |
+ try: |
|
| 993 |
+ val = pwd.getpwuid(local_list[src]['uid']).pw_name |
|
| 994 |
+ except KeyError: |
|
| 995 |
+ attr = "uid" |
|
| 996 |
+ val = local_list[src].get('uid')
|
|
| 997 |
+ warning(u"%s: Owner username not known. Storing UID=%d instead." % (src, val)) |
|
| 998 |
+ elif attr == 'gname': |
|
| 999 |
+ try: |
|
| 1000 |
+ val = grp.getgrgid(local_list[src].get('gid')).gr_name
|
|
| 1001 |
+ except KeyError: |
|
| 1002 |
+ attr = "gid" |
|
| 1003 |
+ val = local_list[src].get('gid')
|
|
| 1004 |
+ warning(u"%s: Owner groupname not known. Storing GID=%d instead." % (src, val)) |
|
| 1005 |
+ elif attr == 'md5': |
|
| 1006 |
+ try: |
|
| 1007 |
+ val = local_list.get_md5(src) |
|
| 1008 |
+ except IOError: |
|
| 1009 |
+ val = None |
|
| 1010 |
+ else: |
|
| 1011 |
+ val = getattr(local_list[src]['sr'], 'st_' + attr) |
|
| 1012 |
+ attrs[attr] = val |
|
| 1013 |
+ |
|
| 1014 |
+ if 'md5' in attrs and attrs['md5'] is None: |
|
| 1015 |
+ del attrs['md5'] |
|
| 987 | 1016 |
|
| 988 |
-def cmd_sync_local2remote(args): |
|
| 989 |
- def _build_attr_header(local_list, src): |
|
| 990 |
- import pwd, grp |
|
| 991 |
- attrs = {}
|
|
| 992 |
- for attr in cfg.preserve_attrs_list: |
|
| 993 |
- if attr == 'uname': |
|
| 994 |
- try: |
|
| 995 |
- val = pwd.getpwuid(local_list[src]['uid']).pw_name |
|
| 996 |
- except KeyError: |
|
| 997 |
- attr = "uid" |
|
| 998 |
- val = local_list[src].get('uid')
|
|
| 999 |
- warning(u"%s: Owner username not known. Storing UID=%d instead." % (src, val)) |
|
| 1000 |
- elif attr == 'gname': |
|
| 1001 |
- try: |
|
| 1002 |
- val = grp.getgrgid(local_list[src].get('gid')).gr_name
|
|
| 1003 |
- except KeyError: |
|
| 1004 |
- attr = "gid" |
|
| 1005 |
- val = local_list[src].get('gid')
|
|
| 1006 |
- warning(u"%s: Owner groupname not known. Storing GID=%d instead." % (src, val)) |
|
| 1007 |
- elif attr == 'md5': |
|
| 1008 |
- try: |
|
| 1009 |
- val = local_list.get_md5(src) |
|
| 1010 |
- except IOError: |
|
| 1011 |
- val = None |
|
| 1012 |
- else: |
|
| 1013 |
- val = getattr(local_list[src]['sr'], 'st_' + attr) |
|
| 1014 |
- attrs[attr] = val |
|
| 1017 |
+ result = "" |
|
| 1018 |
+ for k in attrs: result += "%s:%s/" % (k, attrs[k]) |
|
| 1019 |
+ return { 'x-amz-meta-s3cmd-attrs' : result[:-1] }
|
|
| 1015 | 1020 |
|
| 1016 |
- if 'md5' in attrs and attrs['md5'] is None: |
|
| 1017 |
- del attrs['md5'] |
|
| 1018 | 1021 |
|
| 1019 |
- result = "" |
|
| 1020 |
- for k in attrs: result += "%s:%s/" % (k, attrs[k]) |
|
| 1021 |
- return { 'x-amz-meta-s3cmd-attrs' : result[:-1] }
|
|
| 1022 |
+def cmd_sync_local2remote(args): |
|
| 1022 | 1023 |
|
| 1023 | 1024 |
def _do_deletes(s3, remote_list): |
| 1024 | 1025 |
if cfg.max_delete > 0 and len(remote_list) > cfg.max_delete: |