static int recursive_remove_internal(const char *path, int missing_ok, int cwd) { DIR *dir; struct dirent *de; const char *sub_path; char *subdir; int did_chdir, rv; /* * If the argument is longer than PATH_MAX, long_remove * will try to shorten it using chdir. So before returning, * make sure to fchdir back to the original cwd. */ sub_path = path; if (long_remove(&sub_path, missing_ok, &did_chdir) == 0) rv = 0; else if (errno != ENOTEMPTY) /* Other errors are terminal. */ rv = -1; else rv = 1; if (rv != 1) { if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0) rv = -1; return rv; } if ((dir = opendir(sub_path)) == NULL) { if (errno == EMFILE) warn("opendir failed"); return -1; } if (did_chdir && fchdir(cwd) == -1) return -1; rv = 0; while ((de = readdir(dir)) != NULL) { if (strcmp(de->d_name, ".") == 0) continue; if (strcmp(de->d_name, "..") == 0) continue; subdir = xasprintf("%s/%s", path, de->d_name); rv = recursive_remove_internal(subdir, 1, cwd); free(subdir); } closedir(dir); safe_fchdir(cwd); rv |= long_remove(&path, missing_ok, &did_chdir); if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0) rv = -1; return rv; }
static void add_dir(struct sfs_fs *sfs, struct cache_inode *parent, const char *dirname, int curfd, int fd, ino_t real) { assert(search_cache_inode(sfs, real) == NULL); struct cache_inode *current = alloc_cache_inode(sfs, real, 0, SFS_TYPE_DIR); safe_fchdir(fd), subpath_push(sfs, dirname); open_dir(sfs, current, parent); safe_fchdir(curfd), subpath_pop(sfs); add_entry(sfs, parent, current, dirname); }
int create_img(struct sfs_fs *sfs, const char *home) { int curfd, homefd; if ((curfd = open(".", O_RDONLY)) < 0) { bug("get current fd failed.\n"); } if ((homefd = open(home, O_RDONLY | O_NOFOLLOW)) < 0) { bug("open home directory '%s' failed.\n", home); } safe_fchdir(homefd); open_dir(sfs, sfs->root, sfs->root); safe_fchdir(curfd); close(curfd), close(homefd); close_sfs(sfs); return 0; }