diff options
| author | Pete Zaitcev <zaitcev@kotori.zaitcev.us> | 2014-08-14 13:57:53 -0600 |
|---|---|---|
| committer | Pete Zaitcev <zaitcev@kotori.zaitcev.us> | 2014-08-14 13:57:53 -0600 |
| commit | 3d56b65c898d7997819f2627a2fb722bd0c33b69 (patch) | |
| tree | 3e99288aa0a3f8b83fd046008f5bfa18471b7c96 /swiftclient | |
| parent | 8664eadd19915db3c9b9fc009fc2accbac8f1b93 (diff) | |
| download | python-swiftclient-3d56b65c898d7997819f2627a2fb722bd0c33b69.tar.gz | |
Fix crash when downloading a pseudo-directory
If a user creates an object with name ending with a slash, then
downloading such container ends in a traceback like this:
..............
test5g.file [auth 1.516s, headers 1.560s, total 244.565s, 22.089 MB/s]
Traceback (most recent call last):
File "/usr/lib/python2.6/site-packages/swiftclient/multithreading.py", lin
result = self.func(item, *self.args, **self.kwargs)
File "/usr/lib/python2.6/site-packages/swiftclient/shell.py", line 403, in
fp = open(path, 'wb')
IOError: [Errno 21] Is a directory: 'first-pseudo-folder/'
The proposed fix is not to save this object. Note that the contents of
the object are available with --output option, as before. Only the
crash is fixed.
Even though we do not use the contents, we download the object and
check its Etag, in case. We also create a corresponding directory,
in case the pseudo-directory contains no objects.
The format of printout is changed, so user realizes easier when
pseudo-directory convention is in effect. Note that this is not a
compatibility issue because previously there was crash in such case.
Change-Id: I3352f7a4eaf9970961af0cc84c4706fc1eab281d
Diffstat (limited to 'swiftclient')
| -rwxr-xr-x | swiftclient/shell.py | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/swiftclient/shell.py b/swiftclient/shell.py index ef153c7..f967009 100755 --- a/swiftclient/shell.py +++ b/swiftclient/shell.py @@ -24,7 +24,7 @@ from errno import EEXIST, ENOENT from hashlib import md5 from optparse import OptionParser, SUPPRESS_HELP from os import environ, listdir, makedirs, utime, _exit as os_exit -from os.path import dirname, getmtime, getsize, isdir, join, \ +from os.path import basename, dirname, getmtime, getsize, isdir, join, \ sep as os_path_sep from random import shuffle from sys import argv as sys_argv, exit, stderr, stdout @@ -381,7 +381,9 @@ def st_download(parser, args, thread_manager): content_length = None etag = headers.get('etag') md5sum = None - make_dir = not options.no_download and out_file != "-" + pseudodir = False + no_file = options.no_download + make_dir = not no_file and out_file != "-" if content_type.split(';', 1)[0] == 'text/directory': if make_dir and not isdir(path): mkdirs(path) @@ -397,24 +399,28 @@ def st_download(parser, args, thread_manager): dirpath = dirname(path) if make_dir and dirpath and not isdir(dirpath): mkdirs(dirpath) - if not options.no_download: + if not no_file: if out_file == "-": fp = stdout elif out_file: fp = open(out_file, 'wb') else: - fp = open(path, 'wb') + if basename(path): + fp = open(path, 'wb') + else: + pseudodir = True + no_file = True read_length = 0 if 'x-object-manifest' not in headers and \ 'x-static-large-object' not in headers: md5sum = md5() for chunk in body: - if not options.no_download: + if not no_file: fp.write(chunk) read_length += len(chunk) if md5sum: md5sum.update(chunk) - if not options.no_download: + if not no_file: fp.close() if md5sum and md5sum.hexdigest() != etag: thread_manager.error('%s: md5sum != etag, %s != %s', @@ -424,8 +430,7 @@ def st_download(parser, args, thread_manager): '%s: read_length != content_length, %d != %d', path, read_length, content_length) if 'x-object-meta-mtime' in headers and not options.out_file \ - and not options.no_download: - + and not no_file: mtime = float(headers['x-object-meta-mtime']) utime(path, (mtime, mtime)) if options.verbose: @@ -434,10 +439,15 @@ def st_download(parser, args, thread_manager): headers_receipt = headers_receipt - start_time total_time = finish_time - start_time download_time = total_time - auth_time - time_str = ('auth %.3fs, headers %.3fs, total %.3fs, ' - '%.3f MB/s' % ( - auth_time, headers_receipt, total_time, - float(read_length) / download_time / 1000000)) + if pseudodir: + time_str = ( + 'auth %.3fs, headers %.3fs, total %.3fs, pseudo' % ( + auth_time, headers_receipt, total_time)) + else: + time_str = ( + 'auth %.3fs, headers %.3fs, total %.3fs, %.3f MB/s' % ( + auth_time, headers_receipt, total_time, + float(read_length) / download_time / 1000000)) if conn.attempts > 1: thread_manager.print_msg('%s [%s after %d attempts]', path, time_str, conn.attempts) |
