Skip to content

Commit

Permalink
Fix corrupted S3 downloads when fileobj in append mode
Browse files Browse the repository at this point in the history
  • Loading branch information
hhamalai committed Oct 20, 2018
1 parent f506f39 commit d9d5ee3
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 2 deletions.
14 changes: 14 additions & 0 deletions s3transfer/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ def accepts_kwargs(func):
MAXINT = sys.maxint


def writes_are_seekable(fileobj):
"""Backwards compat function to determine if writes to a fileobj are seekable
:param fileobj: The file-like object to determine if writes are seekable
:returns: True, if in append mode. False, otherwise.
"""
APPEND_ONLY_MODE = 'a'
is_seekable = seekable(fileobj)
if hasattr(fileobj, 'mode') and APPEND_ONLY_MODE in fileobj.mode:
is_seekable = False
return is_seekable


def seekable(fileobj):
"""Backwards compat function to determine if a fileobj is seekable
Expand Down
2 changes: 1 addition & 1 deletion s3transfer/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
ReadTimeoutError

from s3transfer.compat import SOCKET_ERROR
from s3transfer.compat import seekable
from s3transfer.compat import seekable, writes_are_seekable
from s3transfer.exceptions import RetriesExceededError
from s3transfer.futures import IN_MEMORY_DOWNLOAD_TAG
from s3transfer.utils import random_file_extension
Expand Down
8 changes: 7 additions & 1 deletion tests/unit/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from botocore.compat import six

from tests import unittest
from s3transfer.compat import seekable, readable
from s3transfer.compat import seekable, readable, writes_are_seekable


class ErrorRaisingSeekWrapper(object):
Expand Down Expand Up @@ -49,6 +49,12 @@ def test_seekable_fileobj(self):
with open(self.filename, 'w') as f:
self.assertTrue(seekable(f))

def test_non_seekable_append_fileobj(self):
with open(self.filename, 'a') as f:
self.assertFalse(writes_are_seekable(f))
with open(self.filename, 'a+') as f:
self.assertFalse(writes_are_seekable(f))

def test_non_file_like_obj(self):
# Fails becase there is no seekable(), seek(), nor tell()
self.assertFalse(seekable(object()))
Expand Down

0 comments on commit d9d5ee3

Please sign in to comment.