Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved fix for Unicode mistakes in atomic move #4209

Merged
merged 6 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions beets/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,31 +479,40 @@ def move(path, dest, replace=False):
instead, in which case metadata will *not* be preserved. Paths are
translated to system paths.
"""
if os.path.isdir(path):
if os.path.isdir(syspath(path)):
raise FilesystemError(u'source is directory', 'move', (path, dest))
if os.path.isdir(dest):
if os.path.isdir(syspath(dest)):
raise FilesystemError(u'destination is directory', 'move',
(path, dest))
if samefile(path, dest):
return
path = syspath(path)
dest = syspath(dest)
if os.path.exists(dest) and not replace:
if os.path.exists(syspath(dest)) and not replace:
raise FilesystemError('file exists', 'rename', (path, dest))

# First, try renaming the file.
try:
os.replace(path, dest)
os.replace(syspath(path), syspath(dest))
except OSError:
tmp = tempfile.mktemp(suffix='.beets',
prefix=py3_path(b'.' + os.path.basename(dest)),
dir=py3_path(os.path.dirname(dest)))
tmp = syspath(tmp)
# Copy the file to a temporary destination.
basename = os.path.basename(bytestring_path(dest))
dirname = os.path.dirname(bytestring_path(dest))
tmp = tempfile.NamedTemporaryFile(
suffix=syspath(b'.beets', prefix=False),
prefix=syspath(b'.' + basename, prefix=False),
dir=syspath(dirname),
delete=False,
)
try:
with open(syspath(path), 'rb') as f:
shutil.copyfileobj(f, tmp)
finally:
tmp.close()

# Move the copied file into place.
try:
shutil.copyfile(path, tmp)
os.replace(tmp, dest)
os.replace(tmp.name, syspath(dest))
tmp = None
os.remove(path)
os.remove(syspath(path))
except OSError as exc:
raise FilesystemError(exc, 'move', (path, dest),
traceback.format_exc())
Expand Down
3 changes: 3 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Bug fixes:
``r128_album_gain`` fields was changed from integer to float to fix loss of
precision due to truncation.
:bug:`4169`
* Fix a regression in the previous release that caused a `TypeError` when
moving files across filesystems.
:bug:`4168`
* :doc:`/plugins/convert`: Files are no longer converted when running import in
``--pretend`` mode.
* :doc:`/plugins/convert`: Deleting the original files during conversion no
Expand Down