1#!/usr/bin/env python 2import boto 3from boto.exception import S3ResponseError 4from boto.s3.connection import OrdinaryCallingFormat 5 6 7def sizeof_fmt(num): 8 for x in ['b ', 'KB', 'MB', 'GB', 'TB', 'XB']: 9 if num < 1024.0: 10 return "%3.1f %s" % (num, x) 11 num /= 1024.0 12 return "%3.1f %s" % (num, x) 13 14 15def list_bucket(b, prefix=None, marker=None): 16 """List everything in a bucket""" 17 from boto.s3.prefix import Prefix 18 from boto.s3.key import Key 19 total = 0 20 21 if prefix: 22 if not prefix.endswith("/"): 23 prefix = prefix + "/" 24 query = b.list(prefix=prefix, delimiter="/", marker=marker) 25 print("%s" % prefix) 26 else: 27 query = b.list(delimiter="/", marker=marker) 28 29 num = 0 30 for k in query: 31 num += 1 32 mode = "-rwx---" 33 if isinstance(k, Prefix): 34 mode = "drwxr--" 35 size = 0 36 else: 37 size = k.size 38 for g in k.get_acl().acl.grants: 39 if g.id == None: 40 if g.permission == "READ": 41 mode = "-rwxr--" 42 elif g.permission == "FULL_CONTROL": 43 mode = "-rwxrwx" 44 if isinstance(k, Key): 45 print("%s\t%s\t%010s\t%s" % (mode, k.last_modified, 46 sizeof_fmt(size), k.name)) 47 else: 48 #If it's not a Key object, it doesn't have a last_modified time, so 49 #print nothing instead 50 print("%s\t%s\t%010s\t%s" % (mode, ' ' * 24, 51 sizeof_fmt(size), k.name)) 52 total += size 53 print ("=" * 80) 54 print ("\t\tTOTAL: \t%010s \t%i Files" % (sizeof_fmt(total), num)) 55 56 57def list_buckets(s3, display_tags=False): 58 """List all the buckets""" 59 for b in s3.get_all_buckets(): 60 print(b.name) 61 if display_tags: 62 try: 63 tags = b.get_tags() 64 for tag in tags[0]: 65 print(" %s:%s" % (tag.key, tag.value)) 66 except S3ResponseError as e: 67 if e.status != 404: 68 raise 69 70 71def main(): 72 import optparse 73 import sys 74 75 usage = "usage: %prog [options] [BUCKET1] [BUCKET2]" 76 description = "List all S3 buckets OR list keys in the named buckets" 77 parser = optparse.OptionParser(description=description, usage=usage) 78 parser.add_option('-m', '--marker', 79 help='The S3 key where the listing starts after it.') 80 parser.add_option('-t', '--tags', action='store_true', 81 help='Display tags when listing all buckets.') 82 options, buckets = parser.parse_args() 83 marker = options.marker 84 85 if not buckets: 86 list_buckets(boto.connect_s3(), options.tags) 87 sys.exit(0) 88 89 if options.tags: 90 print("-t option only works for the overall bucket list") 91 sys.exit(1) 92 93 pairs = [] 94 mixedCase = False 95 for name in buckets: 96 if "/" in name: 97 pairs.append(name.split("/", 1)) 98 else: 99 pairs.append([name, None]) 100 if pairs[-1][0].lower() != pairs[-1][0]: 101 mixedCase = True 102 103 if mixedCase: 104 s3 = boto.connect_s3(calling_format=OrdinaryCallingFormat()) 105 else: 106 s3 = boto.connect_s3() 107 108 for name, prefix in pairs: 109 list_bucket(s3.get_bucket(name), prefix, marker=marker) 110 111 112if __name__ == "__main__": 113 main() 114