Browse code

Merge branch 'bug/remote-md5sum' into merge

Matt Domsch authored on 2013/05/21 13:48:55
Showing 3 changed files
... ...
@@ -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: