From: Alex Riesen <raa.lkml@gmail.com>
To: git@vger.kernel.org
Cc: Johannes Schindelin <Johannes.Schindelin@gmx.de>,
Johannes Sixt <j.sixt@viscovery.net>,
Dmitry Potapov <dpotapov@gmail.com>,
Junio C Hamano <gitster@pobox.com>
Subject: [PATCH] Expand the rename(2) workaround in mingw to cover case change in filename
Date: Mon, 8 Jun 2009 22:32:48 +0200 [thread overview]
Message-ID: <20090608203248.GA22972@blimp.localdomain> (raw)
Windows, being a case-confused operating system, sometimes has
problems renaming directory entries with only change in the case
of their characters. Try to work the problem around by using an
intermediate file.
---
NOT TESTED. Can't. My Windows broke again. Not even compile-tested.
And sorry for somewhat extended Cc:. Thought the problem need a little
more experienced attention (then again, maybe it doesn't).
That's a response to Bug 228 (which is properly "WONTFIX",
if you ask my opinion):
http://code.google.com/p/msysgit/issues/detail?id=228
I don't like it, but it is the same what people usually forced to do
anyway, so here it is.
It has a racing problem which can cause the original file be renamed
into a temporary name (as returned by mkstemp):
- the rename of the source name to temp name succeeds
- the rename of temp name to destination name fails (i.e. it
exists and is open)
It is not fixable (because the atomicity of rename(2) is broken by the
intermediate name and two separate calls to rename involved).
I could have tried to rename back to source, but got fed up with
another Windows stupidity and gave up.
compat/mingw.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 55 insertions(+), 10 deletions(-)
diff --git a/compat/mingw.c b/compat/mingw.c
index e190fdd..ad60dff 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -931,21 +931,12 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
return connect(s, sa, sz);
}
-#undef rename
-int mingw_rename(const char *pold, const char *pnew)
+static int move_file_replace(const char *pold, const char *pnew)
{
DWORD attrs, gle;
int tries = 0;
static const int delay[] = { 0, 1, 10, 20, 40 };
- /*
- * Try native rename() first to get errno right.
- * It is based on MoveFile(), which cannot overwrite existing files.
- */
- if (!rename(pold, pnew))
- return 0;
- if (errno != EEXIST)
- return -1;
repeat:
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0;
@@ -982,6 +973,60 @@ repeat:
return -1;
}
+#undef rename
+int mingw_rename(const char *pold, const char *pnew)
+{
+ int fd, rc = -1;
+ char *p, *tmp = NULL;
+
+ /*
+ * Try native rename() first to get errno right.
+ * It is based on MoveFile(), which cannot overwrite existing files.
+ */
+ if (!rename(pold, pnew))
+ return 0;
+ if (errno != EEXIST)
+ return -1;
+ /*
+ * Windows' case-insensitivity does not allow it to directly
+ * do a rename where the only change in the file name is
+ * the change of a letter case. Work this around with a
+ * temporary file.
+ */
+ if (!dst) {
+ errno = EINVAL;
+ goto fail;
+ }
+ tmp = malloc(strlen(dst) + 7 /* reserved for template */);
+ if (!tmp) {
+ errno = ENOMEM;
+ goto fail;
+ }
+ strcpy(tmp, dst);
+ p = tmp + strlen(dst);
+ for (p = tmp + strlen(dst); p > tmp; --p)
+ if ('\\' == *p || '/' == *p) {
+ ++p;
+ break;
+ }
+ strcpy(p, "XXXXXX")
+ fd = mkstemp(tmp);
+ if (fd < 0)
+ goto fail;
+ close(fd);
+ if (move_file_replace(src, tmp)) {
+ rc = errno;
+ unlink(tmp);
+ errno = rc;
+ rc = -1;
+ goto fail;
+ }
+ rc = move_file_replace(tmp, dst);
+fail:
+ free(tmp);
+ return rc;
+}
+
struct passwd *getpwuid(int uid)
{
static char user_name[100];
--
1.6.3.2.214.g82a9d
next reply other threads:[~2009-06-08 20:33 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-08 20:32 Alex Riesen [this message]
2009-06-08 21:59 ` [PATCH] Expand the rename(2) workaround in mingw to cover case change in filename Johannes Schindelin
2009-06-08 22:00 ` Johannes Schindelin
2009-06-08 22:08 ` Alex Riesen
2009-06-09 5:54 ` Johannes Sixt
2009-06-09 6:04 ` Alex Riesen
2009-06-09 7:27 ` Johannes Schindelin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090608203248.GA22972@blimp.localdomain \
--to=raa.lkml@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=dpotapov@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=j.sixt@viscovery.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).