main(int argc, char** argv) { Ardir_t* dir; Ardirent_t* ent; long touch; char* file; touch = 0; while (file = *++argv) { if (!strcmp(file, "-t") && *(argv + 1)) touch = strtol(*++argv, NiL, 0); else if (dir = ardiropen(file, NiL, touch ? ARDIR_UPDATE : 0)) { sfprintf(sfstdout, "%s: type=%s truncate=%d%s\n", file, dir->meth->name, dir->truncate, (dir->flags & ARDIR_RANLIB) ? " ranlib" : ""); while (ent = ardirnext(dir)) { if (touch) { ent->mtime = touch; ardirchange(dir, ent); sfprintf(sfstdout, "touch %s\n", ent->name); } else sfprintf(sfstdout, "%s %8u %8u %8llu %8llu %s %s\n", fmtmode(ent->mode, 1), ent->uid, ent->gid, ent->size, ent->offset, fmttime("%k", ent->mtime), ent->name); } if (ardirclose(dir)) error(2, "%s: archive read error", file); } else error(ERROR_SYSTEM|2, "%s: not an archive", file); } return 0; }
static int rm(State_t* state, register FTSENT* ent) { register char* path; register int n; int v; struct stat st; if (ent->fts_info == FTS_NS || ent->fts_info == FTS_ERR || ent->fts_info == FTS_SLNONE) { if (!state->force) error(2, "%s: not found", ent->fts_path); } else if (state->fs3d && iview(ent->fts_statp)) fts_set(NiL, ent, FTS_SKIP); else switch (ent->fts_info) { case FTS_DNR: case FTS_DNX: if (state->unconditional) { if (!beenhere(ent)) break; if (!chmod(ent->fts_name, (ent->fts_statp->st_mode & S_IPERM)|S_IRWXU)) { fts_set(NiL, ent, FTS_AGAIN); break; } error_info.errors++; } else if (!state->force) error(2, "%s: cannot %s directory", ent->fts_path, (ent->fts_info & FTS_NR) ? "read" : "search"); else error_info.errors++; fts_set(NiL, ent, FTS_SKIP); nonempty(ent); break; case FTS_D: case FTS_DC: path = ent->fts_name; if (path[0] == '.' && (!path[1] || path[1] == '.' && !path[2]) && (ent->fts_level > 0 || path[1])) { fts_set(NiL, ent, FTS_SKIP); if (!state->force) error(2, "%s: cannot remove", ent->fts_path); else error_info.errors++; break; } if (!state->recursive) { fts_set(NiL, ent, FTS_SKIP); error(2, "%s: directory", ent->fts_path); break; } if (!beenhere(ent)) { if (state->unconditional && (ent->fts_statp->st_mode & S_IRWXU) != S_IRWXU) chmod(path, (ent->fts_statp->st_mode & S_IPERM)|S_IRWXU); if (ent->fts_level > 0) { char* s; if (ent->fts_accpath == ent->fts_name || !(s = strrchr(ent->fts_accpath, '/'))) v = !stat(".", &st); else { path = ent->fts_accpath; *s = 0; v = !stat(path, &st); *s = '/'; } if (v) v = st.st_nlink <= 2 || st.st_ino == ent->fts_parent->fts_statp->st_ino && st.st_dev == ent->fts_parent->fts_statp->st_dev || strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'l'); } else v = 1; if (v) { if (state->interactive) { if ((v = astquery(-1, "remove directory %s? ", ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { fts_set(NiL, ent, FTS_SKIP); nonempty(ent); } } if (ent->fts_info == FTS_D) break; } else { ent->fts_info = FTS_DC; error(1, "%s: hard link to directory", ent->fts_path); } } else if (ent->fts_info == FTS_D) break; /*FALLTHROUGH*/ case FTS_DP: if (isempty(ent) || state->directory) { path = ent->fts_name; if (path[0] != '.' || path[1]) { path = ent->fts_accpath; if (state->verbose) sfputr(sfstdout, ent->fts_path, '\n'); if ((ent->fts_info == FTS_DC || state->directory) ? remove(path) : rmdir(path)) switch (errno) { case ENOENT: break; case EEXIST: #if defined(ENOTEMPTY) && (ENOTEMPTY) != (EEXIST) case ENOTEMPTY: #endif if (ent->fts_info == FTS_DP && !beenhere(ent)) { retry(ent); fts_set(NiL, ent, FTS_AGAIN); break; } /*FALLTHROUGH*/ default: nonempty(ent); if (!state->force) error(ERROR_SYSTEM|2, "%s: directory not removed", ent->fts_path); else error_info.errors++; break; } } else if (!state->force) error(2, "%s: cannot remove", ent->fts_path); else error_info.errors++; } else { nonempty(ent); if (!state->force) error(2, "%s: directory not removed", ent->fts_path); else error_info.errors++; } break; default: path = ent->fts_accpath; if (state->verbose) sfputr(sfstdout, ent->fts_path, '\n'); if (state->interactive) { if ((v = astquery(-1, "remove %s? ", ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { nonempty(ent); break; } } else if (!state->force && state->terminal && eaccess(path, W_OK)) { if ((v = astquery(-1, "override protection %s for %s? ", #ifdef ETXTBSY errno == ETXTBSY ? "``running program''" : #endif ent->fts_statp->st_uid != state->uid ? "``not owner''" : fmtmode(ent->fts_statp->st_mode & S_IPERM, 0) + 1, ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { nonempty(ent); break; } } #if _lib_fsync if (state->clobber && S_ISREG(ent->fts_statp->st_mode) && ent->fts_statp->st_size > 0) { if ((n = open(path, O_WRONLY)) < 0) error(ERROR_SYSTEM|2, "%s: cannot clear data", ent->fts_path); else { off_t c = ent->fts_statp->st_size; for (;;) { if (write(n, state->buf, sizeof(state->buf)) != sizeof(state->buf)) { error(ERROR_SYSTEM|2, "%s: data clear error", ent->fts_path); break; } if (c <= sizeof(state->buf)) break; c -= sizeof(state->buf); } fsync(n); close(n); } } #endif if (remove(path)) { nonempty(ent); switch (errno) { case ENOENT: break; default: if (!state->force || state->interactive) error(ERROR_SYSTEM|2, "%s: not removed", ent->fts_path); else error_info.errors++; break; } } break; } return 0; }