static void unzip_create_leading_dirs(const char *fn) { /* Create all leading directories */ char *name = xstrdup(fn); if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) { xfunc_die(); /* bb_make_directory is noisy */ } free(name); }
int mkdir_main (int argc, char **argv) { mode_t mode = (mode_t)(-1); int status = EXIT_SUCCESS; int flags = 0; unsigned long opt; char *smode; #ifdef CONFIG_SELINUX security_context_t scontext = NULL; #endif #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS bb_applet_long_options = mkdir_long_options; #endif #ifdef CONFIG_SELINUX opt = bb_getopt_ulflags(argc, argv, "m:pZ:", &smode, &scontext); #else opt = bb_getopt_ulflags(argc, argv, "m:p", &smode); #endif if(opt & 1) { mode = 0777; if (!bb_parse_mode (smode, &mode)) { bb_error_msg_and_die ("invalid mode `%s'", smode); } } if(opt & 2) flags |= FILEUTILS_RECUR; #ifdef CONFIG_SELINUX if(opt & 4) { if(!is_selinux_enabled()) { bb_error_msg_and_die ("Sorry, --context (-Z) can be used only on " "a selinux-enabled kernel.\n" ); } if (setfscreatecon(scontext)) { bb_error_msg_and_die ("Sorry, cannot set default context " "to %s.\n", scontext); } } #endif if (optind == argc) { bb_show_usage(); } argv += optind; do { if (bb_make_directory(*argv, mode, flags)) { status = EXIT_FAILURE; } } while (*++argv); return status; }
int mkdir_main(int argc UNUSED_PARAM, char **argv) { long mode = -1; int status = EXIT_SUCCESS; int flags = 0; unsigned opt; char *smode; #if ENABLE_SELINUX security_context_t scontext; #endif #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS applet_long_options = mkdir_longopts; #endif opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); if (opt & 1) { mode_t mmode = bb_parse_mode(smode, 0777); if (mmode == (mode_t)-1) { bb_error_msg_and_die("invalid mode '%s'", smode); } mode = mmode; } if (opt & 2) flags |= FILEUTILS_RECUR; if ((opt & 4) && FILEUTILS_VERBOSE) flags |= FILEUTILS_VERBOSE; #if ENABLE_SELINUX if (opt & 8) { selinux_or_die(); setfscreatecon_or_die(scontext); } #endif argv += optind; if (!argv[0]) bb_show_usage(); do { if (bb_make_directory(*argv, mode, flags)) { status = EXIT_FAILURE; } } while (*++argv); return status; }
int mkdir_main(int argc, char **argv) { mode_t mode = (mode_t)(-1); int status = EXIT_SUCCESS; int flags = 0; unsigned opt; char *smode; #if ENABLE_SELINUX security_context_t scontext; #endif #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS applet_long_options = mkdir_longopts; #endif opt = getopt32(argv, "m:p" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext)); if (opt & 1) { mode = 0777; if (!bb_parse_mode(smode, &mode)) { bb_error_msg_and_die("invalid mode '%s'", smode); } } if (opt & 2) flags |= FILEUTILS_RECUR; #if ENABLE_SELINUX if (opt & 4) { selinux_or_die(); setfscreatecon_or_die(scontext); } #endif if (optind == argc) { bb_show_usage(); } argv += optind; do { if (bb_make_directory(*argv, mode, flags)) { status = EXIT_FAILURE; } } while (*++argv); return status; }
/* Builds an alias path. * This function potentionally reallocates the alias parameter. * Only used for ENABLE_FEATURE_MDEV_RENAME */ static char *build_alias(char *alias, const char *device_name) { char *dest; /* ">bar/": rename to bar/device_name */ /* ">bar[/]baz": rename to bar[/]baz */ dest = strrchr(alias, '/'); if (dest) { /* ">bar/[baz]" ? */ *dest = '\0'; /* mkdir bar */ bb_make_directory(alias, 0755, FILEUTILS_RECUR); *dest = '/'; if (dest[1] == '\0') { /* ">bar/" => ">bar/device_name" */ dest = alias; alias = concat_path_file(alias, device_name); free(dest); } } return alias; }
int patch_main(int argc UNUSED_PARAM, char **argv) { int opts; int reverse, state = 0; char *oldname = NULL, *newname = NULL; char *opt_p, *opt_i; long oldlen = oldlen; /* for compiler */ long newlen = newlen; /* for compiler */ INIT_TT(); opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); argv += optind; reverse = opts & FLAG_REVERSE; TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! TT.filein = TT.fileout = -1; if (opts & FLAG_INPUT) { xmove_fd(xopen_stdin(opt_i), STDIN_FILENO); } else { if (argv[0] && argv[1]) { xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); } } if (argv[0]) { oldname = xstrdup(argv[0]); newname = xstrdup(argv[0]); } // Loop through the lines in the patch for(;;) { char *patchline; patchline = xmalloc_fgetline(stdin); if (!patchline) break; // Other versions of patch accept damaged patches, // so we need to also. if (!*patchline) { free(patchline); patchline = xstrdup(" "); } // Are we assembling a hunk? if (state >= 2) { if (*patchline==' ' || *patchline=='+' || *patchline=='-') { dlist_add(&TT.current_hunk, patchline); if (*patchline != '+') oldlen--; if (*patchline != '-') newlen--; // Context line? if (*patchline==' ' && state==2) TT.context++; else state=3; // If we've consumed all expected hunk lines, apply the hunk. if (!oldlen && !newlen) state = apply_one_hunk(); continue; } fail_hunk(); state = 0; continue; } // Open a new file? if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { char *s, **name = reverse ? &newname : &oldname; int i; if (*patchline == '+') { name = reverse ? &oldname : &newname; state = 1; } finish_oldfile(); if (!argv[0]) { free(*name); // Trim date from end of filename (if any). We don't care. for (s = patchline+4; *s && *s!='\t'; s++) if (*s=='\\' && s[1]) s++; i = atoi(s); if (i>1900 && i<=1970) *name = xstrdup("/dev/null"); else { *s = 0; *name = xstrdup(patchline+4); } } // We defer actually opening the file because svn produces broken // patches that don't signal they want to create a new file the // way the patch man page says, so you have to read the first hunk // and _guess_. // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ // but a missing ,value means the value is 1. } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { int i; char *s = patchline+4; // Read oldline[,oldlen] +newline[,newlen] TT.oldlen = oldlen = TT.newlen = newlen = 1; TT.oldline = strtol(s, &s, 10); if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10); TT.newline = strtol(s+2, &s, 10); if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10); if (oldlen < 1 && newlen < 1) bb_error_msg_and_die("Really? %s", patchline); TT.context = 0; state = 2; // If this is the first hunk, open the file. if (TT.filein == -1) { int oldsum, newsum, empty = 0; char *name; oldsum = TT.oldline + oldlen; newsum = TT.newline + newlen; name = reverse ? oldname : newname; // We're deleting oldname if new file is /dev/null (before -p) // or if new hunk is empty (zero context) after patching if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) { name = reverse ? newname : oldname; empty++; } // handle -p path truncation. for (i=0, s = name; *s;) { if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; if (*s++ != '/') continue; while (*s == '/') s++; i++; name = s; } if (empty) { // File is empty after the patches have been applied state = 0; if (option_mask32 & FLAG_RMEMPTY) { // If flag -E or --remove-empty-files is set printf("removing %s\n", name); xunlink(name); } else { printf("patching file %s\n", name); xclose(xopen(name, O_WRONLY | O_TRUNC)); } // If we've got a file to open, do so. } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { struct stat statbuf; // If the old file was null, we're creating a new one. if (!strcmp(oldname, "/dev/null") || !oldsum) { printf("creating %s\n", name); s = strrchr(name, '/'); if (s) { *s = 0; bb_make_directory(name, -1, FILEUTILS_RECUR); *s = '/'; } TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); } else { printf("patching file %s\n", name); TT.filein = xopen(name, O_RDONLY); } TT.tempname = xasprintf("%sXXXXXX", name); TT.fileout = xmkstemp(TT.tempname); // Set permissions of output file fstat(TT.filein, &statbuf); fchmod(TT.fileout, statbuf.st_mode); TT.linenum = 0; TT.hunknum = 0; } } TT.hunknum++; continue; } // If we didn't continue above, discard this line. free(patchline); } finish_oldfile(); if (ENABLE_FEATURE_CLEAN_UP) { free(oldname); free(newname); } return TT.exitval; }
int main(int argc, char **argv) { int opt; FILE *table = stdin; char *rootdir = NULL; char *line = NULL; int linenum = 0; int ret = EXIT_SUCCESS; bb_applet_name = basename(argv[0]); while ((opt = getopt(argc, argv, "d:")) != -1) { switch(opt) { case 'd': table = bb_xfopen((line=optarg), "r"); break; default: bb_show_usage(); } } if (optind >= argc || (rootdir=argv[optind])==NULL) { bb_error_msg_and_die("root directory not speficied"); } if (chdir(rootdir) != 0) { bb_perror_msg_and_die("Couldnt chdir to %s", rootdir); } umask(0); printf("rootdir=%s\n", rootdir); if (line) { printf("table='%s'\n", line); } else { printf("table=<stdin>\n"); } while ((line = bb_get_chomped_line_from_file(table))) { char type; unsigned int mode = 0755; unsigned int major = 0; unsigned int minor = 0; unsigned int count = 0; unsigned int increment = 0; unsigned int start = 0; char name[4096]; char user[41]; char group[41]; char *full_name; uid_t uid; gid_t gid; linenum++; if ((2 > sscanf(line, "%4095s %c %o %40s %40s %u %u %u %u %u", name, &type, &mode, user, group, &major, &minor, &start, &increment, &count)) || ((major | minor | start | count | increment) > 0xfffff)) { if (*line=='\0' || *line=='#' || isspace(*line)) continue; bb_error_msg("line %d invalid: '%s'\n", linenum, line); ret = EXIT_FAILURE; continue; } if (name[0] == '#') { continue; } if (*group) { gid = get_ug_id(group, my_getgrnam); } else { gid = getgid(); } if (*user) { uid = get_ug_id(user, my_getpwnam); } else { uid = getuid(); } full_name = concat_path_file(rootdir, name); if (type == 'd') { bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR); if (chown(full_name, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } if ((mode != -1) && (chmod(full_name, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } } else if (type == 'f') { struct stat st; if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) { bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name); ret = EXIT_FAILURE; goto loop; } if (chown(full_name, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } if ((mode != -1) && (chmod(full_name, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } } else if (type == 'r') { recursive_uid = uid; recursive_gid = gid; recursive_mode = mode; if (nftw(full_name, bb_recursive, 20, FTW_MOUNT | FTW_PHYS) < 0) { bb_perror_msg("line %d: recursive failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } } else { dev_t rdev; if (type == 'p') { mode |= S_IFIFO; } else if (type == 'c') { mode |= S_IFCHR; } else if (type == 'b') { mode |= S_IFBLK; } else { bb_error_msg("line %d: Unsupported file type %c", linenum, type); ret = EXIT_FAILURE; goto loop; } if (count > 0) { int i; char *full_name_inc; full_name_inc = xmalloc(strlen(full_name) + 8); for (i = 0; i < count; i++) { sprintf(full_name_inc, "%s%d", full_name, start + i); rdev = makedev(major, minor + i * increment); if (mknod(full_name_inc, mode, rdev) == -1) { bb_perror_msg("line %d: Couldnt create node %s", linenum, full_name_inc); ret = EXIT_FAILURE; } else if (chown(full_name_inc, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name_inc); ret = EXIT_FAILURE; } if ((mode != -1) && (chmod(full_name_inc, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name_inc); ret = EXIT_FAILURE; } } free(full_name_inc); } else { rdev = makedev(major, minor); if (mknod(full_name, mode, rdev) == -1) { bb_perror_msg("line %d: Couldnt create node %s", linenum, full_name); ret = EXIT_FAILURE; } else if (chown(full_name, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name); ret = EXIT_FAILURE; } if ((mode != -1) && (chmod(full_name, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name); ret = EXIT_FAILURE; } } } loop: free(line); free(full_name); } fclose(table); return ret; }
void data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { char *name = bb_xstrdup(file_header->name); bb_make_directory (dirname(name), -1, FILEUTILS_RECUR); free(name); } /* Check if the file already exists */ if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { /* Remove the existing entry if it exists */ if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT)) { bb_perror_msg_and_die("Couldnt remove old file"); } } else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat statbuf; if (lstat(file_header->name, &statbuf) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("Couldnt stat old file"); } } else if (statbuf.st_mtime <= file_header->mtime) { if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_error_msg("%s not created: newer or same age file exists", file_header->name); } data_skip(archive_handle); return; } else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("Couldnt remove old file %s", file_header->name); } } /* Handle hard links separately * We identified hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && (file_header->link_name) && (file_header->size == 0)) { /* hard link */ res = link(file_header->link_name, file_header->name); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("Couldnt create hard link"); } } else { /* Create the filesystem entry */ switch(file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL); bb_copyfd_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((errno != EISDIR) && (res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("extract_archive: %s", file_header->name); } break; case S_IFLNK: /* Symlink */ res = symlink(file_header->link_name, file_header->name); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("Cannot create node %s", file_header->name); } break; default: bb_error_msg_and_die("Unrecognised file type"); } } if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) { lchown(file_header->name, file_header->uid, file_header->gid); } if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM) && (file_header->mode & S_IFMT) != S_IFLNK) { chmod(file_header->name, file_header->mode); } if (archive_handle->flags & ARCHIVE_PRESERVE_DATE && !S_ISLNK(file_header->mode)) { struct utimbuf t; t.actime = t.modtime = file_header->mtime; utime(file_header->name, &t); } }
int cp_main(int argc, char **argv) { struct stat source_stat; struct stat dest_stat; const char *last; const char *dest; int s_flags; int d_flags; int flags; int status; enum { OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1), OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)), OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1), OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2), #if ENABLE_FEATURE_CP_LONG_OPTIONS OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3), #endif }; // Need at least two arguments // Soft- and hardlinking doesn't mix // -P and -d are the same (-P is POSIX, -d is GNU) // -r and -R are the same // -R (and therefore -r) turns on -d (coreutils does this) // -a = -pdR opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR"; #if ENABLE_FEATURE_CP_LONG_OPTIONS applet_long_options = "archive\0" No_argument "a" "force\0" No_argument "f" "interactive\0" No_argument "i" "link\0" No_argument "l" "dereference\0" No_argument "L" "no-dereference\0" No_argument "P" "recursive\0" No_argument "R" "symbolic-link\0" No_argument "s" "verbose\0" No_argument "v" "parents\0" No_argument "\xff" ; #endif flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPv"); /* Options of cp from GNU coreutils 6.10: * -a, --archive * -f, --force * -i, --interactive * -l, --link * -L, --dereference * -P, --no-dereference * -R, -r, --recursive * -s, --symbolic-link * -v, --verbose * -H follow command-line symbolic links in SOURCE * -d same as --no-dereference --preserve=links * -p same as --preserve=mode,ownership,timestamps * -c same as --preserve=context * --parents * use full source file name under DIRECTORY * NOT SUPPORTED IN BBOX: * --backup[=CONTROL] * make a backup of each existing destination file * -b like --backup but does not accept an argument * --copy-contents * copy contents of special files when recursive * --preserve[=ATTR_LIST] * preserve attributes (default: mode,ownership,timestamps), * if possible additional attributes: security context,links,all * --no-preserve=ATTR_LIST * --remove-destination * remove each existing destination file before attempting to open * --sparse=WHEN * control creation of sparse files * --strip-trailing-slashes * remove any trailing slashes from each SOURCE argument * -S, --suffix=SUFFIX * override the usual backup suffix * -t, --target-directory=DIRECTORY * copy all SOURCE arguments into DIRECTORY * -T, --no-target-directory * treat DEST as a normal file * -u, --update * copy only when the SOURCE file is newer than the destination * file or when the destination file is missing * -x, --one-file-system * stay on this file system * -Z, --context=CONTEXT * (SELinux) set SELinux security context of copy to CONTEXT */ argc -= optind; argv += optind; /* Reverse this bit. If there is -d, bit is not set: */ flags ^= FILEUTILS_DEREFERENCE; /* coreutils 6.9 compat: * by default, "cp" derefs symlinks (creates regular dest files), * but "cp -R" does not. We switch off deref if -r or -R (see above). * However, "cp -RL" must still deref symlinks: */ if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */ flags |= FILEUTILS_DEREFERENCE; #if ENABLE_SELINUX if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) { selinux_or_die(); } #endif status = EXIT_SUCCESS; last = argv[argc - 1]; /* If there are only two arguments and... */ if (argc == 2) { s_flags = cp_mv_stat2(*argv, &source_stat, (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); if (s_flags < 0) return EXIT_FAILURE; d_flags = cp_mv_stat(last, &dest_stat); if (d_flags < 0) return EXIT_FAILURE; #if ENABLE_FEATURE_CP_LONG_OPTIONS if (flags & OPT_parents) { if (!(d_flags & 2)) { bb_error_msg_and_die("with --parents, the destination must be a directory"); } } #endif /* ...if neither is a directory... */ if (!((s_flags | d_flags) & 2) /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */ || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) ) { /* Do a simple copy */ dest = last; goto DO_COPY; /* NB: argc==2 -> *++argv==last */ } } while (1) { #if ENABLE_FEATURE_CP_LONG_OPTIONS if (flags & OPT_parents) { char *dest_dup; char *dest_dir; dest = concat_path_file(last, *argv); dest_dup = xstrdup(dest); dest_dir = dirname(dest_dup); if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) { return EXIT_FAILURE; } free(dest_dup); goto DO_COPY; } #endif dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); DO_COPY: if (copy_file(*argv, dest, flags) < 0) { status = EXIT_FAILURE; } if (*++argv == last) { /* possibly leaking dest... */ break; } /* don't move up: dest may be == last and not malloced! */ free((void*)dest); } /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */ return status; }
int makedevs_main(int argc, char **argv) { FILE *table = stdin; char *rootdir = NULL; char *line = NULL; int linenum = 0; int ret = EXIT_SUCCESS; unsigned long flags; flags = bb_getopt_ulflags(argc, argv, "d:", &line); if (line) table = bb_xfopen(line, "r"); if (optind >= argc || (rootdir=argv[optind])==NULL) { bb_error_msg_and_die("root directory not specified"); } bb_xchdir(rootdir); umask(0); printf("rootdir=%s\n", rootdir); if (line) { printf("table='%s'\n", line); } else { printf("table=<stdin>\n"); } while ((line = bb_get_chomped_line_from_file(table))) { char type; unsigned int mode = 0755; unsigned int major = 0; unsigned int minor = 0; unsigned int count = 0; unsigned int increment = 0; unsigned int start = 0; char name[41]; char user[41]; char group[41]; char *full_name; uid_t uid; gid_t gid; linenum++; if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name, &type, &mode, user, group, &major, &minor, &start, &increment, &count)) || ((major | minor | start | count | increment) > 255)) { if (*line=='\0' || *line=='#' || isspace(*line)) continue; bb_error_msg("line %d invalid: '%s'\n", linenum, line); ret = EXIT_FAILURE; continue; } if (name[0] == '#') { continue; } gid = (*group) ? get_ug_id(group, bb_xgetgrnam) : getgid(); uid = (*user) ? get_ug_id(user, bb_xgetpwnam) : getuid(); full_name = concat_path_file(rootdir, name); if (type == 'd') { bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR); if (chown(full_name, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } if ((mode != -1) && (chmod(full_name, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } } else if (type == 'f') { struct stat st; if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) { bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name); ret = EXIT_FAILURE; goto loop; } if (chown(full_name, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } if ((mode != -1) && (chmod(full_name, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name); ret = EXIT_FAILURE; goto loop; } } else { dev_t rdev; if (type == 'p') { mode |= S_IFIFO; } else if (type == 'c') { mode |= S_IFCHR; } else if (type == 'b') { mode |= S_IFBLK; } else { bb_error_msg("line %d: unsupported file type %c", linenum, type); ret = EXIT_FAILURE; goto loop; } if (count > 0) { int i; char *full_name_inc; full_name_inc = xmalloc(strlen(full_name) + 4); for (i = start; i < count; i++) { sprintf(full_name_inc, "%s%d", full_name, i); rdev = (major << 8) + minor + (i * increment - start); if (mknod(full_name_inc, mode, rdev) == -1) { bb_perror_msg("line %d: could not create node %s", linenum, full_name_inc); ret = EXIT_FAILURE; } else if (chown(full_name_inc, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name_inc); ret = EXIT_FAILURE; } if ((mode != -1) && (chmod(full_name_inc, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name_inc); ret = EXIT_FAILURE; } } free(full_name_inc); } else { rdev = (major << 8) + minor; if (mknod(full_name, mode, rdev) == -1) { bb_perror_msg("line %d: could not create node %s", linenum, full_name); ret = EXIT_FAILURE; } else if (chown(full_name, uid, gid) == -1) { bb_perror_msg("line %d: chown failed for %s", linenum, full_name); ret = EXIT_FAILURE; } if ((mode != -1) && (chmod(full_name, mode) < 0)){ bb_perror_msg("line %d: chmod failed for %s", linenum, full_name); ret = EXIT_FAILURE; } } } loop: free(line); free(full_name); } fclose(table); return ret; }
int file_mkdir_hier(const char *path, long mode) { return bb_make_directory((char *)path, mode, FILEUTILS_RECUR); }
int patch_main(int argc, char **argv) { int patch_level = -1; char *patch_line; int ret; FILE *patch_file = NULL; { char *p, *i; ret = getopt32(argv, "p:i:", &p, &i); if (ret & 1) patch_level = xatol_range(p, -1, USHRT_MAX); if (ret & 2) { patch_file = xfopen(i, "r"); } else { patch_file = stdin; } ret = 0; } patch_line = xmalloc_getline(patch_file); while (patch_line) { FILE *src_stream; FILE *dst_stream; char *original_filename; char *new_filename; char *backup_filename; unsigned int src_cur_line = 1; unsigned int dest_cur_line = 0; unsigned int dest_beg_line; unsigned int bad_hunk_count = 0; unsigned int hunk_count = 0; char copy_trailing_lines_flag = 0; /* Skip everything upto the "---" marker * No need to parse the lines "Only in <dir>", and "diff <args>" */ while (patch_line && strncmp(patch_line, "--- ", 4) != 0) { free(patch_line); patch_line = xmalloc_getline(patch_file); } /* FIXME: patch_line NULL check?? */ /* Extract the filename used before the patch was generated */ original_filename = extract_filename(patch_line, patch_level); free(patch_line); patch_line = xmalloc_getline(patch_file); /* FIXME: NULL check?? */ if (strncmp(patch_line, "+++ ", 4) != 0) { ret = 2; bb_error_msg("invalid patch"); continue; } new_filename = extract_filename(patch_line, patch_level); free(patch_line); if (file_doesnt_exist(new_filename)) { char *line_ptr; /* Create leading directories */ line_ptr = strrchr(new_filename, '/'); if (line_ptr) { *line_ptr = '\0'; bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *line_ptr = '/'; } dst_stream = xfopen(new_filename, "w+"); backup_filename = NULL; } else { backup_filename = xmalloc(strlen(new_filename) + 6); strcpy(backup_filename, new_filename); strcat(backup_filename, ".orig"); if (rename(new_filename, backup_filename) == -1) { bb_perror_msg_and_die("cannot create file %s", backup_filename); } dst_stream = xfopen(new_filename, "w"); } if ((backup_filename == NULL) || file_doesnt_exist(original_filename)) { src_stream = NULL; } else { if (strcmp(original_filename, new_filename) == 0) { src_stream = xfopen(backup_filename, "r"); } else { src_stream = xfopen(original_filename, "r"); } } printf("patching file %s\n", new_filename); /* Handle each hunk */ patch_line = xmalloc_fgets(patch_file); while (patch_line) { unsigned int count; unsigned int src_beg_line; unsigned int unused; unsigned int hunk_offset_start = 0; int hunk_error = 0; /* This bit should be improved */ if ((sscanf(patch_line, "@@ -%d,%d +%d,%d @@", &src_beg_line, &unused, &dest_beg_line, &unused) != 4) && (sscanf(patch_line, "@@ -%d,%d +%d @@", &src_beg_line, &unused, &dest_beg_line) != 3) && (sscanf(patch_line, "@@ -%d +%d,%d @@", &src_beg_line, &dest_beg_line, &unused) != 3)) { /* No more hunks for this file */ break; } free(patch_line); hunk_count++; if (src_beg_line && dest_beg_line) { /* Copy unmodified lines upto start of hunk */ /* src_beg_line will be 0 if its a new file */ count = src_beg_line - src_cur_line; if (copy_lines(src_stream, dst_stream, count) != count) { bb_error_msg_and_die("bad src file"); } src_cur_line += count; dest_cur_line += count; copy_trailing_lines_flag = 1; } hunk_offset_start = src_cur_line; while ((patch_line = xmalloc_fgets(patch_file)) != NULL) { if ((*patch_line == '-') || (*patch_line == ' ')) { char *src_line = NULL; if (src_stream) { src_line = xmalloc_fgets(src_stream); if (!src_line) { hunk_error++; break; } else { src_cur_line++; } if (strcmp(src_line, patch_line + 1) != 0) { bb_error_msg("hunk #%d FAILED at %d", hunk_count, hunk_offset_start); hunk_error++; free(patch_line); /* Probably need to find next hunk, etc... */ /* but for now we just bail out */ patch_line = NULL; break; } free(src_line); } if (*patch_line == ' ') { fputs(patch_line + 1, dst_stream); dest_cur_line++; } } else if (*patch_line == '+') { fputs(patch_line + 1, dst_stream); dest_cur_line++; } else { break; } free(patch_line); } if (hunk_error) { bad_hunk_count++; } } /* Cleanup last patched file */ if (copy_trailing_lines_flag) { copy_lines(src_stream, dst_stream, -1); } if (src_stream) { fclose(src_stream); } if (dst_stream) { fclose(dst_stream); } if (bad_hunk_count) { if (!ret) { ret = 1; } bb_error_msg("%d out of %d hunk FAILED", bad_hunk_count, hunk_count); } else { /* It worked, we can remove the backup */ if (backup_filename) { unlink(backup_filename); } if ((dest_cur_line == 0) || (dest_beg_line == 0)) { /* The new patched file is empty, remove it */ xunlink(new_filename); if (strcmp(new_filename, original_filename) != 0) xunlink(original_filename); } } } /* 0 = SUCCESS * 1 = Some hunks failed * 2 = More serious problems */ return ret; }
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; #if ENABLE_FEATURE_TAR_SELINUX char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; #ifdef __BIONIC__ matchpathcon_init(NULL); #endif if (!sctx) sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); free(archive_handle->tar__sctx[PAX_NEXT_FILE]); archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { char *slash = strrchr(file_header->name, '/'); if (slash) { *slash = '\0'; bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); *slash = '/'; } } if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { /* Remove the entry if it exists */ if (!S_ISDIR(file_header->mode)) { /* Is it hardlink? * We encode hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 ) { /* Ugly special case: * tar cf t.tar hardlink1 hardlink2 hardlink1 * results in this tarball structure: * hardlink1 * hardlink2 -> hardlink1 * hardlink1 -> hardlink1 <== !!! */ if (strcmp(file_header->link_target, file_header->name) == 0) goto ret; } /* Proceed with deleting */ if (unlink(file_header->name) == -1 && errno != ENOENT ) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } } else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat existing_sb; if (lstat(file_header->name, &existing_sb) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("can't stat old file"); } } else if ((time_t) existing_sb.st_mtime >= (time_t) file_header->mtime) { if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) && !S_ISDIR(file_header->mode) ) { bb_error_msg("%s not created: newer or " "same age file exists", file_header->name); } data_skip(archive_handle); goto ret; } else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } /* Handle hard links separately * We encode hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 ) { /* hard link */ res = link(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("can't create %slink " "from %s to %s", "hard", file_header->name, file_header->link_target); } /* Hardlinks have no separate mode/ownership, skip chown/chmod */ goto ret; } /* Create the filesystem entry */ switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ char *dst_name; int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; dst_name = file_header->name; #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) /* rpm-style temp file name */ dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); #endif dst_fd = xopen3(dst_name, flags, file_header->mode ); bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { xrename(dst_name, file_header->name); free(dst_name); } #endif break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((res == -1) && (errno != EISDIR) /* btw, Linux doesn't return this */ && (errno != EEXIST) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't make dir %s", file_header->name); } break; case S_IFLNK: /* Symlink */ //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) res = symlink(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create %slink " "from %s to %s", "sym", file_header->name, file_header->link_target); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create node %s", file_header->name); } break; default: bb_error_msg_and_die("unrecognized file type"); } if (!S_ISLNK(file_header->mode)) { if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { uid_t uid = file_header->uid; gid_t gid = file_header->gid; #if ENABLE_FEATURE_TAR_UNAME_GNAME if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { if (file_header->tar__uname) { //TODO: cache last name/id pair? struct passwd *pwd = getpwnam(file_header->tar__uname); if (pwd) uid = pwd->pw_uid; } if (file_header->tar__gname) { struct group *grp = getgrnam(file_header->tar__gname); if (grp) gid = grp->gr_gid; } } #endif /* GNU tar 1.15.1 uses chown, not lchown */ chown(file_header->name, uid, gid); } /* uclibc has no lchmod, glibc is even stranger - * it has lchmod which seems to do nothing! * so we use chmod... */ if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { chmod(file_header->name, file_header->mode); } if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { struct timeval t[2]; t[1].tv_sec = t[0].tv_sec = file_header->mtime; t[1].tv_usec = t[0].tv_usec = 0; utimes(file_header->name, t); } } ret: ; #if ENABLE_FEATURE_TAR_SELINUX if (sctx) { /* reset the context after creating an entry */ setfscreatecon(NULL); } #endif }
int patch_main(int argc UNUSED_PARAM, char **argv) { struct stat saved_stat; char *patch_line; FILE *patch_file; int patch_level; int ret = 0; char plus = '+'; unsigned opt; enum { OPT_R = (1 << 2), OPT_N = (1 << 3), /*OPT_f = (1 << 4), ignored */ /*OPT_E = (1 << 5), ignored, this is the default */ /*OPT_g = (1 << 6), ignored */ OPT_dry_run = (1 << 7) * ENABLE_LONG_OPTS, }; xfunc_error_retval = 2; { const char *p = "-1"; const char *i = "-"; /* compat */ #if ENABLE_LONG_OPTS static const char patch_longopts[] ALIGN1 = "strip\0" Required_argument "p" "input\0" Required_argument "i" "reverse\0" No_argument "R" "forward\0" No_argument "N" /* "Assume user knows what [s]he is doing, do not ask any questions": */ "force\0" No_argument "f" /*ignored*/ # if ENABLE_DESKTOP "remove-empty-files\0" No_argument "E" /*ignored*/ /* "Controls actions when a file is under RCS or SCCS control, * and does not exist or is read-only and matches the default version, * or when a file is under ClearCase control and does not exist..." * IOW: rather obscure option. * But Gentoo's portage does use -g0 */ "get\0" Required_argument "g" /*ignored*/ # endif "dry-run\0" No_argument "\xfd" # if ENABLE_DESKTOP "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ # endif ; applet_long_options = patch_longopts; #endif /* -f,-E,-g are ignored */ opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL); if (opt & OPT_R) plus = '-'; patch_level = xatoi(p); /* can be negative! */ patch_file = xfopen_stdin(i); } patch_line = xmalloc_fgetline(patch_file); while (patch_line) { FILE *src_stream; FILE *dst_stream; //char *old_filename; char *new_filename; char *backup_filename = NULL; unsigned src_cur_line = 1; unsigned dst_cur_line = 0; unsigned dst_beg_line; unsigned bad_hunk_count = 0; unsigned hunk_count = 0; smallint copy_trailing_lines_flag = 0; /* Skip everything upto the "---" marker * No need to parse the lines "Only in <dir>", and "diff <args>" */ do { /* Extract the filename ugsed before the patch was generated */ new_filename = extract_filename(patch_line, patch_level, "--- "); // was old_filename above patch_line = xmalloc_fgetline(patch_file); if (!patch_line) goto quit; } while (!new_filename); free(new_filename); // "source" filename is irrelevant new_filename = extract_filename(patch_line, patch_level, "+++ "); if (!new_filename) { bb_error_msg_and_die("invalid patch"); } /* Get access rights from the file to be patched */ if (stat(new_filename, &saved_stat) != 0) { char *slash = strrchr(new_filename, '/'); if (slash) { /* Create leading directories */ *slash = '\0'; bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *slash = '/'; } src_stream = NULL; saved_stat.st_mode = 0644; } else if (!(opt & OPT_dry_run)) { backup_filename = xasprintf("%s.orig", new_filename); xrename(new_filename, backup_filename); src_stream = xfopen_for_read(backup_filename); } else src_stream = xfopen_for_read(new_filename); if (opt & OPT_dry_run) { dst_stream = xfopen_for_write("/dev/null"); } else { dst_stream = xfopen_for_write(new_filename); fchmod(fileno(dst_stream), saved_stat.st_mode); } printf("patching file %s\n", new_filename); /* Handle all hunks for this file */ patch_line = xmalloc_fgets(patch_file); while (patch_line) { unsigned count; unsigned src_beg_line; unsigned hunk_offset_start; unsigned src_last_line = 1; unsigned dst_last_line = 1; if ((sscanf(patch_line, "@@ -%u,%u +%u,%u", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) && (sscanf(patch_line, "@@ -%u +%u,%u", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) ) { /* No more hunks for this file */ break; } if (plus != '+') { /* reverse patch */ unsigned tmp = src_last_line; src_last_line = dst_last_line; dst_last_line = tmp; tmp = src_beg_line; src_beg_line = dst_beg_line; dst_beg_line = tmp; } hunk_count++; if (src_beg_line && dst_beg_line) { /* Copy unmodified lines upto start of hunk */ /* src_beg_line will be 0 if it's a new file */ count = src_beg_line - src_cur_line; if (copy_lines(src_stream, dst_stream, count)) { bb_error_msg_and_die("bad src file"); } src_cur_line += count; dst_cur_line += count; copy_trailing_lines_flag = 1; } src_last_line += hunk_offset_start = src_cur_line; dst_last_line += dst_cur_line; while (1) { free(patch_line); patch_line = xmalloc_fgets(patch_file); if (patch_line == NULL) break; /* EOF */ if (!*patch_line) { /* whitespace-damaged patch with "" lines */ free(patch_line); patch_line = xstrdup(" "); } if ((*patch_line != '-') && (*patch_line != '+') && (*patch_line != ' ') ) { break; /* End of hunk */ } if (*patch_line != plus) { /* '-' or ' ' */ char *src_line = NULL; if (src_cur_line == src_last_line) break; if (src_stream) { src_line = xmalloc_fgets(src_stream); if (src_line) { int diff = strcmp(src_line, patch_line + 1); src_cur_line++; free(src_line); if (diff) src_line = NULL; } } /* Do not patch an already patched hunk with -N */ if (src_line == 0 && (opt & OPT_N)) { continue; } if (!src_line) { bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); bad_hunk_count++; break; } if (*patch_line != ' ') { /* '-' */ continue; } } if (dst_cur_line == dst_last_line) break; fputs(patch_line + 1, dst_stream); dst_cur_line++; } /* end of while loop handling one hunk */ } /* end of while loop handling one file */ /* Cleanup last patched file */ if (copy_trailing_lines_flag) { copy_lines(src_stream, dst_stream, (unsigned)(-1)); } if (src_stream) { fclose(src_stream); } fclose(dst_stream); if (bad_hunk_count) { ret = 1; bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); } else { /* It worked, we can remove the backup */ if (backup_filename) { unlink(backup_filename); } if (!(opt & OPT_dry_run) && ((dst_cur_line == 0) || (dst_beg_line == 0)) ) { /* The new patched file is empty, remove it */ xunlink(new_filename); // /* old_filename and new_filename may be the same file */ // unlink(old_filename); } } free(backup_filename); //free(old_filename); free(new_filename); } /* end of "while there are patch lines" */ quit: /* 0 = SUCCESS * 1 = Some hunks failed * 2 = More serious problems (exited earlier) */ return ret; }
int patch_main(int argc UNUSED_PARAM, char **argv) { struct stat saved_stat; char *patch_line; FILE *patch_file; int patch_level; int ret = 0; char plus = '+'; xfunc_error_retval = 2; { const char *p = "-1"; const char *i = "-"; /* compat */ if (getopt32(argv, "p:i:R", &p, &i) & 4) plus = '-'; patch_level = xatoi(p); /* can be negative! */ patch_file = xfopen_stdin(i); } patch_line = xmalloc_fgetline(patch_file); while (patch_line) { FILE *src_stream; FILE *dst_stream; //char *old_filename; char *new_filename; char *backup_filename; unsigned src_cur_line = 1; unsigned dst_cur_line = 0; unsigned dst_beg_line; unsigned bad_hunk_count = 0; unsigned hunk_count = 0; smallint copy_trailing_lines_flag = 0; /* Skip everything upto the "---" marker * No need to parse the lines "Only in <dir>", and "diff <args>" */ do { /* Extract the filename used before the patch was generated */ new_filename = extract_filename(patch_line, patch_level, "--- "); // was old_filename above patch_line = xmalloc_fgetline(patch_file); if (!patch_line) goto quit; } while (!new_filename); free(new_filename); // "source" filename is irrelevant new_filename = extract_filename(patch_line, patch_level, "+++ "); if (!new_filename) { bb_error_msg_and_die("invalid patch"); } /* Get access rights from the file to be patched */ if (stat(new_filename, &saved_stat) != 0) { char *slash = strrchr(new_filename, '/'); if (slash) { /* Create leading directories */ *slash = '\0'; bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *slash = '/'; } backup_filename = NULL; src_stream = NULL; saved_stat.st_mode = 0644; } else { backup_filename = xasprintf("%s.orig", new_filename); xrename(new_filename, backup_filename); src_stream = xfopen_for_read(backup_filename); } dst_stream = xfopen_for_write(new_filename); fchmod(fileno(dst_stream), saved_stat.st_mode); printf("patching file %s\n", new_filename); /* Handle all hunks for this file */ patch_line = xmalloc_fgets(patch_file); while (patch_line) { unsigned count; unsigned src_beg_line; unsigned hunk_offset_start; unsigned src_last_line = 1; unsigned dst_last_line = 1; if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) ) { /* No more hunks for this file */ break; } if (plus != '+') { /* reverse patch */ unsigned tmp = src_last_line; src_last_line = dst_last_line; dst_last_line = tmp; tmp = src_beg_line; src_beg_line = dst_beg_line; dst_beg_line = tmp; } hunk_count++; if (src_beg_line && dst_beg_line) { /* Copy unmodified lines upto start of hunk */ /* src_beg_line will be 0 if it's a new file */ count = src_beg_line - src_cur_line; if (copy_lines(src_stream, dst_stream, count)) { bb_error_msg_and_die("bad src file"); } src_cur_line += count; dst_cur_line += count; copy_trailing_lines_flag = 1; } src_last_line += hunk_offset_start = src_cur_line; dst_last_line += dst_cur_line; while (1) { free(patch_line); patch_line = xmalloc_fgets(patch_file); if (patch_line == NULL) break; /* EOF */ if ((*patch_line != '-') && (*patch_line != '+') && (*patch_line != ' ') ) { break; /* End of hunk */ } if (*patch_line != plus) { /* '-' or ' ' */ char *src_line = NULL; if (src_cur_line == src_last_line) break; if (src_stream) { src_line = xmalloc_fgets(src_stream); if (src_line) { int diff = strcmp(src_line, patch_line + 1); src_cur_line++; free(src_line); if (diff) src_line = NULL; } } if (!src_line) { bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); bad_hunk_count++; break; } if (*patch_line != ' ') { /* '-' */ continue; } } if (dst_cur_line == dst_last_line) break; fputs(patch_line + 1, dst_stream); dst_cur_line++; } /* end of while loop handling one hunk */ } /* end of while loop handling one file */ /* Cleanup last patched file */ if (copy_trailing_lines_flag) { copy_lines(src_stream, dst_stream, (unsigned)(-1)); } if (src_stream) { fclose(src_stream); } fclose(dst_stream); if (bad_hunk_count) { ret = 1; bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); } else { /* It worked, we can remove the backup */ if (backup_filename) { unlink(backup_filename); } if ((dst_cur_line == 0) || (dst_beg_line == 0)) { /* The new patched file is empty, remove it */ xunlink(new_filename); // /* old_filename and new_filename may be the same file */ // unlink(old_filename); } } free(backup_filename); //free(old_filename); free(new_filename); } /* end of "while there are patch lines" */ quit: /* 0 = SUCCESS * 1 = Some hunks failed * 2 = More serious problems (exited earlier) */ return ret; }
int unzip_main(int argc, char **argv) { enum { O_PROMPT, O_NEVER, O_ALWAYS }; zip_header_t zip_header; smallint verbose = 1; smallint listing = 0; smallint overwrite = O_PROMPT; unsigned total_size; unsigned total_entries; int src_fd = -1; int dst_fd = -1; char *src_fn = NULL; char *dst_fn = NULL; llist_t *zaccept = NULL; llist_t *zreject = NULL; char *base_dir = NULL; int i, opt; int opt_range = 0; char key_buf[80]; struct stat stat_buf; /* '-' makes getopt return 1 for non-options */ while ((opt = getopt(argc, argv, "-d:lnopqx")) != -1) { switch (opt_range) { case 0: /* Options */ switch (opt) { case 'l': /* List */ listing = 1; break; case 'n': /* Never overwrite existing files */ overwrite = O_NEVER; break; case 'o': /* Always overwrite existing files */ overwrite = O_ALWAYS; break; case 'p': /* Extract files to stdout and fall through to set verbosity */ dst_fd = STDOUT_FILENO; case 'q': /* Be quiet */ verbose = 0; break; case 1: /* The zip file */ /* +5: space for ".zip" and NUL */ src_fn = xmalloc(strlen(optarg) + 5); strcpy(src_fn, optarg); opt_range++; break; default: bb_show_usage(); } break; case 1: /* Include files */ if (opt == 1) { llist_add_to(&zaccept, optarg); break; } if (opt == 'd') { base_dir = optarg; opt_range += 2; break; } if (opt == 'x') { opt_range++; break; } bb_show_usage(); case 2 : /* Exclude files */ if (opt == 1) { llist_add_to(&zreject, optarg); break; } if (opt == 'd') { /* Extract to base directory */ base_dir = optarg; opt_range++; break; } /* fall through */ default: bb_show_usage(); } } if (src_fn == NULL) { bb_show_usage(); } /* Open input file */ if (LONE_DASH(src_fn)) { src_fd = STDIN_FILENO; /* Cannot use prompt mode since zip data is arriving on STDIN */ if (overwrite == O_PROMPT) overwrite = O_NEVER; } else { static const char extn[][5] = {"", ".zip", ".ZIP"}; int orig_src_fn_len = strlen(src_fn); for (i = 0; (i < 3) && (src_fd == -1); i++) { strcpy(src_fn + orig_src_fn_len, extn[i]); src_fd = open(src_fn, O_RDONLY); } if (src_fd == -1) { src_fn[orig_src_fn_len] = '\0'; bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn); } } /* Change dir if necessary */ if (base_dir) xchdir(base_dir); if (verbose) { printf("Archive: %s\n", src_fn); if (listing){ puts(" Length Date Time Name\n" " -------- ---- ---- ----"); } } total_size = 0; total_entries = 0; while (1) { uint32_t magic; /* Check magic number */ xread(src_fd, &magic, 4); if (magic == ZIP_CDS_MAGIC) break; if (magic != ZIP_FILEHEADER_MAGIC) bb_error_msg_and_die("invalid zip magic %08X", magic); /* Read the file header */ xread(src_fd, zip_header.raw, ZIP_HEADER_LEN); FIX_ENDIANNESS(zip_header); if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) { bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method); } /* Read filename */ free(dst_fn); dst_fn = xzalloc(zip_header.formatted.filename_len + 1); xread(src_fd, dst_fn, zip_header.formatted.filename_len); /* Skip extra header bytes */ unzip_skip(src_fd, zip_header.formatted.extra_len); /* Filter zip entries */ if (find_list_entry(zreject, dst_fn) || (zaccept && !find_list_entry(zaccept, dst_fn)) ) { /* Skip entry */ i = 'n'; } else { /* Extract entry */ if (listing) { /* List entry */ if (verbose) { unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16); printf("%9u %02u-%02u-%02u %02u:%02u %s\n", zip_header.formatted.ucmpsize, (dostime & 0x01e00000) >> 21, (dostime & 0x001f0000) >> 16, (((dostime & 0xfe000000) >> 25) + 1980) % 100, (dostime & 0x0000f800) >> 11, (dostime & 0x000007e0) >> 5, dst_fn); total_size += zip_header.formatted.ucmpsize; total_entries++; } else { /* short listing -- filenames only */ puts(dst_fn); } i = 'n'; } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */ i = -1; } else if (last_char_is(dst_fn, '/')) { /* Extract directory */ if (stat(dst_fn, &stat_buf) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("cannot stat '%s'",dst_fn); } if (verbose) { printf(" creating: %s\n", dst_fn); } unzip_create_leading_dirs(dst_fn); if (bb_make_directory(dst_fn, 0777, 0)) { bb_error_msg_and_die("exiting"); } } else { if (!S_ISDIR(stat_buf.st_mode)) { bb_error_msg_and_die("'%s' exists but is not directory", dst_fn); } } i = 'n'; } else { /* Extract file */ _check_file: if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */ if (errno != ENOENT) { bb_perror_msg_and_die("cannot stat '%s'",dst_fn); } i = 'y'; } else { /* File already exists */ if (overwrite == O_NEVER) { i = 'n'; } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */ if (overwrite == O_ALWAYS) { i = 'y'; } else { printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn); if (!fgets(key_buf, sizeof(key_buf), stdin)) { bb_perror_msg_and_die("cannot read input"); } i = key_buf[0]; } } else { /* File is not regular file */ bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn); } } } }
int makedevs_main(int argc UNUSED_PARAM, char **argv) { parser_t *parser; char *line = (char *)"-"; int ret = EXIT_SUCCESS; opt_complementary = "=1"; /* exactly one param */ getopt32(argv, "d:", &line); argv += optind; xchdir(*argv); /* ensure root dir exists */ umask(0); printf("rootdir=%s\ntable=", *argv); if (NOT_LONE_DASH(line)) { printf("'%s'\n", line); } else { puts("<stdin>"); } parser = config_open(line); while (config_read(parser, &line, 1, 1, "# \t", PARSE_NORMAL)) { int linenum; char type; unsigned mode = 0755; unsigned major = 0; unsigned minor = 0; unsigned count = 0; unsigned increment = 0; unsigned start = 0; char name[41]; char user[41]; char group[41]; char *full_name = name; uid_t uid; gid_t gid; linenum = parser->lineno; if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name, &type, &mode, user, group, &major, &minor, &start, &increment, &count)) || ((unsigned)(major | minor | start | count | increment) > 255) ) { bb_error_msg("invalid line %d: '%s'", linenum, line); ret = EXIT_FAILURE; continue; } gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid(); uid = (*user) ? get_ug_id(user, xuname2uid) : getuid(); /* We are already in the right root dir, * so make absolute paths relative */ if ('/' == *full_name) full_name++; if (type == 'd') { bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR); if (chown(full_name, uid, gid) == -1) { chown_fail: bb_perror_msg("line %d: can't chown %s", linenum, full_name); ret = EXIT_FAILURE; continue; } if (chmod(full_name, mode) < 0) { chmod_fail: bb_perror_msg("line %d: can't chmod %s", linenum, full_name); ret = EXIT_FAILURE; continue; } } else if (type == 'f') { struct stat st; if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) { bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name); ret = EXIT_FAILURE; continue; } if (chown(full_name, uid, gid) < 0) goto chown_fail; if (chmod(full_name, mode) < 0) goto chmod_fail; } else { dev_t rdev; unsigned i; char *full_name_inc; if (type == 'p') { mode |= S_IFIFO; } else if (type == 'c') { mode |= S_IFCHR; } else if (type == 'b') { mode |= S_IFBLK; } else { bb_error_msg("line %d: unsupported file type %c", linenum, type); ret = EXIT_FAILURE; continue; } full_name_inc = xmalloc(strlen(full_name) + sizeof(int)*3 + 2); if (count) count--; for (i = start; i <= start + count; i++) { sprintf(full_name_inc, count ? "%s%u" : "%s", full_name, i); rdev = makedev(major, minor + (i - start) * increment); if (mknod(full_name_inc, mode, rdev) != 0 && errno != EEXIST ) { bb_perror_msg("line %d: can't create node %s", linenum, full_name_inc); ret = EXIT_FAILURE; } else if (chown(full_name_inc, uid, gid) < 0) { bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc); ret = EXIT_FAILURE; } else if (chmod(full_name_inc, mode) < 0) { bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc); ret = EXIT_FAILURE; } } free(full_name_inc); } } if (ENABLE_FEATURE_CLEAN_UP) config_close(parser); return ret; }
int install_main(int argc, char **argv) { struct stat statbuf; mode_t mode; uid_t uid; gid_t gid; char *arg, *last; const char *gid_str; const char *uid_str; const char *mode_str; int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE; int opts; int min_args = 1; int ret = EXIT_SUCCESS; int isdir = 0; #if ENABLE_SELINUX security_context_t scontext; bool use_default_selinux_context = 1; #endif enum { OPT_c = 1 << 0, OPT_v = 1 << 1, OPT_b = 1 << 2, OPT_MKDIR_LEADING = 1 << 3, OPT_DIRECTORY = 1 << 4, OPT_PRESERVE_TIME = 1 << 5, OPT_STRIP = 1 << 6, OPT_GROUP = 1 << 7, OPT_MODE = 1 << 8, OPT_OWNER = 1 << 9, #if ENABLE_SELINUX OPT_SET_SECURITY_CONTEXT = 1 << 10, OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11, #endif }; #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS applet_long_options = install_longopts; #endif opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); /* -c exists for backwards compatibility, it's needed */ /* -v is ignored ("print name of each created directory") */ /* -b is ignored ("make a backup of each existing destination file") */ opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"), &gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext)); argc -= optind; argv += optind; #if ENABLE_SELINUX if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) { selinux_or_die(); use_default_selinux_context = 0; if (opts & OPT_PRESERVE_SECURITY_CONTEXT) { copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; } if (opts & OPT_SET_SECURITY_CONTEXT) { setfscreatecon_or_die(scontext); copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT; } } #endif /* preserve access and modification time, this is GNU behaviour, * BSD only preserves modification time */ if (opts & OPT_PRESERVE_TIME) { copy_flags |= FILEUTILS_PRESERVE_STATUS; } mode = 0755; /* GNU coreutils 6.10 compat */ if (opts & OPT_MODE) bb_parse_mode(mode_str, &mode); uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); last = argv[argc - 1]; if (!(opts & OPT_DIRECTORY)) { argv[argc - 1] = NULL; min_args++; /* coreutils install resolves link in this case, don't use lstat */ isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode); } if (argc < min_args) bb_show_usage(); while ((arg = *argv++) != NULL) { char *dest = last; if (opts & OPT_DIRECTORY) { dest = arg; /* GNU coreutils 6.9 does not set uid:gid * on intermediate created directories * (only on last one) */ if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) { ret = EXIT_FAILURE; goto next; } } else { if (opts & OPT_MKDIR_LEADING) { char *ddir = xstrdup(dest); bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR); /* errors are not checked. copy_file * will fail if dir is not created. */ free(ddir); } if (isdir) dest = concat_path_file(last, bb_basename(arg)); if (copy_file(arg, dest, copy_flags) != 0) { /* copy is not made */ ret = EXIT_FAILURE; goto next; } if (opts & OPT_STRIP) { char *args[4]; args[0] = (char*)"strip"; args[1] = (char*)"-p"; /* -p --preserve-dates */ args[2] = dest; args[3] = NULL; if (spawn_and_wait(args)) { bb_perror_msg("strip"); ret = EXIT_FAILURE; } } } /* Set the file mode (always, not only with -m). * GNU coreutils 6.10 is not affected by umask. */ if (chmod(dest, mode) == -1) { bb_perror_msg("can't change %s of %s", "permissions", dest); ret = EXIT_FAILURE; } #if ENABLE_SELINUX if (use_default_selinux_context) setdefaultfilecon(dest); #endif /* Set the user and group id */ if ((opts & (OPT_OWNER|OPT_GROUP)) && lchown(dest, uid, gid) == -1 ) { bb_perror_msg("can't change %s of %s", "ownership", dest); ret = EXIT_FAILURE; } next: if (ENABLE_FEATURE_CLEAN_UP && isdir) free(dest); } return ret; }
void data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { char *name = xstrdup(file_header->name); bb_make_directory(dirname(name), -1, FILEUTILS_RECUR); free(name); } /* Check if the file already exists */ if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { /* Remove the existing entry if it exists */ if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT) ) { bb_perror_msg_and_die("cannot remove old file %s", file_header->name); } } else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat statbuf; if (lstat(file_header->name, &statbuf) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("cannot stat old file"); } } else if (statbuf.st_mtime <= file_header->mtime) { if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_error_msg("%s not created: newer or " "same age file exists", file_header->name); } data_skip(archive_handle); return; } else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("cannot remove old file %s", file_header->name); } } /* Handle hard links separately * We identified hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && (file_header->link_target) && (file_header->size == 0) ) { /* hard link */ res = link(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("cannot create %slink " "from %s to %s", "hard", file_header->name, file_header->link_target); } } else { /* Create the filesystem entry */ switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL, file_header->mode); bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((res == -1) && (errno != EISDIR) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("cannot make dir %s", file_header->name); } break; case S_IFLNK: /* Symlink */ res = symlink(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("cannot create %slink " "from %s to %s", "sym", file_header->name, file_header->link_target); } break; #ifndef _WIN32 case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("cannot create node %s", file_header->name); } break; #endif default: bb_error_msg_and_die("unrecognized file type"); } } #ifndef _WIN32 if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) { #if ENABLE_FEATURE_TAR_UNAME_GNAME uid_t uid = file_header->uid; gid_t gid = file_header->gid; if (file_header->uname) { struct passwd *pwd = getpwnam(file_header->uname); if (pwd) uid = pwd->pw_uid; } if (file_header->gname) { struct group *grp = getgrnam(file_header->gname); if (grp) gid = grp->gr_gid; } lchown(file_header->name, uid, gid); #else lchown(file_header->name, file_header->uid, file_header->gid); #endif } #endif if ((file_header->mode & S_IFMT) != S_IFLNK) { /* uclibc has no lchmod, glibc is even stranger - * it has lchmod which seems to do nothing! * so we use chmod... */ if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM)) { chmod(file_header->name, file_header->mode); } /* same for utime */ if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { struct utimbuf t; t.actime = t.modtime = file_header->mtime; utime(file_header->name, &t); } } }
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { char *slash = strrchr(file_header->name, '/'); if (slash) { *slash = '\0'; bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); *slash = '/'; } } if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { /* Remove the entry if it exists */ if ((!S_ISDIR(file_header->mode)) && (unlink(file_header->name) == -1) && (errno != ENOENT) ) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat existing_sb; if (lstat(file_header->name, &existing_sb) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("can't stat old file"); } } else if (existing_sb.st_mtime >= file_header->mtime) { if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { bb_error_msg("%s not created: newer or " "same age file exists", file_header->name); } data_skip(archive_handle); return; } else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } /* Handle hard links separately * We identified hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 ) { /* hard link */ res = link(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("can't create %slink " "from %s to %s", "hard", file_header->name, file_header->link_target); } } else { /* Create the filesystem entry */ switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; dst_fd = xopen3(file_header->name, flags, file_header->mode ); bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((res == -1) && (errno != EISDIR) /* btw, Linux doesn't return this */ && (errno != EEXIST) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't make dir %s", file_header->name); } break; case S_IFLNK: /* Symlink */ res = symlink(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create %slink " "from %s to %s", "sym", file_header->name, file_header->link_target); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create node %s", file_header->name); } break; default: bb_error_msg_and_die("unrecognized file type"); } } if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { #if ENABLE_FEATURE_TAR_UNAME_GNAME if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { uid_t uid = file_header->uid; gid_t gid = file_header->gid; if (file_header->tar__uname) { //TODO: cache last name/id pair? struct passwd *pwd = getpwnam(file_header->tar__uname); if (pwd) uid = pwd->pw_uid; } if (file_header->tar__gname) { struct group *grp = getgrnam(file_header->tar__gname); if (grp) gid = grp->gr_gid; } /* GNU tar 1.15.1 uses chown, not lchown */ chown(file_header->name, uid, gid); } else #endif chown(file_header->name, file_header->uid, file_header->gid); } if (!S_ISLNK(file_header->mode)) { /* uclibc has no lchmod, glibc is even stranger - * it has lchmod which seems to do nothing! * so we use chmod... */ if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { chmod(file_header->name, file_header->mode); } /* same for utime */ if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { struct timeval t[2]; t[1].tv_sec = t[0].tv_sec = file_header->mtime; t[1].tv_usec = t[0].tv_usec = 0; utimes(file_header->name, t); } } }