Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { char** paths = malloc(argc * sizeof(char*)); int i; for (i = 0; i < argc; ++i) { paths[i] = Evaluate(state, argv[i]); if (paths[i] == NULL) { int j; for (j = 0; j < i; ++i) { free(paths[j]); } free(paths); return NULL; } } bool recursive = (strcmp(name, "delete_recursive") == 0); int success = 0; for (i = 0; i < argc; ++i) { if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0) ++success; free(paths[i]); } free(paths); char buffer[10]; sprintf(buffer, "%d", success); return StringValue(strdup(buffer)); }
int dirUnlinkHierarchy(const char *path) { struct stat st; DIR *dir; struct dirent *de; int fail = 0; /* is it a file or directory? */ if (lstat(path, &st) < 0) { return -1; } /* a file, so unlink it */ if (!S_ISDIR(st.st_mode)) { return unlink(path); } /* a directory, so open handle */ dir = opendir(path); if (dir == NULL) { return -1; } /* recurse over components */ errno = 0; while ((de = readdir(dir)) != NULL) { //TODO: don't blow the stack char dn[PATH_MAX]; if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { continue; } snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); if (dirUnlinkHierarchy(dn) < 0) { fail = 1; break; } errno = 0; } /* in case readdir or unlink_recursive failed */ if (fail || errno < 0) { int save = errno; closedir(dir); errno = save; return -1; } /* close directory handle */ if (closedir(dir) < 0) { return -1; } /* delete target directory */ return rmdir(path); }
/* delete <file1> [<fileN> ...] * delete_recursive <file-or-dir1> [<file-or-dirN> ...] * * Like "rm -f", will try to delete every named file/dir, even if * earlier ones fail. Recursive deletes that fail halfway through * give up early. */ static int cmd_delete(const char *name, void *cookie, int argc, const char *argv[], PermissionRequestList *permissions) { UNUSED(cookie); CHECK_WORDS(); int nerr = 0; bool recurse; if (argc < 1) { LOGE("Command %s requires at least one argument\n", name); return 1; } recurse = (strcmp(name, "delete_recursive") == 0); ui_print("Deleting files...\n"); //xxx permissions int i; for (i = 0; i < argc; i++) { const char *root_path = argv[i]; char pathbuf[PATH_MAX]; const char *path; /* This guarantees that all paths use "SYSTEM:"-style roots; * plain paths won't make it through translate_root_path(). */ path = translate_root_path(root_path, pathbuf, sizeof(pathbuf)); if (path != NULL) { int ret = ensure_root_path_mounted(root_path); if (ret < 0) { LOGW("Can't mount volume to delete \"%s\"\n", root_path); nerr++; continue; } if (recurse) { ret = dirUnlinkHierarchy(path); } else { ret = unlink(path); } if (ret != 0 && errno != ENOENT) { LOGW("Can't delete %s\n(%s)\n", path, strerror(errno)); nerr++; } } else { nerr++; } } //TODO: add a way to fail if a delete didn't work return 0; }