static void remove_sequencer_state(void) { struct strbuf seq_dir = STRBUF_INIT; strbuf_addf(&seq_dir, "%s", git_path(SEQ_DIR)); remove_dir_recursively(&seq_dir, 0); strbuf_release(&seq_dir); }
static NORETURN void exit_cleanup(const char *tmpdir, int exit_code) { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, tmpdir); remove_dir_recursively(&buf, 0); if (exit_code) warning(_("failed: %d"), exit_code); exit(exit_code); }
static int remove_feed(const char *feed, int options) { char url[URL_MAX], alias[PATH_MAX], path[PATH_MAX]; int err; char answer; if (find_feed_url(feed, url)) { strcpy(alias, feed); } else if (find_feed_alias(feed, alias)) { strcpy(url, feed); } else { fprintf(stderr, "%s: no such feed.\n", feed); return -1; } if (options & OPT_REMOVE_CONFIRM) { printf("remove feed %s? (y/N) ", alias); scanf("%c", &answer); if (answer != 'y' && answer != 'Y') { printf("not removing feed %s.\n", alias); return 0; } } printf("removing feed %s.\n", alias); sprintf(path, "%s/%s", RSS_DIR, alias); // first remove the data if (options & OPT_REMOVE_FORCE) { err = remove_dir_recursively(path); if (err) { fprintf(stderr, "error: unable to remove directory %s.\n", path); return -1; } } else { err = rmdir(path); if (err) { if (errno == ENOTEMPTY) { fprintf(stderr, "%s: directory not empty: use -f to force removal.\n", path); return -1; } else { fprintf(stderr, "%s: unable to remove.\n", path); return -1; } } } rm_feed(url, alias); printf("successfully removed feed %s.\n", alias); return 0; }
int notes_merge_abort(struct notes_merge_options *o) { /* Remove .git/NOTES_MERGE_WORKTREE directory and all files within */ struct strbuf buf = STRBUF_INIT; int ret; strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE)); OUTPUT(o, 3, "Removing notes merge worktree at %s", buf.buf); ret = remove_dir_recursively(&buf, 0); strbuf_release(&buf); return ret; }
int remove_dir_recursively(struct strbuf *path, int flag) { DIR *dir; struct dirent *e; int ret = 0, original_len = path->len, len; int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY); int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL); unsigned char submodule_head[20]; if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) && !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) /* Do not descend and nuke a nested git work tree. */ return 0; flag &= ~(REMOVE_DIR_KEEP_TOPLEVEL|REMOVE_DIR_KEEP_NESTED_GIT); dir = opendir(path->buf); if (!dir) { if (!keep_toplevel) return rmdir(path->buf); else return -1; } if (path->buf[original_len - 1] != '/') strbuf_addch(path, '/'); len = path->len; while ((e = readdir(dir)) != NULL) { struct stat st; if (is_dot_or_dotdot(e->d_name)) continue; strbuf_setlen(path, len); strbuf_addstr(path, e->d_name); if (lstat(path->buf, &st)) ; /* fall thru */ else if (S_ISDIR(st.st_mode)) { if (!remove_dir_recursively(path, flag)) continue; /* happy */ } else if (!only_empty && !unlink(path->buf)) continue; /* happy, too */ /* path too long, stat fails, or non-directory still exists */ ret = -1; break; } closedir(dir); strbuf_setlen(path, original_len); if (!ret && !keep_toplevel) ret = rmdir(path->buf); return ret; }
static int delete_git_dir(struct worktree *wt) { struct strbuf sb = STRBUF_INIT; int ret = 0; strbuf_addstr(&sb, git_common_path("worktrees/%s", wt->id)); if (remove_dir_recursively(&sb, 0)) { error_errno(_("failed to delete '%s'"), sb.buf); ret = -1; } strbuf_release(&sb); return ret; }
int git2_creat_force(const char *path, int mode) { if (git2_mkdir_2file(path) < GIT_OK) return GIT_ERROR; if (!git2_isdir(path)) { struct strbuf pathbuf = STRBUF_INIT; char * buf_path = xmalloc(strlen(path)*sizeof(char)); memcpy(buf_path, path, strlen(path)*sizeof(char)); strbuf_attach(&pathbuf, (void *)buf_path, strlen(path)*sizeof(char), strlen(path)*sizeof(char)); if (remove_dir_recursively(&pathbuf) != 0) return GIT_ERROR; } return git2_creat(path, mode); }
int notes_merge_abort(struct notes_merge_options *o) { /* * Remove all files within .git/NOTES_MERGE_WORKTREE. We do not remove * the .git/NOTES_MERGE_WORKTREE directory itself, since it might be * the current working directory of the user. */ struct strbuf buf = STRBUF_INIT; int ret; git_path_buf(&buf, NOTES_MERGE_WORKTREE); if (o->verbosity >= 3) printf("Removing notes merge worktree at %s/*\n", buf.buf); ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL); strbuf_release(&buf); return ret; }
int sequencer_remove_state(struct replay_opts *opts) { struct strbuf dir = STRBUF_INIT; int i; free(opts->gpg_sign); free(opts->strategy); for (i = 0; i < opts->xopts_nr; i++) free(opts->xopts[i]); free(opts->xopts); strbuf_addf(&dir, "%s", get_dir(opts)); remove_dir_recursively(&dir, 0); strbuf_release(&dir); return 0; }
static int remove_empty_directories(const char *file) { /* we want to create a file but there is a directory there; * if that is an empty directory (or a directory that contains * only empty directories), remove them. */ struct strbuf path; int result; strbuf_init(&path, 20); strbuf_addstr(&path, file); result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY); strbuf_release(&path); return result; }
int remove_dir_recursively(struct strbuf *path) { DIR *dir; struct dirent *e; int ret = 0, original_len = path->len, len; dir = opendir(path->buf); if (!dir) return rmdir(path->buf); if (path->buf[original_len - 1] != '/') strbuf_addch(path, '/'); len = path->len; while ((e = readdir(dir)) != NULL) { struct stat st; if (strcmp(e->d_name, "..") == 0 || strcmp(e->d_name, ".")==0) continue; strbuf_setlen(path, len); strbuf_addstr(path, e->d_name); if (lstat(path->buf, &st)) ; /* fall thru */ else if (S_ISDIR(st.st_mode)) { if (!remove_dir_recursively(path)) continue; /* happy */ } else if (!unlink(path->buf)) continue; /* happy, too */ /* path too long, stat fails, or non-directory still exists */ ret = -1; break; } closedir(dir); strbuf_setlen(path, original_len); if (!ret) ret = rmdir(path->buf); return ret; }
static void remove_test_directory(void) { if (mtime_dir.len) remove_dir_recursively(&mtime_dir, 0); }
static int rsync_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; int result = 0, i; struct child_process rsync; const char *args[10]; if (flags & TRANSPORT_PUSH_MIRROR) return error("rsync transport does not support mirror mode"); /* first push the objects */ strbuf_addstr(&buf, rsync_url(transport->url)); strbuf_addch(&buf, '/'); memset(&rsync, 0, sizeof(rsync)); rsync.argv = args; rsync.stdout_to_stderr = 1; i = 0; args[i++] = "rsync"; args[i++] = "-a"; if (flags & TRANSPORT_PUSH_DRY_RUN) args[i++] = "--dry-run"; if (transport->verbose > 1) args[i++] = "-v"; args[i++] = "--ignore-existing"; args[i++] = "--exclude"; args[i++] = "info"; args[i++] = get_object_directory(); args[i++] = buf.buf; args[i++] = NULL; if (run_command(&rsync)) return error("Could not push objects to %s", rsync_url(transport->url)); /* copy the refs to the temporary directory; they could be packed. */ strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); if (!mkdtemp(temp_dir.buf)) die_errno ("Could not make temporary directory"); strbuf_addch(&temp_dir, '/'); if (flags & TRANSPORT_PUSH_ALL) { if (for_each_ref(write_one_ref, &temp_dir)) return -1; } else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec)) return -1; i = 2; if (flags & TRANSPORT_PUSH_DRY_RUN) args[i++] = "--dry-run"; if (!(flags & TRANSPORT_PUSH_FORCE)) args[i++] = "--ignore-existing"; args[i++] = temp_dir.buf; args[i++] = rsync_url(transport->url); args[i++] = NULL; if (run_command(&rsync)) result = error("Could not push to %s", rsync_url(transport->url)); if (remove_dir_recursively(&temp_dir, 0)) warning ("Could not remove temporary directory %s.", temp_dir.buf); strbuf_release(&buf); strbuf_release(&temp_dir); return result; }
static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) { struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; struct ref dummy = {NULL}, *tail = &dummy; struct child_process rsync; const char *args[5]; int temp_dir_len; if (for_push) return NULL; /* copy the refs to the temporary directory */ strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); if (!mkdtemp(temp_dir.buf)) die_errno ("Could not make temporary directory"); temp_dir_len = temp_dir.len; strbuf_addstr(&buf, rsync_url(transport->url)); strbuf_addstr(&buf, "/refs"); memset(&rsync, 0, sizeof(rsync)); rsync.argv = args; rsync.stdout_to_stderr = 1; args[0] = "rsync"; args[1] = (transport->verbose > 1) ? "-rv" : "-r"; args[2] = buf.buf; args[3] = temp_dir.buf; args[4] = NULL; if (run_command(&rsync)) die ("Could not run rsync to get refs"); strbuf_reset(&buf); strbuf_addstr(&buf, rsync_url(transport->url)); strbuf_addstr(&buf, "/packed-refs"); args[2] = buf.buf; if (run_command(&rsync)) die ("Could not run rsync to get refs"); /* read the copied refs */ strbuf_addstr(&temp_dir, "/refs"); read_loose_refs(&temp_dir, temp_dir_len + 1, &tail); strbuf_setlen(&temp_dir, temp_dir_len); tail = &dummy; strbuf_addstr(&temp_dir, "/packed-refs"); insert_packed_refs(temp_dir.buf, &tail); strbuf_setlen(&temp_dir, temp_dir_len); if (remove_dir_recursively(&temp_dir, 0)) warning ("Error removing temporary directory %s.", temp_dir.buf); strbuf_release(&buf); strbuf_release(&temp_dir); return dummy.next; }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i, newfd; const char **pathspec; char *seen; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); /* * Drop trailing directory separators from directories so we'll find * submodules in the index. */ for (i = 0; i < argc; i++) { size_t pathlen = strlen(argv[i]); if (pathlen && is_dir_sep(argv[i][pathlen - 1]) && is_directory(argv[i])) { do { pathlen--; } while (pathlen && is_dir_sep(argv[i][pathlen - 1])); argv[i] = xmemdupz(argv[i], pathlen); } } pathspec = get_pathspec(prefix, argv); refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL); seen = NULL; for (i = 0; pathspec[i] ; i++) /* nothing */; seen = xcalloc(i, 1); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) continue; ALLOC_GROW(list.entry, list.nr + 1, list.alloc); list.entry[list.nr].name = ce->name; list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode); } if (pathspec) { const char *match; int seen_any = 0; for (i = 0; (match = pathspec[i]) != NULL ; i++) { if (!seen[i]) { if (!ignore_unmatch) { die(_("pathspec '%s' did not match any files"), match); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die(_("not removing '%s' recursively without -r"), *match ? match : "."); } if (! seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } else if (!index_only) { if (check_submodules_use_gitfiles()) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die(_("git rm: unable to remove %s"), path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0; for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { if (is_empty_dir(path)) { if (!rmdir(path)) { removed = 1; continue; } } else { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, path); if (!remove_dir_recursively(&buf, 0)) { removed = 1; strbuf_release(&buf); continue; } strbuf_release(&buf); /* Fallthrough and let remove_path() fail. */ } } if (!remove_path(path)) { removed = 1; continue; } if (!removed) die_errno("git rm: '%s'", path); } } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die(_("Unable to write new index file")); } return 0; }
int cmd_clean(int argc, const char **argv, const char *prefix) { int i; int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0; int ignored_only = 0, baselen = 0, config_set = 0, errors = 0; int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT; struct strbuf directory = STRBUF_INIT; struct dir_struct dir; static const char **pathspec; struct strbuf buf = STRBUF_INIT; struct string_list exclude_list = STRING_LIST_INIT_NODUP; const char *qname; char *seen = NULL; struct option options[] = { OPT__QUIET(&quiet), OPT__DRY_RUN(&show_only), OPT_BOOLEAN('f', "force", &force, "force"), OPT_BOOLEAN('d', NULL, &remove_directories, "remove whole directories"), { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern", "exclude <pattern>", PARSE_OPT_NONEG, exclude_cb }, OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"), OPT_BOOLEAN('X', NULL, &ignored_only, "remove only ignored files"), OPT_END() }; git_config(git_clean_config, NULL); if (force < 0) force = 0; else config_set = 1; argc = parse_options(argc, argv, prefix, options, builtin_clean_usage, 0); memset(&dir, 0, sizeof(dir)); if (ignored_only) dir.flags |= DIR_SHOW_IGNORED; if (ignored && ignored_only) die("-x and -X cannot be used together"); if (!show_only && !force) die("clean.requireForce %s to true and neither -n nor -f given; " "refusing to clean", config_set ? "set" : "defaults"); if (force > 1) rm_flags = 0; dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; if (read_cache() < 0) die("index file corrupt"); if (!ignored) setup_standard_excludes(&dir); for (i = 0; i < exclude_list.nr; i++) add_exclude(exclude_list.items[i].string, "", 0, dir.exclude_list); pathspec = get_pathspec(prefix, argv); fill_directory(&dir, pathspec); if (pathspec) seen = xmalloc(argc > 0 ? argc : 1); for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; int len, pos; int matches = 0; struct cache_entry *ce; struct stat st; /* * Remove the '/' at the end that directory * walking adds for directory entries. */ len = ent->len; if (len && ent->name[len-1] == '/') len--; pos = cache_name_pos(ent->name, len); if (0 <= pos) continue; /* exact match */ pos = -pos - 1; if (pos < active_nr) { ce = active_cache[pos]; if (ce_namelen(ce) == len && !memcmp(ce->name, ent->name, len)) continue; /* Yup, this one exists unmerged */ } /* * we might have removed this as part of earlier * recursive directory removal, so lstat() here could * fail with ENOENT. */ if (lstat(ent->name, &st)) continue; if (pathspec) { memset(seen, 0, argc > 0 ? argc : 1); matches = match_pathspec(pathspec, ent->name, len, baselen, seen); } if (S_ISDIR(st.st_mode)) { strbuf_addstr(&directory, ent->name); qname = quote_path_relative(directory.buf, directory.len, &buf, prefix); if (show_only && (remove_directories || (matches == MATCHED_EXACTLY))) { printf("Would remove %s\n", qname); } else if (remove_directories || (matches == MATCHED_EXACTLY)) { if (!quiet) printf("Removing %s\n", qname); if (remove_dir_recursively(&directory, rm_flags) != 0) { warning("failed to remove '%s'", qname); errors++; } } else if (show_only) { printf("Would not remove %s\n", qname); } else { printf("Not removing %s\n", qname); } strbuf_reset(&directory); } else { if (pathspec && !matches) continue; qname = quote_path_relative(ent->name, -1, &buf, prefix); if (show_only) { printf("Would remove %s\n", qname); continue; } else if (!quiet) { printf("Removing %s\n", qname); } if (unlink(ent->name) != 0) { warning("failed to remove '%s'", qname); errors++; } } } free(seen); strbuf_release(&directory); string_list_clear(&exclude_list, 0); return (errors != 0); }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i; struct pathspec pathspec; char *seen; gitmodules_config(); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD | PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, prefix, argv); refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL); seen = xcalloc(pathspec.nr, 1); for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; if (!ce_path_match(ce, &pathspec, seen)) continue; ALLOC_GROW(list.entry, list.nr + 1, list.alloc); list.entry[list.nr].name = xstrdup(ce->name); list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode); if (list.entry[list.nr++].is_submodule && !is_staging_gitmodules_ok()) die (_("Please stage your changes to .gitmodules or stash them to proceed")); } if (pathspec.nr) { const char *original; int seen_any = 0; for (i = 0; i < pathspec.nr; i++) { original = pathspec.items[i].original; if (!seen[i]) { if (!ignore_unmatch) { die(_("pathspec '%s' did not match any files"), original); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die(_("not removing '%s' recursively without -r"), *original ? original : "."); } if (!seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } else if (!index_only) { if (check_submodules_use_gitfiles()) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die(_("git rm: unable to remove %s"), path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0, gitmodules_modified = 0; for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { if (is_empty_dir(path)) { if (!rmdir(path)) { removed = 1; if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; continue; } } else { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, path); if (!remove_dir_recursively(&buf, 0)) { removed = 1; if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; strbuf_release(&buf); continue; } else if (!file_exists(path)) /* Submodule was removed by user */ if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; strbuf_release(&buf); /* Fallthrough and let remove_path() fail. */ } } if (!remove_path(path)) { removed = 1; continue; } if (!removed) die_errno("git rm: '%s'", path); } if (gitmodules_modified) stage_updated_gitmodules(); } if (active_cache_changed) { if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("Unable to write new index file")); } return 0; }