commit 8ec7352a93a3c62a7786b92e4183aa7cb0b34869 from: Stefan Sperling via: Thomas Adam date: Thu Jun 01 10:18:37 2023 UTC only delete empty directories appearing in arguments to 'got rm' Make 'got rm' keep empty directories which are not explicitly listed for deletion. Deleting such directories is problematic in several use cases. Avoids deleting the current working directory when the user runs "got rm *" (pointed out by Mikhail), and avoids deletion of an empty directory "foo/" after 'got rm foo/a foo/b' (pointed out by op@). ok jamsek, op commit - 00580e07010e9d6aab00f67b628381ca81f19def commit + 8ec7352a93a3c62a7786b92e4183aa7cb0b34869 blob - e02fba3a7dd77de4b2b04a5b483529660338f5f6 blob + 5ff4c0008aaff91e17805726113b20ed707f0c5a --- lib/worktree.c +++ lib/worktree.c @@ -4309,6 +4309,8 @@ struct schedule_deletion_args { int delete_local_mods; int keep_on_disk; int ignore_missing_paths; + const char *status_path; + size_t status_path_len; const char *status_codes; }; @@ -4407,11 +4409,17 @@ schedule_for_deletion(void *arg, unsigned char status, root_len = strlen(a->worktree->root_path); do { char *parent; + err = got_path_dirname(&parent, ondisk_path); if (err) goto done; free(ondisk_path); ondisk_path = parent; + if (got_path_cmp(ondisk_path, a->status_path, + strlen(ondisk_path), a->status_path_len) != 0 && + !got_path_is_child(ondisk_path, a->status_path, + a->status_path_len)) + break; if (rmdir(ondisk_path) == -1) { if (errno != ENOTEMPTY) err = got_error_from_errno2("rmdir", @@ -4465,8 +4473,19 @@ got_worktree_schedule_delete(struct got_worktree *work sda.status_codes = status_codes; TAILQ_FOREACH(pe, paths, entry) { + char *ondisk_status_path; + + if (asprintf(&ondisk_status_path, "%s%s%s", + got_worktree_get_root_path(worktree), + pe->path[0] == '\0' ? "" : "/", pe->path) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + sda.status_path = ondisk_status_path; + sda.status_path_len = strlen(ondisk_status_path); err = worktree_status(worktree, pe->path, fileindex, repo, schedule_for_deletion, &sda, NULL, NULL, 1, 1); + free(ondisk_status_path); if (err) break; } @@ -9835,7 +9854,9 @@ got_worktree_patch_schedule_rm(const char *path, struc struct got_worktree *worktree, struct got_fileindex *fileindex, got_worktree_delete_cb progress_cb, void *progress_arg) { + const struct got_error *err; struct schedule_deletion_args sda; + char *ondisk_status_path; memset(&sda, 0, sizeof(sda)); sda.worktree = worktree; @@ -9847,9 +9868,16 @@ got_worktree_patch_schedule_rm(const char *path, struc sda.keep_on_disk = 0; sda.ignore_missing_paths = 0; sda.status_codes = NULL; - - return worktree_status(worktree, path, fileindex, repo, + if (asprintf(&ondisk_status_path, "%s/%s", + got_worktree_get_root_path(worktree), path) == -1) + return got_error_from_errno("asprintf"); + sda.status_path = ondisk_status_path; + sda.status_path_len = strlen(ondisk_status_path); + + err = worktree_status(worktree, path, fileindex, repo, schedule_for_deletion, &sda, NULL, NULL, 1, 1); + free(ondisk_status_path); + return err; } const struct got_error *