Skip to content

Commit

Permalink
[sync] download files to a temporary filename, then rename
Browse files Browse the repository at this point in the history
This fix makes all the downloads happen to temporary files of type
.s3cmd.XXXXX.tmp in the same folder as the target file's. Once the
download is complete, the file is renamed to the actual
destination. This renaming is atomic in nature; hence any parallel
thread or process could work on fully downloaded data (by filtering
all files matching .s3cmd.XXXXX.tmp pattern while walking the data
directory).

s3tools#81

Patch manually applied by Matt Domsch because this portion of the code has
changed more than pulling or rebasing could handle.
  • Loading branch information
Sumit Kumar authored and mdomsch committed Dec 6, 2012
1 parent 64dc6a3 commit eecbcba
Showing 1 changed file with 9 additions and 8 deletions.
17 changes: 9 additions & 8 deletions s3cmd
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import subprocess
import htmlentitydefs
import socket
import shutil
import tempfile

from copy import copy
from optparse import OptionParser, Option, OptionValueError, IndentedHelpFormatter
Expand Down Expand Up @@ -783,17 +784,17 @@ def cmd_sync_remote2local(args):
warning(u"%s: destination directory not writable: %s" % (file, dst_dir))
continue
try:
open_flags = os.O_CREAT
open_flags |= os.O_TRUNC
# open_flags |= os.O_EXCL

debug(u"dst_file=%s" % unicodise(dst_file))
# This will have failed should the file exist
os.close(os.open(dst_file, open_flags))
# Yeah I know there is a race condition here. Sadly I don't know how to open() in exclusive mode.
dst_stream = open(dst_file, "wb")
# create temporary files (of type .s3cmd.XXXX.tmp) in the same directory
# for downloading and then rename once downloaded
chkptfd, chkptfname = tempfile.mkstemp(".tmp",".s3cmd.",os.path.dirname(dst_file))
debug(u"created chkptfname=%s" % unicodise(chkptfname))
dst_stream = os.fdopen(chkptfd, "wb")
response = s3.object_get(uri, dst_stream, extra_label = seq_label)
dst_stream.close()
# download completed, rename the file to destination
os.rename(chkptfname, dst_file)
debug(u"renamed chkptfname=%s to dst_file=%s" % (unicodise(chkptfname), unicodise(dst_file)))
if response['headers'].has_key('x-amz-meta-s3cmd-attrs') and cfg.preserve_attrs:
attrs = parse_attrs_header(response['headers']['x-amz-meta-s3cmd-attrs'])
if attrs.has_key('mode'):
Expand Down

0 comments on commit eecbcba

Please sign in to comment.