static int read_loose_refs(struct strbuf *path, int name_offset, struct ref **tail) { DIR *dir = opendir(path->buf); struct dirent *de; struct { char **entries; int nr, alloc; } list; int i, pathlen; if (!dir) return -1; memset (&list, 0, sizeof(list)); while ((de = readdir(dir))) { if (is_dot_or_dotdot(de->d_name)) continue; ALLOC_GROW(list.entries, list.nr + 1, list.alloc); list.entries[list.nr++] = xstrdup(de->d_name); } closedir(dir); /* sort the list */ qsort(list.entries, list.nr, sizeof(char *), str_cmp); pathlen = path->len; strbuf_addch(path, '/'); for (i = 0; i < list.nr; i++, strbuf_setlen(path, pathlen + 1)) { strbuf_addstr(path, list.entries[i]); if (read_loose_refs(path, name_offset, tail)) { int fd = open(path->buf, O_RDONLY); char buffer[40]; struct ref *next; if (fd < 0) continue; next = alloc_ref(path->buf + name_offset); if (read_in_full(fd, buffer, 40) != 40 || get_sha1_hex(buffer, next->old_sha1)) { close(fd); free(next); continue; } close(fd); (*tail)->next = next; *tail = next; } } strbuf_setlen(path, pathlen); for (i = 0; i < list.nr; i++) free(list.entries[i]); free(list.entries); return 0; }
static void prune_worktrees(void) { struct strbuf reason = STRBUF_INIT; struct strbuf path = STRBUF_INIT; DIR *dir = opendir(git_path("worktrees")); struct dirent *d; int ret; if (!dir) return; while ((d = readdir(dir)) != NULL) { if (is_dot_or_dotdot(d->d_name)) continue; strbuf_reset(&reason); if (!prune_worktree(d->d_name, &reason)) continue; if (show_only || verbose) printf("%s\n", reason.buf); if (show_only) continue; git_path_buf(&path, "worktrees/%s", d->d_name); ret = remove_dir_recursively(&path, 0); if (ret < 0 && errno == ENOTDIR) ret = unlink(path.buf); if (ret) error_errno(_("failed to remove '%s'"), path.buf); } closedir(dir); if (!show_only) rmdir(git_path("worktrees")); strbuf_release(&reason); strbuf_release(&path); }
int dirlist(char *pathname) { DIR *dirp; struct dirent *dt; char *currentpath; long max_pathname, namelen, orig_offset; int olderrno; dirp = opendir(pathname); if (dirp == NULL) { perror(":: opendir "); return RET_ERROR; } max_pathname = dirent_buf_size(dirp); namelen = strlen(pathname) + max_pathname + 1; currentpath = malloc(namelen); if (currentpath == NULL) { perror(":: malloc "); closedir(dirp); return RET_ERROR; } memset(currentpath, 0, namelen); orig_offset = sprintf(currentpath, "%s/", pathname); for (;;) { olderrno = errno; dt = readdir(dirp); if (dt == NULL) { /* error detected when errno changed with readdir return NULL. */ if (errno != olderrno) perror(":: readdir "); /* else, end of stream reached */ break; } /* hide . & .. */ if (is_dot_or_dotdot(dt->d_name)) continue; sprintf(currentpath + orig_offset, "%s", dt->d_name); printf("%s\n", currentpath); #ifdef DIRLIST_RECURSIVE if (is_directory(currentpath)) dirlist(currentpath); #endif } free(currentpath); closedir(dirp); return RET_OKAY; }
static void garbage_collect(struct string_list *rr) { struct string_list to_remove = { NULL, 0, 0, 1 }; DIR *dir; struct dirent *e; int i, cutoff; time_t now = time(NULL), then; git_config(git_rerere_gc_config, NULL); dir = opendir(git_path("rr-cache")); while ((e = readdir(dir))) { if (is_dot_or_dotdot(e->d_name)) continue; then = rerere_created_at(e->d_name); if (!then) continue; cutoff = (has_resolution(e->d_name) ? cutoff_resolve : cutoff_noresolve); if (then < now - cutoff * 86400) string_list_append(e->d_name, &to_remove); } for (i = 0; i < to_remove.nr; i++) unlink_rr_item(to_remove.items[i].string); string_list_clear(&to_remove, 0); }
/* Recurse over all holding directories in a holding disk. * * Call per_dir_fn for each dir, and so on, stopping at the level given by * stop_at. * * datap is passed, unchanged, to all holding_walk_fns. * * @param hdisk: holding disk to examine (fully qualified path) * @param datap: generic user-data pointer * @param stop_at: do not proceed beyond this level of the hierarchy * @param per_dir_fn: function to call for each holding dir * @param per_file_fn: function to call for each holding file * @param per_chunk_fn: function to call for each holding chunk */ static void holding_walk_disk( char *hdisk, gpointer datap, stop_at_t stop_at, holding_walk_fn per_dir_fn, holding_walk_fn per_file_fn, holding_walk_fn per_chunk_fn) { DIR *dir; struct dirent *workdir; char *hdir = NULL; int proceed = 1; if ((dir = opendir(hdisk)) == NULL) { if (errno != ENOENT) dbprintf(_("Warning: could not open holding disk %s: %s\n"), hdisk, strerror(errno)); return; } while ((workdir = readdir(dir)) != NULL) { int is_cruft = 0; if (is_dot_or_dotdot(workdir->d_name)) continue; /* expected cruft */ g_free(hdir); hdir = g_strconcat(hdisk, "/", workdir->d_name, NULL); /* detect cruft */ if (!is_dir(hdir)) { is_cruft = 1; } else if (!is_datestr(workdir->d_name)) { /* EXT2/3 leave these in the root of each volume */ if (g_str_equal(workdir->d_name, "lost+found")) continue; /* expected cruft */ else is_cruft = 1; /* unexpected */ } if (per_dir_fn) proceed = per_dir_fn(datap, hdisk, workdir->d_name, hdir, is_cruft); if (!is_cruft && proceed && stop_at != STOP_AT_DIR) holding_walk_dir(hdir, datap, stop_at, per_file_fn, per_chunk_fn); } closedir(dir); amfree(hdir); }
/* scandir (optional, sort) files under directory "pathname" */ int _scandir(char *pathname) { DIR *dirp; struct dirent **namelist; char *currentpath; long max_pathname, namelen, orig_offset; int count; dirp = opendir(pathname); if (dirp == NULL) { perror(":: opendir "); return RET_ERROR; } max_pathname = dirent_buf_size(dirp); namelen = strlen(pathname) + max_pathname + 1; currentpath = malloc(namelen); if (currentpath == NULL) { perror(":: malloc "); closedir(dirp); return RET_ERROR; } memset(currentpath, 0, namelen); orig_offset = sprintf(currentpath, "%s/", pathname); // count = scandir(currentpath, &namelist, NULL, alphasort); count = scandir(currentpath, &namelist, NULL, NULL); if (count == -1) perror(":: scandir "); else { while (count--) { if (is_dot_or_dotdot(namelist[count]->d_name)) { continue; free(namelist[count]); } sprintf(currentpath + orig_offset, "%s", namelist[count]->d_name); printf("%s\n", currentpath); free(namelist[count]); #ifdef DIRLIST_RECURSIVE if (is_directory(currentpath)) _scandir(currentpath); #endif } free(namelist); } closedir(dirp); free(currentpath); return RET_OKAY; }
/* reentrant version */ int dirlist_r(char *pathname) { DIR *dirp; struct dirent *dt, *entry; long max_pathname, namelen, orig_offset; char *currentpath; dirp = opendir(pathname); if (dirp == NULL) { perror(":: opendir "); return RET_ERROR; } max_pathname = dirent_buf_size(dirp); entry = malloc(max_pathname); if (entry == NULL) { perror(":: malloc "); closedir(dirp); return RET_ERROR; } namelen = strlen(pathname) + max_pathname + 1; currentpath = malloc(namelen); if (currentpath == NULL) { perror(":: malloc "); free(entry); closedir(dirp); return RET_ERROR; } memset(currentpath, 0, namelen); orig_offset = sprintf(currentpath, "%s/", pathname); while ((readdir_r(dirp, entry, &dt) == 0) && (dt != NULL)) { /* hide . & .. */ if (is_dot_or_dotdot(dt->d_name)) continue; sprintf(currentpath + orig_offset, "%s", dt->d_name); printf("%s\n", currentpath); #ifdef DIRLIST_RECURSIVE if (is_directory(currentpath)) dirlist_r(currentpath); #endif } free(entry); free(currentpath); closedir(dirp); return RET_OKAY; }
static void count_objects(DIR *d, char *path, int len, int verbose, unsigned long *loose, unsigned long *loose_size, unsigned long *packed_loose, unsigned long *garbage) { struct dirent *ent; while ((ent = readdir(d)) != NULL) { char hex[41]; unsigned char sha1[20]; const char *cp; int bad = 0; if (is_dot_or_dotdot(ent->d_name)) continue; for (cp = ent->d_name; *cp; cp++) { int ch = *cp; if (('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f')) continue; bad = 1; break; } if (cp - ent->d_name != 38) bad = 1; else { struct stat st; memcpy(path + len + 3, ent->d_name, 38); path[len + 2] = '/'; path[len + 41] = 0; if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else (*loose_size) += xsize_t(on_disk_bytes(st)); } if (bad) { if (verbose) { error("garbage found: %.*s/%s", len + 2, path, ent->d_name); (*garbage)++; } continue; } (*loose)++; if (!verbose) continue; memcpy(hex, path+len, 2); memcpy(hex+2, ent->d_name, 38); hex[40] = 0; if (get_sha1_hex(hex, sha1)) die("internal error"); if (has_sha1_pack(sha1)) (*packed_loose)++; } }
int git_path_direach( git_buf *path, int (*fn)(void *, git_buf *), void *arg) { ssize_t wd_len; DIR *dir; struct dirent *de, *de_buf; if (git_path_to_dir(path) < 0) return -1; wd_len = git_buf_len(path); if ((dir = opendir(path->ptr)) == NULL) { giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr); return -1; } #ifdef __sun de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); #endif while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) continue; if (git_buf_puts(path, de->d_name) < 0) { closedir(dir); git__free(de_buf); return -1; } result = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ if (result < 0) { closedir(dir); git__free(de_buf); return -1; } } closedir(dir); git__free(de_buf); return 0; }
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; }
// read dirent* read() { dirent* buf; if (! good() ) return 0; do { buf = readdir(dir); f_eof = (buf == 0); } while ( good() && is_dot_or_dotdot(&(buf->d_name[0])) ); return buf; }
int git_futils_direach( char *path, size_t path_sz, int (*fn)(void *, char *), void *arg) { size_t wd_len = strlen(path); DIR *dir; struct dirent *de; if (!wd_len || path_sz < wd_len + 2) return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path); while (path[wd_len - 1] == '/') wd_len--; path[wd_len++] = '/'; path[wd_len] = '\0'; dir = opendir(path); if (!dir) return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path); while ((de = readdir(dir)) != NULL) { size_t de_len; int result; if (is_dot_or_dotdot(de->d_name)) continue; de_len = strlen(de->d_name); if (path_sz < wd_len + de_len + 1) { closedir(dir); return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path); } strcpy(path + wd_len, de->d_name); result = fn(arg, path); if (result < GIT_SUCCESS) { closedir(dir); return result; /* The callee is reponsible for setting the correct error message */ } if (result > 0) { closedir(dir); return result; } } closedir(dir); return GIT_SUCCESS; }
void rerere_gc(struct string_list *rr) { struct string_list to_remove = STRING_LIST_INIT_DUP; DIR *dir; struct dirent *e; int i; timestamp_t now = time(NULL); timestamp_t cutoff_noresolve = now - 15 * 86400; timestamp_t cutoff_resolve = now - 60 * 86400; if (setup_rerere(rr, 0) < 0) return; git_config_get_expiry_in_days("gc.rerereresolved", &cutoff_resolve, now); git_config_get_expiry_in_days("gc.rerereunresolved", &cutoff_noresolve, now); git_config(git_default_config, NULL); dir = opendir(git_path("rr-cache")); if (!dir) die_errno(_("unable to open rr-cache directory")); /* Collect stale conflict IDs ... */ while ((e = readdir(dir))) { struct rerere_dir *rr_dir; struct rerere_id id; int now_empty; if (is_dot_or_dotdot(e->d_name)) continue; rr_dir = find_rerere_dir(e->d_name); if (!rr_dir) continue; /* or should we remove e->d_name? */ now_empty = 1; for (id.variant = 0, id.collection = rr_dir; id.variant < id.collection->status_nr; id.variant++) { prune_one(&id, cutoff_resolve, cutoff_noresolve); if (id.collection->status[id.variant]) now_empty = 0; } if (now_empty) string_list_append(&to_remove, e->d_name); } closedir(dir); /* ... and then remove the empty directories */ for (i = 0; i < to_remove.nr; i++) rmdir(git_path("rr-cache/%s", to_remove.items[i].string)); string_list_clear(&to_remove, 0); rollback_lock_file(&write_lock); }
int remove_any_file (const char *path, int recurse) { struct L_STAT stat_buffer; if (L_LSTAT (path, &stat_buffer) < 0) return 0; if (S_ISDIR (stat_buffer.st_mode)) if (recurse) { DIR *dirp = opendir (path); struct dirent *dp; if (dirp == NULL) return 0; while (dp = readdir (dirp), dp && !is_dot_or_dotdot (dp->d_name)) { char *path_buffer = new_name (path, dp->d_name); if (!remove_any_file (path_buffer, 1)) { int saved_errno = errno; free (path_buffer); closedir (dirp); errno = saved_errno; /* FIXME: errno should be read-only */ return 0; } free (path_buffer); } closedir (dirp); return rmdir (path) >= 0; } else { /* FIXME: Saving errno might not be needed anymore, now that extract_archive tests for the special case before recovery. */ int saved_errno = errno; if (rmdir (path) >= 0) return 1; errno = saved_errno; /* FIXME: errno should be read-only */ return 0; } return unlink (path) >= 0; }
int submodule_uses_worktrees(const char *path) { char *submodule_gitdir; struct strbuf sb = STRBUF_INIT; DIR *dir; struct dirent *d; int ret = 0; struct repository_format format; submodule_gitdir = git_pathdup_submodule(path, "%s", ""); if (!submodule_gitdir) return 0; /* The env would be set for the superproject. */ get_common_dir_noenv(&sb, submodule_gitdir); free(submodule_gitdir); /* * The check below is only known to be good for repository format * version 0 at the time of writing this code. */ strbuf_addstr(&sb, "/config"); read_repository_format(&format, sb.buf); if (format.version != 0) { strbuf_release(&sb); return 1; } /* Replace config by worktrees. */ strbuf_setlen(&sb, sb.len - strlen("config")); strbuf_addstr(&sb, "worktrees"); /* See if there is any file inside the worktrees directory. */ dir = opendir(sb.buf); strbuf_release(&sb); if (!dir) return 0; while ((d = readdir(dir)) != NULL) { if (is_dot_or_dotdot(d->d_name)) continue; ret = 1; break; } closedir(dir); return ret; }
static int read_directory_contents(const char *path, struct string_list *list) { DIR *dir; struct dirent *e; if (!(dir = opendir(path))) return error("Could not open directory %s", path); while ((e = readdir(dir))) if (!is_dot_or_dotdot(e->d_name)) string_list_insert(list, e->d_name); closedir(dir); return 0; }
static int prune_dir(int i, struct strbuf *path) { size_t baselen = path->len; DIR *dir = opendir(path->buf); struct dirent *de; if (!dir) return 0; while ((de = readdir(dir)) != NULL) { char name[100]; unsigned char sha1[20]; if (is_dot_or_dotdot(de->d_name)) continue; if (strlen(de->d_name) == 38) { sprintf(name, "%02x", i); memcpy(name+2, de->d_name, 39); if (get_sha1_hex(name, sha1) < 0) break; /* * Do we know about this object? * It must have been reachable */ if (lookup_object(sha1)) continue; strbuf_addf(path, "/%s", de->d_name); prune_object(path->buf, sha1); strbuf_setlen(path, baselen); continue; } if (starts_with(de->d_name, "tmp_obj_")) { strbuf_addf(path, "/%s", de->d_name); prune_tmp_file(path->buf); strbuf_setlen(path, baselen); continue; } fprintf(stderr, "bad sha1 file: %s/%s\n", path->buf, de->d_name); } closedir(dir); if (!show_only) rmdir(path->buf); return 0; }
int is_empty_dir(const char *path) { DIR *dir = opendir(path); struct dirent *e; int ret = 1; if (!dir) return 0; while ((e = readdir(dir)) != NULL) if (!is_dot_or_dotdot(e->d_name)) { ret = 0; break; } closedir(dir); return ret; }
static enum path_treatment treat_path(struct dir_struct *dir, struct dirent *de, struct strbuf *path, int baselen, const struct path_simplify *simplify) { int dtype; if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_none; strbuf_setlen(path, baselen); strbuf_addstr(path, de->d_name); if (simplify_away(path->buf, path->len, simplify)) return path_none; dtype = DTYPE(de); return treat_one_path(dir, path, simplify, dtype, de); }
void rerere_gc(struct string_list *rr) { struct string_list to_remove = STRING_LIST_INIT_DUP; DIR *dir; struct dirent *e; int i, cutoff; time_t now = time(NULL), then; int cutoff_noresolve = 15; int cutoff_resolve = 60; if (setup_rerere(rr, 0) < 0) return; git_config_get_int("gc.rerereresolved", &cutoff_resolve); git_config_get_int("gc.rerereunresolved", &cutoff_noresolve); git_config(git_default_config, NULL); dir = opendir(git_path("rr-cache")); if (!dir) die_errno("unable to open rr-cache directory"); /* Collect stale conflict IDs ... */ while ((e = readdir(dir))) { if (is_dot_or_dotdot(e->d_name)) continue; then = rerere_last_used_at(e->d_name); if (then) { cutoff = cutoff_resolve; } else { then = rerere_created_at(e->d_name); if (!then) continue; cutoff = cutoff_noresolve; } if (then < now - cutoff * 86400) string_list_append(&to_remove, e->d_name); } closedir(dir); /* ... and then remove them one-by-one */ for (i = 0; i < to_remove.nr; i++) unlink_rr_item(dirname_to_id(to_remove.items[i].string)); string_list_clear(&to_remove, 0); rollback_lock_file(&write_lock); }
static int prune_dir(int i, char *path) { DIR *dir = opendir(path); struct dirent *de; if (!dir) return 0; while ((de = readdir(dir)) != NULL) { char name[100]; unsigned char sha1[20]; if (is_dot_or_dotdot(de->d_name)) continue; if (strlen(de->d_name) == 38) { sprintf(name, "%02x", i); memcpy(name+2, de->d_name, 39); if (get_sha1_hex(name, sha1) < 0) break; /* * Do we know about this object? * It must have been reachable */ if (lookup_object(sha1)) continue; prune_object(path, de->d_name, sha1); continue; } if (!prefixcmp(de->d_name, "tmp_obj_")) { prune_tmp_object(path, de->d_name); continue; } fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); } closedir(dir); if (!show_only) rmdir(path); return 0; }
int git_path_direach( git_buf *path, int (*fn)(void *, git_buf *), void *arg) { ssize_t wd_len; DIR *dir; struct dirent *de; if (git_path_to_dir(path) < GIT_SUCCESS) return git_buf_lasterror(path); wd_len = path->size; dir = opendir(path->ptr); if (!dir) return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path->ptr); while ((de = readdir(dir)) != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) continue; if (git_buf_puts(path, de->d_name) < GIT_SUCCESS) return git_buf_lasterror(path); result = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ if (result != GIT_SUCCESS) { closedir(dir); return result; /* The callee is reponsible for setting the correct error message */ } } closedir(dir); return GIT_SUCCESS; }
int remove_dir_recursively(struct strbuf *path, int only_empty) { DIR *dir = opendir(path->buf); struct dirent *e; int ret = 0, original_len = path->len, len; if (!dir) 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, only_empty)) 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) ret = rmdir(path->buf); return ret; }
static enum path_treatment treat_path(struct dir_struct *dir, struct dirent *de, char *path, int path_max, int baselen, const struct path_simplify *simplify, int *len) { int dtype; if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_ignored; *len = strlen(de->d_name); /* Ignore overly long pathnames! */ if (*len + baselen + 8 > path_max) return path_ignored; memcpy(path + baselen, de->d_name, *len + 1); *len += baselen; if (simplify_away(path, *len, simplify)) return path_ignored; dtype = DTYPE(de); return treat_one_path(dir, path, len, simplify, dtype, de); }
static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up) { DIR *dir; struct dirent *e; int ret = 0, original_len = path->len, len, kept_down = 0; 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. */ if (kept_up) *kept_up = 1; return 0; } flag &= ~REMOVE_DIR_KEEP_TOPLEVEL; dir = opendir(path->buf); if (!dir) { /* an empty dir could be removed even if it is unreadble */ 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_recurse(path, flag, &kept_down)) 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 && !kept_down) ret = rmdir(path->buf); else if (kept_up) /* * report the uplevel that it is not an error that we * did not rmdir() our directory. */ *kept_up = !ret; return ret; }
/* Remove a directory entry. Files are removed, directories are recursively walked and removed. Return 0 on success, and -1 on falure. In practice, OpenAxiom does not remove directories with non-trivial recursive structues. */ OPENAXIOM_C_EXPORT int oa_unlink(const char* path) { const char* curdir; int status = -1; #ifdef OPENAXIOM_MS_WINDOWS_HOST WIN32_FIND_DATA findData; HANDLE walkHandle; if (is_dot_or_dotdot(path)) return -1; walkHandle = FindFirstFile(path, &findData); if (walkHandle == INVALID_HANDLE_VALUE) return -1; /* Remember where we are so we can return back properly. */ curdir = oa_getcwd(); do { if (is_dot_or_dotdot(findData.cFileName)) continue; if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ((status = oa_chdir(findData.cFileName)) < 0) goto sortie; if ((status = oa_unlink("*")) < 0) goto sortie; if ((status = oa_chdir("..")) < 0) goto sortie; if(!RemoveDirectory(findData.cFileName)) { status = -1; goto sortie; } } else if (!DeleteFile(findData.cFileName)) { status = -1; goto sortie; } status = 0; } while (FindNextFile(walkHandle, &findData)); if (!FindClose(walkHandle)) { status = -1; goto sortie; } #else struct stat pathstat; DIR* dir; struct dirent* entry; /* Don't ever try to remove `.' or `..'. */ if (is_dot_or_dotdot(path)) return -1; if (stat(path, &pathstat) < 0) return -1; /* handle non directories first. */ if (!S_ISDIR(pathstat.st_mode)) return unlink(path); /* change into the path so that we don't have to form full pathnames. */ curdir = oa_getcwd(); if ((dir = opendir(path)) == NULL || oa_chdir(path) < 0) goto sortie; while (errno = 0, (entry = readdir(dir)) != NULL) { struct stat s; if (is_dot_or_dotdot(entry->d_name)) continue; if ((status = stat(entry->d_name, &s)) < 0) goto sortie; if (S_ISDIR(s.st_mode)) { if ((status = oa_unlink(entry->d_name)) < 0) goto sortie; } else if ((status = unlink(entry->d_name)) < 0) goto sortie; } if (errno != 0) { status = -1; goto sortie; } /* Now, get one level up, and remove the empty directory. */ if (oa_chdir("..") < 0 || closedir(dir) < 0 || rmdir(path) < 0) status = -1; else status = 0; #endif /* OPENAXIOM_MS_WINDOWS_HOST */ sortie: oa_chdir(curdir); free((char*) curdir); return status; }
static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, struct index_state *index, const char *worktree, IgnoreFunc ignore_func, void *data) { char *realpath = g_build_path (PATH_SEPERATOR, worktree, base, NULL); GDir *fdir = g_dir_open (realpath, 0, NULL); const char *dname; char *nfc_dname; int contents = 0; int dtype; if (fdir) { char path[SEAF_PATH_MAX + 1]; memcpy(path, base, baselen); while ((dname = g_dir_read_name(fdir)) != NULL) { int len = 0; #ifdef __APPLE__ nfc_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC); #else nfc_dname = g_strdup(dname); #endif if (is_dot_or_dotdot(nfc_dname)) { g_free (nfc_dname); continue; } if (ignore_func (realpath, nfc_dname, data)) { g_free (nfc_dname); continue; } dtype = get_dtype(nfc_dname, realpath); switch (dtype) { case DT_REG: len = strlen(nfc_dname); memcpy(path + baselen, nfc_dname, len + 1); len = strlen(path); break; case DT_DIR: len = strlen(nfc_dname); memcpy(path + baselen, nfc_dname, len + 1); memcpy(path + baselen + len, "/", 2); len = strlen(path); read_directory_recursive(dir, path, len, 0, index, worktree, ignore_func, data); g_free (nfc_dname); continue; default: /* DT_UNKNOWN */ len = 0; break; } if(len > 0) dir_add_name(dir, path, len, index); g_free (nfc_dname); } g_dir_close(fdir); } g_free(realpath); return contents; }
void traverse_dirs( char * parent_dir, char * include) { DIR *d; struct dirent *f; struct stat finfo; char *dirname, *newname = NULL; char *newbase = NULL; dev_t parent_dev = (dev_t)0; int i; size_t l; size_t parent_len; int has_exclude; char *aparent; if(parent_dir == NULL || include == NULL) return; has_exclude = !is_empty_sl(exclude_sl) && (use_gtar_excl || use_star_excl); aparent = g_strjoin(NULL, parent_dir, "/", include, NULL); /* We (may) need root privs for the *stat() calls here. */ set_root_privs(1); if(stat(parent_dir, &finfo) != -1) parent_dev = finfo.st_dev; parent_len = strlen(parent_dir); push_name(aparent); for(; (dirname = pop_name()) != NULL; free(dirname)) { if(has_exclude && calc_check_exclude(dirname+parent_len+1)) { continue; } if((d = opendir(dirname)) == NULL) { perror(dirname); continue; } l = strlen(dirname); if(l > 0 && dirname[l - 1] != '/') { g_free(newbase); newbase = g_strconcat(dirname, "/", NULL); } else { g_free(newbase); newbase = g_strdup(dirname); } while((f = readdir(d)) != NULL) { int is_symlink = 0; int is_dir; int is_file; if(is_dot_or_dotdot(f->d_name)) { continue; } g_free(newname); newname = g_strconcat(newbase, f->d_name, NULL); if(lstat(newname, &finfo) == -1) { g_fprintf(stderr, "%s/%s: %s\n", dirname, f->d_name, strerror(errno)); continue; } if(finfo.st_dev != parent_dev) continue; #ifdef S_IFLNK is_symlink = ((finfo.st_mode & S_IFMT) == S_IFLNK); #endif is_dir = ((finfo.st_mode & S_IFMT) == S_IFDIR); is_file = ((finfo.st_mode & S_IFMT) == S_IFREG); if (!(is_file || is_dir || is_symlink)) { continue; } { int is_excluded = -1; for(i = 0; i < ndumps; i++) { add_file_name(i, newname); if(is_file && (time_t)finfo.st_ctime >= dumpdate[i]) { if(has_exclude) { if(is_excluded == -1) is_excluded = calc_check_exclude(newname+parent_len+1); if(is_excluded == 1) { i = ndumps; continue; } } add_file(i, &finfo); } } if(is_dir) { if(has_exclude && calc_check_exclude(newname+parent_len+1)) continue; push_name(newname); } } } #ifdef CLOSEDIR_VOID closedir(d); #else if(closedir(d) == -1) perror(dirname); #endif } /* drop root privs -- we're done with the permission-sensitive calls */ set_root_privs(0); amfree(newbase); amfree(newname); amfree(aparent); }
int main( int argc, char ** argv) { GList *dlist; GList *dlist1; disk_t *diskp; disklist_t diskl; size_t i; char *conf_diskfile; char *conf_tapelist; char *conf_indexdir; find_result_t *output_find; time_t tmp_time; int amtrmidx_debug = 0; config_overrides_t *cfg_ovr = NULL; gboolean compress_index; gboolean sort_index; char *lock_file; file_lock *lock_index; if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) { printf("amtrmidx-%s\n", VERSION); return (0); } /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmidx"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], VERSION); cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc > 1 && g_str_equal(argv[1], "-t")) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } set_config_overrides(cfg_ovr); config_init_with_global(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, argv[1]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); compress_index = getconf_boolean(CNF_COMPRESS_INDEX); sort_index = getconf_boolean(CNF_SORT_INDEX); output_find = find_dump(&diskl); conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR)); /* take a lock file to prevent concurent trim */ lock_file = g_strdup_printf("%s/%s", conf_indexdir, "lock"); lock_index = file_lock_new(lock_file); if (file_lock_lock_wr(lock_index) != 0) goto lock_failed; /* now go through the list of disks and find which have indexes */ time(&tmp_time); tmp_time -= 7*24*60*60; /* back one week */ for (dlist = diskl.head; dlist != NULL; dlist = dlist->next) { diskp = dlist->data; if (diskp->index) { char *indexdir, *qindexdir; DIR *d; struct dirent *f; char **names; size_t name_length; size_t name_count; char *host; char *disk, *qdisk; size_t len_date; disk_t *dp; GSList *matching_dp = NULL; /* get listing of indices, newest first */ host = sanitise_filename(diskp->host->hostname); disk = sanitise_filename(diskp->name); qdisk = quote_string(diskp->name); indexdir = g_strjoin(NULL, conf_indexdir, "/", host, "/", disk, "/", NULL); qindexdir = quote_string(indexdir); /* find all dles that use the same indexdir */ for (dlist1 = diskl.head; dlist1 != NULL; dlist1 = dlist1->next) { char *dp_host, *dp_disk; dp = dlist1->data; dp_host = sanitise_filename(dp->host->hostname); dp_disk = sanitise_filename(dp->name); if (g_str_equal(host, dp_host) && g_str_equal(disk, dp_disk)) { matching_dp = g_slist_append(matching_dp, dp); } amfree(dp_host); amfree(dp_disk); } dbprintf("%s %s -> %s\n", diskp->host->hostname, qdisk, qindexdir); amfree(qdisk); if ((d = opendir(indexdir)) == NULL) { dbprintf(_("could not open index directory %s\n"), qindexdir); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); g_slist_free(matching_dp); continue; } name_length = 100; names = (char **)g_malloc(name_length * sizeof(char *)); name_count = 0; while ((f = readdir(d)) != NULL) { size_t l; if(is_dot_or_dotdot(f->d_name)) { continue; } for(i = 0; i < sizeof("YYYYMMDDHHMMSS")-1; i++) { if(! isdigit((int)(f->d_name[i]))) { break; } } len_date = i; /* len_date=8 for YYYYMMDD */ /* len_date=14 for YYYYMMDDHHMMSS */ if((len_date != 8 && len_date != 14) || f->d_name[len_date] != '_' || ! isdigit((int)(f->d_name[len_date+1]))) { continue; /* not an index file */ } /* * Clear out old index temp files. */ l = strlen(f->d_name) - (sizeof(".tmp")-1); if ((l > (len_date + 1)) && (g_str_equal(f->d_name + l, ".tmp"))) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, f->d_name, NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); continue; } if(name_count >= name_length) { char **new_names; new_names = g_malloc((name_length * 2) * sizeof(char *)); memcpy(new_names, names, name_length * sizeof(char *)); amfree(names); names = new_names; name_length *= 2; } names[name_count++] = g_strdup(f->d_name); } closedir(d); qsort(names, name_count, sizeof(char *), sort_by_name_reversed); /* * Search for the first full dump past the minimum number * of index files to keep. */ for(i = 0; i < name_count; i++) { char *datestamp; int level; size_t len_date; int matching = 0; GSList *mdp; for(len_date = 0; len_date < sizeof("YYYYMMDDHHMMSS")-1; len_date++) { if(! isdigit((int)(names[i][len_date]))) { break; } } datestamp = g_strdup(names[i]); datestamp[len_date] = '\0'; if (sscanf(&names[i][len_date+1], "%d", &level) != 1) level = 0; for (mdp = matching_dp; mdp != NULL; mdp = mdp->next) { dp = mdp->data; if (dump_exist(output_find, dp->host->hostname, dp->name, datestamp, level)) { matching = 1; } } if (!matching) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, names[i], NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); } /* Did it require un/compression and/or sorting */ { char *orig_name = getindexfname(host, disk, datestamp, level); char *sorted_name = getindex_sorted_fname(host, disk, datestamp, level); char *sorted_gz_name = getindex_sorted_gz_fname(host, disk, datestamp, level); char *unsorted_name = getindex_unsorted_fname(host, disk, datestamp, level); char *unsorted_gz_name = getindex_unsorted_gz_fname(host, disk, datestamp, level); gboolean orig_exist = FALSE; gboolean sorted_exist = FALSE; gboolean sorted_gz_exist = FALSE; gboolean unsorted_exist = FALSE; gboolean unsorted_gz_exist = FALSE; int fd; int uncompress_err_fd = -1; int sort_err_fd = -1; int compress_err_fd = -1; pid_t uncompress_pid = -1; pid_t sort_pid = -1; pid_t compress_pid = -1; orig_exist = file_exists(orig_name); sorted_exist = file_exists(sorted_name); sorted_gz_exist = file_exists(sorted_gz_name); unsorted_exist = file_exists(unsorted_name); unsorted_gz_exist = file_exists(unsorted_gz_name); if (sort_index && compress_index) { if (!sorted_gz_exist) { if (sorted_exist) { // COMPRESS compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // SORT AND COMPRESS sort_pid = run_sort(-1, &fd, &sort_err_fd, unsorted_name, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(orig_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (sort_index && !compress_index) { if (!sorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_exist) { // SORT sort_pid = run_sort(-1, NULL, &sort_err_fd, unsorted_name, sorted_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && compress_index) { if (!sorted_gz_exist && !unsorted_gz_exist) { if (sorted_exist) { // COMPRESS sorted compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // COMPRESS unsorted compress_pid = run_compress(-1, NULL, &compress_err_fd, unsorted_name, unsorted_gz_name); unlink(unsorted_name); } else if (orig_exist) { // RENAME orig rename(orig_name, unsorted_gz_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (sorted_gz_exist && unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && !compress_index) { if (!sorted_exist && !unsorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS sorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_gz_exist) { // UNCOMPRESS unsorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, unsorted_gz_name, unsorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS orig uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, orig_name, unsorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } if (sorted_exist && unsorted_exist) { unlink(unsorted_name); } } } if (uncompress_pid != -1) wait_process(uncompress_pid, uncompress_err_fd, "uncompress"); if (sort_pid != -1) wait_process(sort_pid, sort_err_fd, "sort"); if (compress_pid != -1) wait_process(compress_pid, compress_err_fd, "compress"); g_free(orig_name); g_free(sorted_name); g_free(sorted_gz_name); g_free(unsorted_name); g_free(unsorted_gz_name); } amfree(datestamp); amfree(names[i]); } g_slist_free(matching_dp); amfree(names); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); } } file_lock_unlock(lock_index); lock_failed: file_lock_free(lock_index); amfree(conf_indexdir); amfree(lock_file); free_find_result(&output_find); clear_tapelist(); free_disklist(&diskl); unload_disklist(); dbclose(); return 0; }
/* Recurse over all holding files in a holding directory. * * Call per_file_fn for each file, and so on, stopping at the level given by * stop_at. * * datap is passed, unchanged, to all holding_walk_fns. * * @param hdir: holding directory to examine (fully qualified path) * @param datap: generic user-data pointer * @param stop_at: do not proceed beyond this level of the hierarchy * @param per_file_fn: function to call for each holding file * @param per_chunk_fn: function to call for each holding chunk */ static void holding_walk_dir( char *hdir, gpointer datap, stop_at_t stop_at, holding_walk_fn per_file_fn, holding_walk_fn per_chunk_fn) { DIR *dir; struct dirent *workdir; char *hfile = NULL; dumpfile_t dumpf; int dumpf_ok; int proceed = 1; if ((dir = opendir(hdir)) == NULL) { if (errno != ENOENT) dbprintf(_("Warning: could not open holding dir %s: %s\n"), hdir, strerror(errno)); return; } while ((workdir = readdir(dir)) != NULL) { int is_cruft = 0; if (is_dot_or_dotdot(workdir->d_name)) continue; /* expected cruft */ g_free(hfile); hfile = g_strconcat(hdir, "/", workdir->d_name, NULL); /* filter out various undesirables */ if (is_emptyfile(hfile)) is_cruft = 1; if (is_dir(hfile)) { is_cruft= 1; } if (!(dumpf_ok=holding_file_get_dumpfile(hfile, &dumpf)) || dumpf.type != F_DUMPFILE) { if (dumpf_ok && dumpf.type == F_CONT_DUMPFILE) { dumpfile_free_data(&dumpf); continue; /* silently skip expected file */ } is_cruft = 1; } if (dumpf.dumplevel < 0 || dumpf.dumplevel > 9) { is_cruft = 1; } if (per_file_fn) proceed = per_file_fn(datap, hdir, workdir->d_name, hfile, is_cruft); if (!is_cruft && proceed && stop_at != STOP_AT_FILE) holding_walk_file(hfile, datap, per_chunk_fn); dumpfile_free_data(&dumpf); } closedir(dir); amfree(hfile); }