webdav: deal with buggy webdav servers in renameExport

box.com already had a special case, since its renaming was known buggy.
In its case, renaming to the temp file succeeds, but then renaming the temp
file to final destination fails.

Then this 4shared server has buggy handling of renames across directories.
While already worked around with for the temp files when storing exports
now being in the same directory as the final filename, that also affected
renameExport when the file moves between directories.

I'm not entirely clear what happens on the 4shared server when it fails
this way. It kind of looks like it may rename the file to destination and
then still fail.

To handle both, when rename fails, delete both the source and the
destination, and fall back to uploading the content again. In the box.com
case, the temp file is the source, and deleting it makes sure the temp file
gets cleaned up. In the 4shared case, the file may have been renamed to the
destination and so cleaning that up avoids any interference with the
re-upload to the destination.
This commit is contained in:
Joey Hess 2021-03-22 13:08:18 -04:00
parent 0af9d1dcb6
commit 5d75cbcdcf
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
5 changed files with 41 additions and 10 deletions

View file

@ -247,15 +247,24 @@ removeExportDirectoryDav hdl dir = withDavHandle hdl $ \h -> runExport h $ \_dav
renameExportDav :: DavHandleVar -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
renameExportDav hdl _k src dest = case (exportLocation src, exportLocation dest) of
(Right srcl, Right destl) -> withDavHandle hdl $ \h ->
-- box.com's DAV endpoint has buggy handling of renames,
-- so avoid renaming when using it.
if boxComUrl `isPrefixOf` baseURL h
then return Nothing
else runExport h $ \dav -> do
maybe noop (void . mkColRecursive) (locationParent destl)
moveDAV (baseURL dav) srcl destl
return (Just ())
(Right srcl, Right destl) -> withDavHandle hdl $ \h -> do
-- Several webdav servers have buggy handing of renames,
-- and fail to rename in some circumstances.
-- Since after a failure it's not clear where the file ended
-- up, recover by deleting both the source and destination.
-- The file will later be re-uploaded to the destination,
-- so this deletion is ok.
let go = runExport h $ \dav -> do
maybe noop (void . mkColRecursive) (locationParent destl)
moveDAV (baseURL dav) srcl destl
return (Just ())
let recover = do
void $ runExport h $ \_dav -> safely $
inLocation srcl delContentM
void $ runExport h $ \_dav -> safely $
inLocation destl delContentM
return Nothing
catchNonAsync go (const recover)
(Left err, _) -> giveup err
(_, Left err) -> giveup err