Use os.fstat wherever possible

This commit is contained in:
Markus Unterwaditzer 2016-05-26 20:03:01 +02:00
parent d24f3835ef
commit b3d70a7a93
2 changed files with 17 additions and 27 deletions

View file

@ -9,8 +9,7 @@ from atomicwrites import atomic_write
from .base import Item, Storage, normalize_meta_value
from .. import exceptions
from ..utils import checkdir, expand_path, generate_href, get_etag_from_file, \
get_etag_from_fileobject
from ..utils import checkdir, expand_path, generate_href, get_etag_from_file
from ..utils.compat import text_type, to_native
logger = logging.getLogger(__name__)
@ -137,7 +136,7 @@ class FilesystemStorage(Storage):
try:
with atomic_write(fpath, mode='wb', overwrite=False) as f:
f.write(item.raw.encode(self.encoding))
return fpath, get_etag_from_fileobject(f)
return fpath, get_etag_from_file(f)
except OSError as e:
if e.errno == errno.EEXIST:
raise exceptions.AlreadyExistingError(existing_href=href)
@ -157,7 +156,7 @@ class FilesystemStorage(Storage):
with atomic_write(fpath, mode='wb', overwrite=True) as f:
f.write(item.raw.encode(self.encoding))
etag = get_etag_from_fileobject(f)
etag = get_etag_from_file(f)
if self.post_hook:
self._run_post_hook(fpath)

View file

@ -53,35 +53,26 @@ def uniq(s):
yield x
def get_etag_from_file(fpath):
'''Get mtime-based etag from a filepath.'''
stat = os.stat(fpath)
def get_etag_from_file(f):
'''Get mtime-based etag from a filepath or file-like object.
This function will flush/sync the file as much as necessary to obtain a
correct mtime.
'''
if hasattr(f, 'read'):
f.flush() # Only this is necessary on Linux
if sys.platform == 'win32':
os.fsync(f.fileno()) # Apparently necessary on Windows
stat = os.fstat(f.fileno())
else:
stat = os.stat(f)
mtime = getattr(stat, 'st_mtime_ns', None)
if mtime is None:
mtime = stat.st_mtime
return '{:.9f}'.format(mtime)
def get_etag_from_fileobject(f):
'''
Get mtime-based etag from a local file's fileobject.
This function will flush/sync the file as much as necessary to obtain a
correct mtime.
In filesystem-based storages, this is used instead of
:py:func:`get_etag_from_file` to determine the correct etag *before*
writing the temporary file to the target location.
This works because, as far as I've tested, moving and linking a file
doesn't change its mtime.
'''
f.flush() # Only this is necessary on Linux
if sys.platform == 'win32':
os.fsync(f.fileno()) # Apparently necessary on Windows
return get_etag_from_file(f.name)
def get_storage_init_specs(cls, stop_at=object):
if cls is stop_at:
return ()