summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/syscalls.cc47
1 files changed, 27 insertions, 20 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 13bb309a8..f8712e92d 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -2509,9 +2509,10 @@ rename (const char *oldpath, const char *newpath)
if (status == STATUS_ACCESS_DENIED && dstpc->exists ()
&& !dstpc->isdir ())
{
+ bool need_open = false;
+
if ((dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) && !trans)
{
- start_transaction (old_trans, trans);
/* As mentioned earlier, opening the file must be part of the
transaction. Therefore we have to reopen the file here if the
transaction hasn't been started already. Unfortunately we
@@ -2521,28 +2522,34 @@ rename (const char *oldpath, const char *newpath)
re-open it. Fortunately nothing has happened yet, so the
atomicity of the rename functionality is not spoiled. */
NtClose (fh);
- retry_reopen:
- status = NtOpenFile (&fh, DELETE,
- oldpc.get_object_attr (attr, sec_none_nih),
- &io, FILE_SHARE_VALID_FLAGS,
- FILE_OPEN_FOR_BACKUP_INTENT
- | (oldpc.is_rep_symlink ()
- ? FILE_OPEN_REPARSE_POINT : 0));
- if (!NT_SUCCESS (status))
+ start_transaction (old_trans, trans);
+ need_open = true;
+ }
+ while (true)
+ {
+ status = STATUS_SUCCESS;
+ if (need_open)
+ status = NtOpenFile (&fh, DELETE,
+ oldpc.get_object_attr (attr, sec_none_nih),
+ &io, FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_FOR_BACKUP_INTENT
+ | (oldpc.is_rep_symlink ()
+ ? FILE_OPEN_REPARSE_POINT : 0));
+ if (NT_SUCCESS (status))
{
- if (NT_TRANSACTIONAL_ERROR (status) && trans)
- {
- /* If NtOpenFile fails due to transactional problems,
- stop transaction and go ahead without. */
- stop_transaction (status, old_trans, trans);
- debug_printf ("Transaction failure. Retry open.");
- goto retry_reopen;
- }
- __seterrno_from_nt_status (status);
- __leave;
+ status = unlink_nt (*dstpc);
+ if (NT_SUCCESS (status))
+ break;
}
+ if (!NT_TRANSACTIONAL_ERROR (status) || !trans)
+ break;
+ /* If NtOpenFile or unlink_nt fail due to transactional problems,
+ stop transaction and retry without. */
+ NtClose (fh);
+ stop_transaction (status, old_trans, trans);
+ debug_printf ("Transaction failure %y. Retry open.", status);
}
- if (NT_SUCCESS (status = unlink_nt (*dstpc)))
+ if (NT_SUCCESS (status))
status = NtSetInformationFile (fh, &io, pfri,
sizeof *pfri + pfri->FileNameLength,
FileRenameInformation);