Skip to content

Commit fa2e71c

Browse files
committed
Do not expect unlink(2) to fail on a directory.
When "git checkout-index" checks out path A/B/C, it makes sure A and A/B are truly directories; if there is a regular file or symlink at A, we prefer to remove it. We used to do this by catching an error return from mkdir(2), and on EEXIST did unlink(2), and when it succeeded, tried another mkdir(2). Thomas Glanzmann found out the above does not work on Solaris for a root user, as unlink(2) was so old fashioned there that it allowed to unlink a directory. As pointed out, this still doesn't guarantee that git won't call "unlink()" on a directory (race conditions etc), but that's fundamentally true (there is no "funlink()" like there is "fstat()"), and besides, that is in no way git-specific (ie it's true of any application that gets run as root). Acked-by: Linus Torvalds <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ffb293b commit fa2e71c

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

entry.c

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,40 @@ static void create_directories(const char *path, const struct checkout *state)
88
const char *slash = path;
99

1010
while ((slash = strchr(slash+1, '/')) != NULL) {
11+
struct stat st;
12+
int stat_status;
13+
1114
len = slash - path;
1215
memcpy(buf, path, len);
1316
buf[len] = 0;
17+
18+
if (len <= state->base_dir_len)
19+
/*
20+
* checkout-index --prefix=<dir>; <dir> is
21+
* allowed to be a symlink to an existing
22+
* directory.
23+
*/
24+
stat_status = stat(buf, &st);
25+
else
26+
/*
27+
* if there currently is a symlink, we would
28+
* want to replace it with a real directory.
29+
*/
30+
stat_status = lstat(buf, &st);
31+
32+
if (!stat_status && S_ISDIR(st.st_mode))
33+
continue; /* ok, it is already a directory. */
34+
35+
/*
36+
* We know stat_status == 0 means something exists
37+
* there and this mkdir would fail, but that is an
38+
* error codepath; we do not care, as we unlink and
39+
* mkdir again in such a case.
40+
*/
1441
if (mkdir(buf, 0777)) {
15-
if (errno == EEXIST) {
16-
struct stat st;
17-
if (len > state->base_dir_len && state->force && !unlink(buf) && !mkdir(buf, 0777))
18-
continue;
19-
if (!stat(buf, &st) && S_ISDIR(st.st_mode))
20-
continue; /* ok */
21-
}
42+
if (errno == EEXIST && state->force &&
43+
!unlink(buf) && !mkdir(buf, 0777))
44+
continue;
2245
die("cannot create directory at %s", buf);
2346
}
2447
}

0 commit comments

Comments
 (0)