clean: do not attempt to remove startup_info->original_cwd
Acked-by: Derrick Stolee <stolee@gmail.com> Acked-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Dec 9, 2021 at 05:08 UTC
c65744e7d7f512f3666da5964f0ace90325dd94a
2 files changed
+38
-11
builtin/clean.c
+35
-9
@@ -36,6 +36,8 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
36
static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
37
static const char *msg_warn_remove_failed = N_("failed to remove %s");
38
static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
39
+static const char *msg_skip_cwd = N_("Refusing to remove current working directory\n");
40
+static const char *msg_would_skip_cwd = N_("Would refuse to remove current working directory\n");
41
42
enum color_clean {
43
CLEAN_COLOR_RESET = 0,
@@ -153,6 +155,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
155
{
156
DIR *dir;
157
struct strbuf quoted = STRBUF_INIT;
158
+ struct strbuf realpath = STRBUF_INIT;
159
+ struct strbuf real_ocwd = STRBUF_INIT;
160
struct dirent *e;
161
int res = 0, ret = 0, gone = 1, original_len = path->len, len;
162
struct string_list dels = STRING_LIST_INIT_DUP;
@@ -231,16 +235,36 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
235
strbuf_setlen(path, original_len);
236
237
if (*dir_gone) {
234
- res = dry_run ? 0 : rmdir(path->buf);
235
- if (!res)
236
- *dir_gone = 1;
237
- else {
238
- int saved_errno = errno;
239
- quote_path(path->buf, prefix, "ed, 0);
240
- errno = saved_errno;
241
- warning_errno(_(msg_warn_remove_failed), quoted.buf);
238
+ /*
239
+ * Normalize path components in path->buf, e.g. change '\' to
240
+ * '/' on Windows.
241
+ */
242
+ strbuf_realpath(&realpath, path->buf, 1);
243
+
244
+ /*
245
+ * path and realpath are absolute; for comparison, we would
246
+ * like to transform startup_info->original_cwd to an absolute
247
+ * path too.
248
+ */
249
+ if (startup_info->original_cwd)
250
+ strbuf_realpath(&real_ocwd,
251
+ startup_info->original_cwd, 1);
252
+
253
+ if (!strbuf_cmp(&realpath, &real_ocwd)) {
254
+ printf("%s", dry_run ? _(msg_would_skip_cwd) : _(msg_skip_cwd));
255
*dir_gone = 0;
243
- ret = 1;
256
+ } else {
257
+ res = dry_run ? 0 : rmdir(path->buf);
258
+ if (!res)
259
+ *dir_gone = 1;
260
+ else {
261
+ int saved_errno = errno;
262
+ quote_path(path->buf, prefix, "ed, 0);
263
+ errno = saved_errno;
264
+ warning_errno(_(msg_warn_remove_failed), quoted.buf);
265
+ *dir_gone = 0;
266
+ ret = 1;
267
+ }
268
}
269
}
270
@@ -250,6 +274,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
274
printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
275
}
276
out:
277
+ strbuf_release(&realpath);
278
+ strbuf_release(&real_ocwd);
279
strbuf_release("ed);
280
string_list_clear(&dels, 0);
281
return ret;
t/t2501-cwd-empty.sh
+3
-2
@@ -230,8 +230,9 @@ test_incidental_untracked_dir_removal () {
230
}
231
232
test_expect_success 'clean does not remove cwd incidentally' '
233
- test_incidental_untracked_dir_removal failure \
234
- git -C .. clean -fd -e warnings . >warnings
233
+ test_incidental_untracked_dir_removal success \
234
+ git -C .. clean -fd -e warnings . >warnings &&
235
+ grep "Refusing to remove current working directory" warnings
236
'
237
238
test_expect_success 'stash does not remove cwd incidentally' '