static int unpack_archive(struct xbps_handle *xhp, xbps_dictionary_t pkg_repod, const char *pkgver, const char *fname, struct archive *ar) { xbps_dictionary_t propsd, filesd, old_filesd; xbps_array_t array, obsoletes; xbps_object_t obj; void *instbuf = NULL, *rembuf = NULL; struct stat st; struct xbps_unpack_cb_data xucd; struct archive_entry *entry; size_t i, entry_idx = 0, instbufsiz = 0, rembufsiz = 0; ssize_t entry_size; const char *file, *entry_pname, *transact, *tgtlnk; char *pkgname, *dname, *buf, *buf2, *p, *p2; int ar_rv, rv, entry_type, flags; bool preserve, update, conf_file, file_exists, skip_obsoletes; bool softreplace, skip_extract, force, metafile; uid_t euid; assert(xbps_object_type(pkg_repod) == XBPS_TYPE_DICTIONARY); assert(ar != NULL); propsd = filesd = old_filesd = NULL; force = preserve = update = conf_file = file_exists = false; skip_obsoletes = softreplace = metafile = false; xbps_dictionary_get_bool(pkg_repod, "preserve", &preserve); xbps_dictionary_get_bool(pkg_repod, "skip-obsoletes", &skip_obsoletes); xbps_dictionary_get_bool(pkg_repod, "softreplace", &softreplace); xbps_dictionary_get_cstring_nocopy(pkg_repod, "transaction", &transact); euid = geteuid(); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if (xhp->flags & XBPS_FLAG_FORCE_UNPACK) force = true; if (xhp->unpack_cb != NULL) { /* initialize data for unpack cb */ memset(&xucd, 0, sizeof(xucd)); } if (access(xhp->rootdir, R_OK) == -1) { if (errno != ENOENT) { rv = errno; goto out; } if (xbps_mkpath(xhp->rootdir, 0750) == -1) { rv = errno; goto out; } } if (chdir(xhp->rootdir) == -1) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, errno, pkgver, "%s: [unpack] failed to chdir to rootdir `%s': %s", pkgver, xhp->rootdir, strerror(errno)); rv = errno; goto out; } if (strcmp(transact, "update") == 0) update = true; /* * Process the archive files. */ flags = set_extract_flags(euid); for (;;) { ar_rv = archive_read_next_header(ar, &entry); if (ar_rv == ARCHIVE_EOF || ar_rv == ARCHIVE_FATAL) break; else if (ar_rv == ARCHIVE_RETRY) continue; entry_pname = archive_entry_pathname(entry); entry_size = archive_entry_size(entry); entry_type = archive_entry_filetype(entry); /* * Ignore directories from archive. */ if (entry_type == AE_IFDIR) { archive_read_data_skip(ar); continue; } if (strcmp("./INSTALL", entry_pname) == 0) { /* * Store file in a buffer and execute * the "pre" action from it. */ instbufsiz = entry_size; instbuf = malloc(entry_size); assert(instbuf); if (archive_read_data(ar, instbuf, entry_size) != entry_size) { rv = EINVAL; goto out; } rv = xbps_pkg_exec_buffer(xhp, instbuf, instbufsiz, pkgver, "pre", update); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] INSTALL script failed " "to execute pre ACTION: %s", pkgver, strerror(rv)); goto out; } continue; } else if (strcmp("./REMOVE", entry_pname) == 0) { /* store file in a buffer */ rembufsiz = entry_size; rembuf = malloc(entry_size); assert(rembuf); if (archive_read_data(ar, rembuf, entry_size) != entry_size) { rv = EINVAL; goto out; } continue; } else if (strcmp("./files.plist", entry_pname) == 0) { filesd = xbps_archive_get_dictionary(ar, entry); if (filesd == NULL) { rv = errno; goto out; } continue; } else if (strcmp("./props.plist", entry_pname) == 0) { propsd = xbps_archive_get_dictionary(ar, entry); if (propsd == NULL) { rv = errno; goto out; } continue; } /* * XXX: duplicate code. * Create the metaplist file before unpacking any real file. */ if (propsd && filesd && !metafile) { rv = create_pkg_metaplist(xhp, pkgname, pkgver, propsd, filesd, instbuf, instbufsiz, rembuf, rembufsiz); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to create metaplist file: %s", pkgver, strerror(rv)); goto out; } metafile = true; } /* * If XBPS_PKGFILES or XBPS_PKGPROPS weren't found * in the archive at this phase, skip all data. */ if (propsd == NULL || filesd == NULL) { archive_read_data_skip(ar); /* * If we have processed 4 entries and the two * required metadata files weren't found, bail out. * This is not an XBPS binary package. */ if (entry_idx >= 3) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, ENODEV, pkgver, "%s: [unpack] invalid binary package `%s'.", pkgver, fname); rv = ENODEV; goto out; } entry_idx++; continue; } /* * Prepare unpack callback ops. */ if (xhp->unpack_cb != NULL) { xucd.xhp = xhp; xucd.pkgver = pkgver; xucd.entry = entry_pname; xucd.entry_size = entry_size; xucd.entry_is_conf = false; } /* * Compute total entries in progress data, if set. * total_entries = files + conf_files + links. */ if (xhp->unpack_cb != NULL) { xucd.entry_total_count = 0; array = xbps_dictionary_get(filesd, "files"); xucd.entry_total_count += (ssize_t)xbps_array_count(array); array = xbps_dictionary_get(filesd, "conf_files"); xucd.entry_total_count += (ssize_t)xbps_array_count(array); array = xbps_dictionary_get(filesd, "links"); xucd.entry_total_count += (ssize_t)xbps_array_count(array); } /* * Always check that extracted file exists and hash * doesn't match, in that case overwrite the file. * Otherwise skip extracting it. */ conf_file = skip_extract = file_exists = false; if (lstat(entry_pname, &st) == 0) file_exists = true; if (!force && (entry_type == AE_IFREG)) { buf = strchr(entry_pname, '.') + 1; assert(buf != NULL); if (file_exists) { /* * Handle configuration files. Check if current * entry is a configuration file and take action * if required. Skip packages that don't have * "conf_files" array on its XBPS_PKGPROPS * dictionary. */ if (xbps_entry_is_a_conf_file(propsd, buf)) { conf_file = true; if (xhp->unpack_cb != NULL) xucd.entry_is_conf = true; rv = xbps_entry_install_conf_file(xhp, filesd, entry, entry_pname, pkgver, pkgname); if (rv == -1) { /* error */ goto out; } else if (rv == 0) { /* * Keep curfile as is. */ skip_extract = true; } } else { rv = xbps_file_hash_check_dictionary( xhp, filesd, "files", buf); if (rv == -1) { /* error */ xbps_dbg_printf(xhp, "%s: failed to check" " hash for `%s': %s\n", pkgver, entry_pname, strerror(errno)); goto out; } else if (rv == 0) { /* * hash match, skip extraction. */ xbps_dbg_printf(xhp, "%s: file %s " "matches existing SHA256, " "skipping...\n", pkgver, entry_pname); skip_extract = true; } } } } else if (!force && (entry_type == AE_IFLNK)) { /* * Check if current link from binpkg hasn't been * modified, otherwise extract new link. */ buf = realpath(entry_pname, NULL); if (buf) { if (strcmp(xhp->rootdir, "/")) { p = buf; p += strlen(xhp->rootdir); } else p = buf; tgtlnk = find_pkg_symlink_target(filesd, entry_pname); assert(tgtlnk); if (strncmp(tgtlnk, "./", 2) == 0) { buf2 = strdup(entry_pname); assert(buf2); dname = dirname(buf2); p2 = xbps_xasprintf("%s/%s", dname, tgtlnk); free(buf2); } else { p2 = strdup(tgtlnk); assert(p2); } xbps_dbg_printf(xhp, "%s: symlink %s cur: %s " "new: %s\n", pkgver, entry_pname, p, p2); if (strcmp(p, p2) == 0) { xbps_dbg_printf(xhp, "%s: symlink " "%s matched, skipping...\n", pkgver, entry_pname); skip_extract = true; } free(buf); free(p2); } } /* * Check if current file mode differs from file mode * in binpkg and apply perms if true. */ if (!force && file_exists && skip_extract && (archive_entry_mode(entry) != st.st_mode)) { if (chmod(entry_pname, archive_entry_mode(entry)) != 0) { xbps_dbg_printf(xhp, "%s: failed " "to set perms %s to %s: %s\n", pkgver, archive_entry_strmode(entry), entry_pname, strerror(errno)); rv = EINVAL; goto out; } xbps_dbg_printf(xhp, "%s: entry %s changed file " "mode to %s.\n", pkgver, entry_pname, archive_entry_strmode(entry)); } /* * Check if current uid/gid differs from file in binpkg, * and change permissions if true. */ if ((!force && file_exists && skip_extract && (euid == 0)) && (((archive_entry_uid(entry) != st.st_uid)) || ((archive_entry_gid(entry) != st.st_gid)))) { if (lchown(entry_pname, archive_entry_uid(entry), archive_entry_gid(entry)) != 0) { xbps_dbg_printf(xhp, "%s: failed " "to set uid/gid to %u:%u (%s)\n", pkgver, archive_entry_uid(entry), archive_entry_gid(entry), strerror(errno)); } else { xbps_dbg_printf(xhp, "%s: entry %s changed " "uid/gid to %u:%u.\n", pkgver, entry_pname, archive_entry_uid(entry), archive_entry_gid(entry)); } } if (!update && conf_file && file_exists && !skip_extract) { /* * If installing new package preserve old configuration * file but renaming it to <file>.old. */ buf = xbps_xasprintf("%s.old", entry_pname); (void)rename(entry_pname, buf); free(buf); buf = NULL; xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Renamed old configuration file " "`%s' to `%s.old'.", entry_pname, entry_pname); } if (!force && skip_extract) { archive_read_data_skip(ar); continue; } /* * Reset entry_pname again because if entry's pathname * has been changed it will become a dangling pointer. */ entry_pname = archive_entry_pathname(entry); /* * Extract entry from archive. */ if (archive_read_extract(ar, entry, flags) != 0) { rv = archive_errno(ar); xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to extract file `%s': %s", pkgver, entry_pname, strerror(rv)); } else { if (xhp->unpack_cb != NULL) { xucd.entry_extract_count++; (*xhp->unpack_cb)(&xucd, xhp->unpack_cb_data); } } } /* * XXX: duplicate code. * Create the metaplist file if it wasn't created before. */ if (propsd && filesd && !metafile) { rv = create_pkg_metaplist(xhp, pkgname, pkgver, propsd, filesd, instbuf, instbufsiz, rembuf, rembufsiz); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to create metaplist file: %s", pkgver, strerror(rv)); goto out; } } /* * If there was any error extracting files from archive, error out. */ if ((rv = archive_errno(ar)) != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, NULL, "%s: [unpack] failed to extract files: %s", pkgver, fname, archive_error_string(ar)); goto out; } /* * Skip checking for obsolete files on: * - New package installation without "softreplace" keyword. * - Package with "preserve" keyword. * - Package with "skip-obsoletes" keyword. */ if (skip_obsoletes || preserve || (!softreplace && !update)) goto out; /* * Check and remove obsolete files on: * - Package upgrade. * - Package with "softreplace" keyword. */ old_filesd = xbps_pkgdb_get_pkg_metadata(xhp, pkgname); if (old_filesd == NULL) goto out; obsoletes = xbps_find_pkg_obsoletes(xhp, old_filesd, filesd); for (i = 0; i < xbps_array_count(obsoletes); i++) { obj = xbps_array_get(obsoletes, i); file = xbps_string_cstring_nocopy(obj); if (remove(file) == -1) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL, errno, pkgver, "%s: failed to remove obsolete entry `%s': %s", pkgver, file, strerror(errno)); continue; } xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_OBSOLETE, 0, pkgver, "%s: removed obsolete entry: %s", pkgver, file); xbps_object_release(obj); } xbps_object_release(old_filesd); out: if (xbps_object_type(filesd) == XBPS_TYPE_DICTIONARY) xbps_object_release(filesd); if (xbps_object_type(propsd) == XBPS_TYPE_DICTIONARY) xbps_object_release(propsd); if (pkgname != NULL) free(pkgname); if (instbuf != NULL) free(instbuf); if (rembuf != NULL) free(rembuf); return rv; }
static int process_requests(int sock) { int flags; int size = 0; int retval = 0; uint64_t offset; ProxyHeader header; int mode, uid, gid; V9fsString name, value; struct timespec spec[2]; V9fsString oldpath, path; struct iovec in_iovec, out_iovec; in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; while (1) { /* * initialize the header type, so that we send * response to proper request type. */ header.type = 0; retval = read_request(sock, &in_iovec, &header); if (retval < 0) { goto err_out; } switch (header.type) { case T_OPEN: retval = do_open(&in_iovec); break; case T_CREATE: retval = do_create(&in_iovec); break; case T_MKNOD: case T_MKDIR: case T_SYMLINK: retval = do_create_others(header.type, &in_iovec); break; case T_LINK: v9fs_string_init(&path); v9fs_string_init(&oldpath); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "ss", &oldpath, &path); if (retval > 0) { retval = link(oldpath.data, path.data); if (retval < 0) { retval = -errno; } } v9fs_string_free(&oldpath); v9fs_string_free(&path); break; case T_LSTAT: case T_STATFS: retval = do_stat(header.type, &in_iovec, &out_iovec); break; case T_READLINK: retval = do_readlink(&in_iovec, &out_iovec); break; case T_CHMOD: v9fs_string_init(&path); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sd", &path, &mode); if (retval > 0) { retval = chmod(path.data, mode); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); break; case T_CHOWN: v9fs_string_init(&path); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sdd", &path, &uid, &gid); if (retval > 0) { retval = lchown(path.data, uid, gid); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); break; case T_TRUNCATE: v9fs_string_init(&path); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sq", &path, &offset); if (retval > 0) { retval = truncate(path.data, offset); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); break; case T_UTIME: v9fs_string_init(&path); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sqqqq", &path, &spec[0].tv_sec, &spec[0].tv_nsec, &spec[1].tv_sec, &spec[1].tv_nsec); if (retval > 0) { retval = qemu_utimens(path.data, spec); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); break; case T_RENAME: v9fs_string_init(&path); v9fs_string_init(&oldpath); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "ss", &oldpath, &path); if (retval > 0) { retval = rename(oldpath.data, path.data); if (retval < 0) { retval = -errno; } } v9fs_string_free(&oldpath); v9fs_string_free(&path); break; case T_REMOVE: v9fs_string_init(&path); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "s", &path); if (retval > 0) { retval = remove(path.data); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); break; case T_LGETXATTR: case T_LLISTXATTR: retval = do_getxattr(header.type, &in_iovec, &out_iovec); break; case T_LSETXATTR: v9fs_string_init(&path); v9fs_string_init(&name); v9fs_string_init(&value); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sssdd", &path, &name, &value, &size, &flags); if (retval > 0) { retval = lsetxattr(path.data, name.data, value.data, size, flags); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); v9fs_string_free(&name); v9fs_string_free(&value); break; case T_LREMOVEXATTR: v9fs_string_init(&path); v9fs_string_init(&name); retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "ss", &path, &name); if (retval > 0) { retval = lremovexattr(path.data, name.data); if (retval < 0) { retval = -errno; } } v9fs_string_free(&path); v9fs_string_free(&name); break; case T_GETVERSION: retval = do_getversion(&in_iovec, &out_iovec); break; default: goto err_out; break; } if (process_reply(sock, header.type, &out_iovec, retval) < 0) { goto err_out; } } err_out: g_free(in_iovec.iov_base); g_free(out_iovec.iov_base); return -1; }
/* Return: * -1 error, copy not made * 0 copy is made or user answered "no" in interactive mode * (failures to preserve mode/owner/times are not reported in exit code) */ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) { /* This is a recursive function, try to minimize stack usage */ /* NB: each struct stat is ~100 bytes */ struct stat source_stat; struct stat dest_stat; smallint retval = 0; smallint dest_exists = 0; smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { /* This may be a dangling symlink. * Making [sym]links to dangling symlinks works, so... */ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) goto make_links; bb_perror_msg("can't stat '%s'", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { bb_perror_msg("can't stat '%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino ) { bb_error_msg("'%s' and '%s' are the same file", source, dest); return -1; } dest_exists = 1; } #if ENABLE_SELINUX if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) { security_context_t con; if (lgetfilecon(source, &con) >= 0) { if (setfscreatecon(con) < 0) { bb_perror_msg("can't set setfscreatecon %s", con); freecon(con); return -1; } } else if (errno == ENOTSUP || errno == ENODATA) { setfscreatecon_or_die(NULL); } else { bb_perror_msg("can't lgetfilecon %s", source); return -1; } } #endif if (S_ISDIR(source_stat.st_mode)) { DIR *dp; const char *tp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { bb_error_msg("omitting directory '%s'", source); return -1; } /* Did we ever create source ourself before? */ tp = is_in_ino_dev_hashtable(&source_stat); if (tp) { /* We did! it's a recursion! man the lifeboats... */ bb_error_msg("recursion detected, omitting directory '%s'", source); return -1; } if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); return -1; } /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { /* Create DEST */ mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; /* Allow owner to access new dir (at least for now) */ mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); bb_perror_msg("can't create directory '%s'", dest); return -1; } umask(saved_umask); /* need stat info for add_to_ino_dev_hashtable */ if (lstat(dest, &dest_stat) < 0) { bb_perror_msg("can't stat '%s'", dest); return -1; } } /* remember (dev,inode) of each created dir. * NULL: name is not remembered */ add_to_ino_dev_hashtable(&dest_stat, NULL); /* Recursively copy files in SOURCE */ dp = opendir(source); if (dp == NULL) { retval = -1; goto preserve_mode_ugid_time; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; new_source = concat_subpath_file(source, d->d_name); if (new_source == NULL) continue; new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0) retval = -1; free(new_source); free(new_dest); } closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 ) { bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); /* retval = -1; - WRONG! copy *WAS* made */ } goto preserve_mode_ugid_time; } if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { int (*lf)(const char *oldpath, const char *newpath); make_links: /* Hmm... maybe * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ? * (but realpath returns NULL on dangling symlinks...) */ lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; if (lf(source, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (lf(source, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } /* _Not_ jumping to preserve_mode_ugid_time: * (sym)links don't have those */ return 0; } if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */ !(flags & FILEUTILS_RECUR) /* "cp [-opts] regular_file thing2" */ || S_ISREG(source_stat.st_mode) /* DEREF uses stat, which never returns S_ISLNK() == true. * So the below is never true: */ /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ ) { int src_fd; int dst_fd; mode_t new_mode; if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) { /* "cp -d symlink dst": create a link */ goto dont_cat; } if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { const char *link_target; link_target = is_in_ino_dev_hashtable(&source_stat); if (link_target) { if (link(link_target, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (link(link_target, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } return 0; } add_to_ino_dev_hashtable(&source_stat, dest); } src_fd = open_or_warn(source, O_RDONLY); if (src_fd < 0) return -1; /* Do not try to open with weird mode fields */ new_mode = source_stat.st_mode; if (!S_ISREG(source_stat.st_mode)) new_mode = 0666; // POSIX way is a security problem versus (sym)link attacks if (!ENABLE_FEATURE_NON_POSIX_CP) { dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); } else { /* safe way: */ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); } if (dst_fd == -1) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) { close(src_fd); return ovr; } /* It shouldn't exist. If it exists, do not open (symlink attack?) */ dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); if (dst_fd < 0) { close(src_fd); return -1; } } #if ENABLE_SELINUX if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT)) && is_selinux_enabled() > 0 ) { security_context_t con; if (getfscreatecon(&con) == -1) { bb_perror_msg("getfscreatecon"); return -1; } if (con) { if (setfilecon(dest, con) == -1) { bb_perror_msg("setfilecon:%s,%s", dest, con); freecon(con); return -1; } freecon(con); } } #endif if (bb_copyfd_eof(src_fd, dst_fd) == -1) retval = -1; /* Careful with writing... */ if (close(dst_fd) < 0) { bb_perror_msg("error writing to '%s'", dest); retval = -1; } /* ...but read size is already checked by bb_copyfd_eof */ close(src_fd); /* "cp /dev/something new_file" should not * copy mode of /dev/something */ if (!S_ISREG(source_stat.st_mode)) return retval; goto preserve_mode_ugid_time; } dont_cat: /* Source is a symlink or a special file */ /* We are lazy here, a bit lax with races... */ if (dest_exists) { errno = EEXIST; ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; } if (S_ISLNK(source_stat.st_mode)) { char *lpath = xmalloc_readlink_or_warn(source); if (lpath) { int r = symlink(lpath, dest); free(lpath); if (r < 0) { bb_perror_msg("can't create symlink '%s'", dest); return -1; } if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } /* _Not_ jumping to preserve_mode_ugid_time: * symlinks don't have those */ return 0; } if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ) { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { bb_perror_msg("can't create '%s'", dest); return -1; } } else { bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode); return -1; } preserve_mode_ugid_time: if (flags & FILEUTILS_PRESERVE_STATUS /* Cannot happen: */ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */ ) { struct timeval times[2]; times[1].tv_sec = times[0].tv_sec = 0; times[1].tv_usec = times[0].tv_usec = 0; /* BTW, utimes sets usec-precision time - just FYI */ if (utimes(dest, times) < 0) bb_perror_msg("can't preserve %s of '%s'", "times", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } if (chmod(dest, source_stat.st_mode) < 0) bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); } if (flags & FILEUTILS_VERBOSE) { printf("'%s' -> '%s'\n", source, dest); } return retval; }
int copy_file(const char *source, const char *dest, int flags) { struct stat source_stat; struct stat dest_stat; int dest_exists = 0; int status = 0; if ((!(flags & FILEUTILS_DEREFERENCE) && lstat(source, &source_stat) < 0) || ((flags & FILEUTILS_DEREFERENCE) && stat(source, &source_stat) < 0)) { bb_perror_msg("%s", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { bb_perror_msg("unable to stat `%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino) { bb_error_msg("`%s' and `%s' are the same file", source, dest); return -1; } dest_exists = 1; } if (S_ISDIR(source_stat.st_mode)) { DIR *dp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { bb_error_msg("%s: omitting directory", source); return -1; } /* Create DEST. */ if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("`%s' is not a directory", dest); return -1; } } else { mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); bb_perror_msg("cannot create directory `%s'", dest); return -1; } umask(saved_umask); } /* Recursively copy files in SOURCE. */ if ((dp = bb_opendir(source)) == NULL) { status = -1; goto preserve_status; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; new_source = concat_subpath_file(source, d->d_name); if(new_source == NULL) continue; new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags) < 0) status = -1; free(new_source); free(new_dest); } /* closedir have only EBADF error, but "dp" not changes */ closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { bb_perror_msg("unable to change permissions of `%s'", dest); status = -1; } } else if (S_ISREG(source_stat.st_mode) || (S_ISLNK(source_stat.st_mode) && (flags & FILEUTILS_DEREFERENCE))) { int src_fd; int dst_fd; if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { char *link_name; if (!(flags & FILEUTILS_DEREFERENCE) && is_in_ino_dev_hashtable(&source_stat, &link_name)) { if (link(link_name, dest) < 0) { bb_perror_msg("unable to link `%s'", dest); return -1; } return 0; } add_to_ino_dev_hashtable(&source_stat, dest); } src_fd = open(source, O_RDONLY); if (src_fd == -1) { bb_perror_msg("unable to open `%s'", source); return(-1); } if (dest_exists) { if (flags & FILEUTILS_INTERACTIVE) { fprintf(stderr, "%s: overwrite `%s'? ", bb_applet_name, dest); if (!bb_ask_confirmation()) { close (src_fd); return 0; } } dst_fd = open(dest, O_WRONLY|O_TRUNC); if (dst_fd == -1) { if (!(flags & FILEUTILS_FORCE)) { bb_perror_msg("unable to open `%s'", dest); close(src_fd); return -1; } if (unlink(dest) < 0) { bb_perror_msg("unable to remove `%s'", dest); close(src_fd); return -1; } goto dest_removed; } } else { dest_removed: dst_fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode); if (dst_fd == -1) { bb_perror_msg("unable to open `%s'", dest); close(src_fd); return(-1); } } if (bb_copyfd_eof(src_fd, dst_fd) == -1) status = -1; if (close(dst_fd) < 0) { bb_perror_msg("unable to close `%s'", dest); status = -1; } if (close(src_fd) < 0) { bb_perror_msg("unable to close `%s'", source); status = -1; } } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) || S_ISLNK(source_stat.st_mode)) { if (dest_exists) { if((flags & FILEUTILS_FORCE) == 0) { fprintf(stderr, "`%s' exists\n", dest); return -1; } if(unlink(dest) < 0) { bb_perror_msg("unable to remove `%s'", dest); return -1; } } if (S_ISFIFO(source_stat.st_mode)) { if (mkfifo(dest, source_stat.st_mode) < 0) { bb_perror_msg("cannot create fifo `%s'", dest); return -1; } } else if (S_ISLNK(source_stat.st_mode)) { char *lpath; lpath = xreadlink(source); if (symlink(lpath, dest) < 0) { bb_perror_msg("cannot create symlink `%s'", dest); return -1; } free(lpath); if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) bb_perror_msg("unable to preserve ownership of `%s'", dest); return 0; } else { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { bb_perror_msg("unable to create `%s'", dest); return -1; } } } else { bb_error_msg("internal error: unrecognized file type"); return -1; } preserve_status: if (flags & FILEUTILS_PRESERVE_STATUS) { struct utimbuf times; char *msg="unable to preserve %s of `%s'"; times.actime = source_stat.st_atime; times.modtime = source_stat.st_mtime; if (utime(dest, ×) < 0) bb_perror_msg(msg, "times", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); bb_perror_msg(msg, "ownership", dest); } if (chmod(dest, source_stat.st_mode) < 0) bb_perror_msg(msg, "permissions", dest); } return status; }
static void miss(NODE *p, char *tail) { int create; char *tp; const char *type; for (; p; p = p->next) { if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) continue; strcpy(tail, p->name); if (!(p->flags & F_VISIT)) { /* Don't print missing message if file exists as a symbolic link and the -q flag is set. */ struct stat statbuf; if (qflag && stat(path, &statbuf) == 0) p->flags |= F_VISIT; else printf("%s missing", path); } if (p->type != F_DIR && p->type != F_LINK) { putchar('\n'); continue; } create = 0; if (p->type == F_LINK) type = "symlink"; else type = "directory"; if (!(p->flags & F_VISIT) && uflag) { if (!(p->flags & (F_UID | F_UNAME))) printf(" (%s not created: user not specified)", type); else if (!(p->flags & (F_GID | F_GNAME))) printf(" (%s not created: group not specified)", type); else if (p->type == F_LINK) { if (symlink(p->slink, path)) printf(" (symlink not created: %s)\n", strerror(errno)); else printf(" (created)\n"); if (lchown(path, p->st_uid, p->st_gid)) printf("%s: user/group not modified: %s\n", path, strerror(errno)); continue; } else if (!(p->flags & F_MODE)) printf(" (directory not created: mode not specified)"); else if (mkdir(path, S_IRWXU)) printf(" (directory not created: %s)", strerror(errno)); else { create = 1; printf(" (created)"); } } if (!(p->flags & F_VISIT)) putchar('\n'); for (tp = tail; *tp; ++tp); *tp = '/'; miss(p->child, tp + 1); *tp = '\0'; if (!create) continue; if (chown(path, p->st_uid, p->st_gid)) { printf("%s: user/group/mode not modified: %s\n", path, strerror(errno)); printf("%s: warning: file mode %snot set\n", path, (p->flags & F_FLAGS) ? "and file flags " : ""); continue; } if (chmod(path, p->st_mode)) printf("%s: permissions not set: %s\n", path, strerror(errno)); if ((p->flags & F_FLAGS) && p->st_flags && chflags(path, p->st_flags)) printf("%s: file flags not set: %s\n", path, strerror(errno)); } }
void do_file_entry(const u8* base, const char* dir, const char* path, const char* name, int namelen, const struct cramfs_inode* inode) { int dirlen=strlen(dir); int pathlen=strlen(path); char pname[dirlen+pathlen+namelen+3]; const char* basename; if (dirlen) { strncpy(pname, dir, dirlen); } if (pathlen) { if (dirlen) { pname[dirlen]='/'; ++dirlen; } strncpy(pname+dirlen, path, pathlen); } if (namelen) { if (pathlen+dirlen) { pname[dirlen+pathlen]='/'; ++pathlen; } strncpy(pname+dirlen+pathlen, name, namelen); } pname[pathlen+dirlen+namelen]=0; basename=namelen ? pname+dirlen+pathlen : "/"; // Create things here printmode(inode); printuidgid(inode); if (S_ISREG(inode->mode)) { do_file(base, inode->offset<<2, inode->size, pname, basename, inode->mode); } else if (S_ISDIR(inode->mode)) { do_directory(base, inode->offset<<2, inode->size, pname, basename, inode->mode); } else if (S_ISLNK(inode->mode)) { do_symlink(base, inode->offset<<2, inode->size, pname, basename, inode->mode); } else if (S_ISFIFO(inode->mode)) { do_fifo(base, inode->offset<<2, inode->size, pname, basename, inode->mode, inode->uid, inode->gid); } else if (S_ISSOCK(inode->mode)) { do_socket(base, inode->offset<<2, inode->size, pname, basename, inode->mode); } else if (S_ISCHR(inode->mode)) { do_chrdev(base, inode->offset<<2, inode->size, pname, basename, inode->mode, inode->uid, inode->gid); } else if (S_ISBLK(inode->mode)) { do_blkdev(base, inode->offset<<2, inode->size, pname, basename, inode->mode, inode->uid, inode->gid); } else { do_unknown(base, inode->offset<<2, inode->size, pname, basename, inode->mode); } if (geteuid() == 0) { if (lchown(pname, inode->uid, inode->gid) == -1) perror("cannot change owner or group"); } else if(opt_idsfile && path && path[0]) { char dfp[1024]; char *p; FILE *f; strcpy(dfp,pname); p = strrchr(dfp,'/'); if (!p) { fprintf(stderr,"could not find path in '%s'\n",pname); return; } strcpy(p+1,opt_idsfile); f = fopen(dfp,"at"); if (!f) { perror(dfp); return; } fprintf(f,"%s,%u,%u,%08x\n",basename,inode->uid,inode->gid,inode->mode); fclose(f); } if (geteuid() == 0 || !opt_idsfile) { if (inode->mode & (S_ISGID|S_ISUID|S_ISVTX)) { if (0 != chmod(pname, inode->mode)){ perror("chmod"); return; } } } printf("\n"); }
static int local_symlink(FsContext *fs_ctx, const char *oldpath, V9fsPath *dir_path, const char *name, FsCred *credp) { int err = -1; int serrno = 0; char *newpath; V9fsString fullname; char *buffer = NULL; v9fs_string_init(&fullname); v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); newpath = fullname.data; /* Determine the security model */ if (fs_ctx->export_flags & V9FS_SM_MAPPED) { int fd; ssize_t oldpath_size, write_size; buffer = rpath(fs_ctx, newpath); fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); if (fd == -1) { err = fd; goto out; } /* Write the oldpath (target) to the file. */ oldpath_size = strlen(oldpath); do { write_size = write(fd, (void *)oldpath, oldpath_size); } while (write_size == -1 && errno == EINTR); if (write_size != oldpath_size) { serrno = errno; close(fd); err = -1; goto err_end; } close(fd); /* Set cleint credentials in symlink's xattr */ credp->fc_mode = credp->fc_mode|S_IFLNK; err = local_set_xattr(buffer, credp); if (err == -1) { serrno = errno; goto err_end; } } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { int fd; ssize_t oldpath_size, write_size; buffer = rpath(fs_ctx, newpath); fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); if (fd == -1) { err = fd; goto out; } /* Write the oldpath (target) to the file. */ oldpath_size = strlen(oldpath); do { write_size = write(fd, (void *)oldpath, oldpath_size); } while (write_size == -1 && errno == EINTR); if (write_size != oldpath_size) { serrno = errno; close(fd); err = -1; goto err_end; } close(fd); /* Set cleint credentials in symlink's xattr */ credp->fc_mode = credp->fc_mode|S_IFLNK; err = local_set_mapped_file_attr(fs_ctx, newpath, credp); if (err == -1) { serrno = errno; goto err_end; } } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { buffer = rpath(fs_ctx, newpath); err = symlink(oldpath, buffer); if (err) { goto out; } err = lchown(buffer, credp->fc_uid, credp->fc_gid); if (err == -1) { /* * If we fail to change ownership and if we are * using security model none. Ignore the error */ if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { serrno = errno; goto err_end; } else err = 0; } } goto out; err_end: remove(buffer); errno = serrno; out: g_free(buffer); v9fs_string_free(&fullname); return err; }
/* * routine: * do_like * * purpose: * to propagate ownership and protection changes between * one existing file and another. * * parameters: * file pointer * src/dst indication for who needs to change * whether or not to update statistics (there may be a copy and a like) * * returns: * error mask * * notes: * if we are called from reconcile, we should update * the statistics, but if we were called from do_copy * that routine will do the honors. */ errmask_t do_like(struct file *fp, side_t srcdst, bool_t do_stats) { char *dst; int rc = 0; int do_chown, do_chmod, do_chgrp, do_acls; errmask_t errs = 0; char *errstr = 0; struct base *bp; struct fileinfo *sp; struct fileinfo *dp; struct fileinfo *ip; extern int errno; bp = fp->f_base; /* see if this is a forbidden propagation */ if (srcdst == opt_oneway) { fp->f_flags |= F_CONFLICT; fp->f_problem = gettext(PROB_prohibited); bp->b_unresolved++; return (ERR_UNRESOLVED); } /* get info about source and target files */ if (srcdst == OPT_SRC) { sp = &fp->f_info[ OPT_DST ]; dp = &fp->f_info[ OPT_SRC ]; dst = srcname; } else { sp = &fp->f_info[ OPT_SRC ]; dp = &fp->f_info[ OPT_DST ]; dst = dstname; } ip = &fp->f_info[ OPT_BASE ]; /* figure out what needs fixing */ do_chmod = (sp->f_mode != dp->f_mode); do_chown = (sp->f_uid != dp->f_uid); do_chgrp = (sp->f_gid != dp->f_gid); do_acls = ((fp->f_srcdiffs|fp->f_dstdiffs) & D_FACLS); /* * try to anticipate things that we might not be able to * do, and return appropriate errorst if the calling user * cannot safely perform the requiested updates. */ if (my_uid != 0) { if (do_chown) errstr = gettext(PROB_chown); else if (my_uid != dp->f_uid) { if (do_chmod) errstr = gettext(PROB_chmod); else if (do_acls) errstr = gettext(PROB_chacl); else if (do_chgrp) errstr = gettext(PROB_chgrp); } #ifdef ACL_UID_BUG else if (do_acls && my_gid != dp->f_gid) errstr = gettext(PROB_botch); #endif if (errstr) { need_super = TRUE; /* if the user doesn't care, shine it on */ if (opt_everything == 0) return (0); /* if the user does care, return the error */ rc = -1; goto nogood; } } if (opt_debug & DBG_RECON) { fprintf(stderr, "RECO: do_like %s (", dst); if (do_chmod) fprintf(stderr, "chmod "); if (do_acls) fprintf(stderr, "acls "); if (do_chown) fprintf(stderr, "chown "); if (do_chgrp) fprintf(stderr, "chgrp "); fprintf(stderr, ")\n"); } if (do_chmod) { if (!opt_quiet) fprintf(stdout, "chmod %o %s\n", sp->f_mode, noblanks(dst)); #ifdef DBG_ERRORS /* should we simulate a chmod failure */ if (errno = dbg_chk_error(dst, 'p')) rc = -1; else #endif rc = opt_notouch ? 0 : chmod(dst, sp->f_mode); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_chmod %o -> %d(%d)\n", sp->f_mode, rc, errno); /* update dest and baseline to reflect the change */ if (rc == 0) { dp->f_mode = sp->f_mode; ip->f_mode = sp->f_mode; } else errstr = gettext(PROB_chmod); } /* * see if we need to fix the acls */ if (rc == 0 && do_acls) { if (!opt_quiet) fprintf(stdout, "setfacl %s %s\n", show_acls(sp->f_numacls, sp->f_acls), noblanks(dst)); #ifdef DBG_ERRORS /* should we simulate a set acl failure */ if (errno = dbg_chk_error(dst, 'a')) rc = -1; else #endif rc = opt_notouch ? 0 : set_acls(dst, sp); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_acls %d -> %d(%d)\n", sp->f_numacls, rc, errno); /* update dest and baseline to reflect the change */ if (rc == 0) { dp->f_numacls = sp->f_numacls; dp->f_acls = sp->f_acls; ip->f_numacls = sp->f_numacls; ip->f_acls = sp->f_acls; #ifdef ACL_UID_BUG /* SETFACL changes a file's UID/GID */ if (my_uid != dp->f_uid) { do_chown = 1; dp->f_uid = my_uid; } if (my_gid != dp->f_gid) { do_chgrp = 1; dp->f_gid = my_gid; } #endif } else if (errno == ENOSYS) { /* * if the file system doesn't support ACLs * we should just pretend we never saw them */ fprintf(stderr, gettext(WARN_noacls), dst); ip->f_numacls = 0; sp->f_numacls = 0; dp->f_numacls = 0; rc = 0; } else errstr = gettext(PROB_chacl); } /* * see if we need to fix the ownership */ if (rc == 0 && (do_chown || do_chgrp)) { if (do_chown) fprintf(stdout, "chown %ld %s; ", sp->f_uid, noblanks(dst)); if (do_chgrp) fprintf(stdout, "chgrp %ld %s", sp->f_gid, noblanks(dst)); fprintf(stdout, "\n"); #ifdef DBG_ERRORS /* should we simulate a chown failure */ if (errno = dbg_chk_error(dst, 'O')) rc = -1; else #endif rc = opt_notouch ? 0 : lchown(dst, sp->f_uid, sp->f_gid); if (opt_debug & DBG_RECON) fprintf(stderr, "RECO: do_chown %ld %ld -> %d(%d)\n", sp->f_uid, sp->f_gid, rc, errno); /* update the destination to reflect changes */ if (rc == 0) { dp->f_uid = sp->f_uid; dp->f_gid = sp->f_gid; ip->f_uid = sp->f_uid; ip->f_gid = sp->f_gid; } else { if (errno == EPERM) { need_super = TRUE; if (opt_everything == 0) return (0); } if (rc != 0) errstr = gettext(do_chown ? PROB_chown : PROB_chgrp); } } /* * if we were successful, we should make sure the other links * see the changes. If we were called from do_copy, we don't * want to do the link_updates either because do_copy will * handle them too. */ if (rc == 0 && do_stats) link_update(fp, srcdst); nogood: if (!do_stats) return (errs); if (rc != 0) { fprintf(stderr, gettext(ERR_cannot), errstr, dst); fp->f_problem = errstr; fp->f_flags |= F_CONFLICT; bp->b_unresolved++; errs |= ERR_PERM | ERR_UNRESOLVED; } else { /* * it worked, so update the baseline and statistics */ if (srcdst == OPT_SRC) bp->b_src_misc++; else bp->b_dst_misc++; fp->f_problem = 0; errs |= ERR_RESOLVABLE; } return (errs); }
int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid) { char src_name[1024]; char dst_name[1024]; char buf[1024]; int ifd; int ofd; int err = 0; int cnt; int set_orig = 0; struct DIRECT *ent; struct stat sb; struct link_name *lp; DIR *dir; /* * Make certain both directories exist. This routine is called * after the home directory is created, or recursively after the * target is created. It assumes the target directory exists. */ if (access (src_root, F_OK) != 0 || access (dst_root, F_OK) != 0) return -1; /* * Open the source directory and read each entry. Every file * entry in the directory is copied with the UID and GID set * to the provided values. As an added security feature only * regular files (and directories ...) are copied, and no file * is made set-ID. */ if (!(dir = opendir (src_root))) return -1; if (src_orig == 0) { src_orig = src_root; dst_orig = dst_root; set_orig++; } while ((ent = readdir (dir))) { /* * Skip the "." and ".." entries */ if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) continue; /* * Make the filename for both the source and the * destination files. */ if (strlen (src_root) + strlen (ent->d_name) + 2 > sizeof src_name) { err++; break; } snprintf (src_name, sizeof src_name, "%s/%s", src_root, ent->d_name); if (strlen (dst_root) + strlen (ent->d_name) + 2 > sizeof dst_name) { err++; break; } snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root, ent->d_name); if (LSTAT (src_name, &sb) == -1) continue; if (S_ISDIR (sb.st_mode)) { /* * Create a new target directory, make it owned by * the user and then recursively copy that directory. */ #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif mkdir (dst_name, sb.st_mode & 0777); chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid); if (copy_tree (src_name, dst_name, uid, gid)) { err++; break; } continue; } #ifdef S_IFLNK /* * Copy any symbolic links */ if (S_ISLNK (sb.st_mode)) { char oldlink[1024]; char dummy[1024]; int len; /* * Get the name of the file which the link points * to. If that name begins with the original * source directory name, that part of the link * name will be replaced with the original * destinateion directory name. */ if ((len = readlink (src_name, oldlink, sizeof (oldlink) - 1)) < 0) { err++; break; } oldlink[len] = '\0'; /* readlink() does not NUL-terminate */ if (!strncmp (oldlink, src_orig, strlen (src_orig))) { snprintf (dummy, sizeof dummy, "%s%s", dst_orig, oldlink + strlen (src_orig)); strcpy (oldlink, dummy); } #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif if (symlink (oldlink, dst_name) || lchown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid)) { err++; break; } continue; } #endif /* * See if this is a previously copied link */ if ((lp = check_link (src_name, &sb))) { if (link (lp->ln_name, dst_name)) { err++; break; } if (unlink (src_name)) { err++; break; } if (--lp->ln_count <= 0) remove_link (lp); continue; } /* * Deal with FIFOs and special files. The user really * shouldn't have any of these, but it seems like it * would be nice to copy everything ... */ if (!S_ISREG (sb.st_mode)) { #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) || chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid) || chmod (dst_name, sb.st_mode & 07777)) { err++; break; } continue; } /* * Create the new file and copy the contents. The new * file will be owned by the provided UID and GID values. */ if ((ifd = open (src_name, O_RDONLY)) < 0) { err++; break; } #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif if ((ofd = open (dst_name, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0 || chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid) || chmod (dst_name, sb.st_mode & 07777)) { close (ifd); err++; break; } while ((cnt = read (ifd, buf, sizeof buf)) > 0) { if (write (ofd, buf, cnt) != cnt) { cnt = -1; break; } } close (ifd); close (ofd); if (cnt == -1) { err++; break; } } closedir (dir); if (set_orig) { src_orig = 0; dst_orig = 0; } return err ? -1 : 0; }
/* * Copy a symlink. This only happens if we're in "no derefence" mode, * in which we copy the links rather than the files that are pointed at. * * We always discard the destination file. If it's a symlink already, * we want to throw it out and replace it. If it's not a symlink, we * need to trash it so we can create one. */ static int copySymlink(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options) { struct stat dstStat; char linkBuf[PATH_MAX+1]; int statResult, nameLen; assert(options & COPY_NO_DEREFERENCE); DBUG(("--- copying symlink '%s' to '%s'\n", src, dst)); /* NOTE: we use lstat() here */ statResult = lstat(dst, &dstStat); if (statResult == 0 && !S_ISREG(dstStat.st_mode) && !S_ISLNK(dstStat.st_mode) ) { fprintf(stderr, "acp: destination '%s' exists and is not regular or symlink\n", dst); return -1; } if (statResult == 0) { if (isSameFile(pSrcStat, &dstStat)) { fprintf(stderr, "acp: '%s' and '%s' are the same file\n", src, dst); return -1; } if (options & COPY_UPDATE_ONLY) { if (!isSourceNewer(pSrcStat, &dstStat)) { DBUG(("--- source is not newer: '%s'\n", src)); printNotNewerMsg(src, dst, options); return 0; } } } /* extract the symlink contents */ nameLen = readlink(src, linkBuf, sizeof(linkBuf)-1); if (nameLen <= 0) { fprintf(stderr, "acp: unable to read symlink '%s': %s\n", src, strerror(errno)); return -1; } linkBuf[nameLen] = '\0'; DBUG(("--- creating symlink file '%s' (--> %s)\n", dst, linkBuf)); if (statResult == 0) { DBUG(("--- removing '%s'\n", dst)); if (unlink(dst) != 0) { fprintf(stderr, "acp: unable to remove '%s': %s\n", dst, strerror(errno)); return -1; } } if (symlink(linkBuf, dst) != 0) { fprintf(stderr, "acp: unable to create symlink '%s' [%s]: %s\n", dst, linkBuf, strerror(errno)); return -1; } /* * There's no way to set the file date or access permissions, but * it is possible to set the owner. */ if (options & COPY_PERMISSIONS) { if (lchown(dst, pSrcStat->st_uid, pSrcStat->st_gid) != 0) DBUG(("--- lchown failed: %s\n", strerror(errno))); } printCopyMsg(src, dst, options); return 0; }
static int miss(NODE *p, char *tail) { int create; char *tp; const char *type, *what; int serr; int rval = 0; int rrval = 0; for (; p; p = p->next) { if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) continue; (void)strcpy(tail, p->name); if (!(p->flags & F_VISIT)) { /* Don't print missing message if file exists as a symbolic link and the -q flag is set. */ struct stat statbuf; if (qflag && stat(path, &statbuf) == 0) { p->flags |= F_VISIT; } else { (void)printf("%s missing", path); rval = MISMATCHEXIT; } } if (p->type != F_DIR && p->type != F_LINK) { putchar('\n'); continue; } create = 0; if (p->type == F_LINK) type = "symlink"; else type = "directory"; if (!(p->flags & F_VISIT) && uflag) { if (!(p->flags & (F_UID | F_UNAME))) (void)printf(" (%s not created: user not specified)", type); else if (!(p->flags & (F_GID | F_GNAME))) (void)printf(" (%s not created: group not specified)", type); else if (p->type == F_LINK) { if (symlink(p->slink, path)) (void)printf(" (symlink not created: %s)\n", strerror(errno)); else (void)printf(" (created)\n"); if (lchown(path, p->st_uid, p->st_gid) == -1) { serr = errno; if (p->st_uid == (uid_t)-1) what = "group"; else if (lchown(path, (uid_t)-1, p->st_gid) == -1) what = "user & group"; else { what = "user"; errno = serr; } (void)printf("%s: %s not modified: %s" "\n", path, what, strerror(errno)); } continue; } else if (!(p->flags & F_MODE)) (void)printf(" (directory not created: mode not specified)"); else if (mkdir(path, S_IRWXU)) (void)printf(" (directory not created: %s)", strerror(errno)); else { create = 1; (void)printf(" (created)"); } } if (!(p->flags & F_VISIT)) (void)putchar('\n'); for (tp = tail; *tp; ++tp); *tp = '/'; rrval = miss(p->child, tp + 1); if (rrval != 0) rval = rrval; *tp = '\0'; if (!create) continue; if (chown(path, p->st_uid, p->st_gid) == -1) { serr = errno; if (p->st_uid == (uid_t)-1) what = "group"; else if (chown(path, (uid_t)-1, p->st_gid) == -1) what = "user & group"; else { what = "user"; errno = serr; } (void)printf("%s: %s not modified: %s\n", path, what, strerror(errno)); } if (chmod(path, p->st_mode)) (void)printf("%s: permissions not set: %s\n", path, strerror(errno)); if ((p->flags & F_FLAGS) && p->st_flags && chflags(path, (u_int)p->st_flags)) (void)printf("%s: file flags not set: %s\n", path, strerror(errno)); } return rval; }
int copy_file(const char *source, const char *dest, int flags) { struct stat source_stat; struct stat dest_stat; int dest_exists = 0; int status = 0; if ((!(flags & FILEUTILS_PRESERVE_SYMLINKS) && lstat(source, &source_stat) < 0) || ((flags & FILEUTILS_PRESERVE_SYMLINKS) && stat(source, &source_stat) < 0)) { perror_msg("%s", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { perror_msg("unable to stat `%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino) { error_msg("`%s' and `%s' are the same file", source, dest); return -1; } dest_exists = 1; } if (S_ISDIR(source_stat.st_mode)) { DIR *dp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { error_msg("%s: omitting directory", source); return -1; } /* Create DEST. */ if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { error_msg("`%s' is not a directory", dest); return -1; } } else { mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); perror_msg("cannot create directory `%s'", dest); return -1; } umask(saved_umask); } /* Recursively copy files in SOURCE. */ if ((dp = opendir(source)) == NULL) { perror_msg("unable to open directory `%s'", source); status = -1; goto end; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) continue; new_source = concat_path_file(source, d->d_name); new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags) < 0) status = -1; free(new_source); free(new_dest); } /* closedir have only EBADF error, but "dp" not changes */ closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { perror_msg("unable to change permissions of `%s'", dest); status = -1; } } else if (S_ISREG(source_stat.st_mode)) { FILE *sfp, *dfp=NULL; #ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS char *link_name; if (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && is_in_ino_dev_hashtable(&source_stat, &link_name)) { if (link(link_name, dest) < 0) { perror_msg("unable to link `%s'", dest); return -1; } return 0; } #endif if ((sfp = wfopen(source, "r")) == NULL) { return -1; } if (dest_exists) { if (flags & FILEUTILS_INTERACTIVE) { fprintf(stderr, "%s: overwrite `%s'? ", applet_name, dest); if (!ask_confirmation()) { fclose (sfp); return 0; } } if ((dfp = fopen(dest, "w")) == NULL) { if (!(flags & FILEUTILS_FORCE)) { perror_msg("unable to open `%s'", dest); fclose (sfp); return -1; } if (unlink(dest) < 0) { perror_msg("unable to remove `%s'", dest); fclose (sfp); return -1; } dest_exists = 0; } } if (!dest_exists) { int fd; if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 || (dfp = fdopen(fd, "w")) == NULL) { if (fd >= 0) close(fd); perror_msg("unable to open `%s'", dest); fclose (sfp); return -1; } } if (copy_file_chunk(sfp, dfp, -1) < 0) status = -1; if (fclose(dfp) < 0) { perror_msg("unable to close `%s'", dest); status = -1; } if (fclose(sfp) < 0) { perror_msg("unable to close `%s'", source); status = -1; } } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) || S_ISLNK(source_stat.st_mode)) { if (dest_exists && ((flags & FILEUTILS_FORCE) == 0 || unlink(dest) < 0)) { perror_msg("unable to remove `%s'", dest); return -1; } } else { error_msg("internal error: unrecognized file type"); return -1; } if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode)) { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { perror_msg("unable to create `%s'", dest); return -1; } } else if (S_ISFIFO(source_stat.st_mode)) { if (mkfifo(dest, source_stat.st_mode) < 0) { perror_msg("cannot create fifo `%s'", dest); return -1; } } else if (S_ISLNK(source_stat.st_mode)) { char *lpath; lpath = xreadlink(source); if (symlink(lpath, dest) < 0) { perror_msg("cannot create symlink `%s'", dest); return -1; } free(lpath); #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) perror_msg("unable to preserve ownership of `%s'", dest); #endif #ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS add_to_ino_dev_hashtable(&source_stat, dest); #endif return 0; } #ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS add_to_ino_dev_hashtable(&source_stat, dest); #endif end: if (flags & FILEUTILS_PRESERVE_STATUS) { struct utimbuf times; times.actime = source_stat.st_atime; times.modtime = source_stat.st_mtime; if (utime(dest, ×) < 0) perror_msg("unable to preserve times of `%s'", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); perror_msg("unable to preserve ownership of `%s'", dest); } if (chmod(dest, source_stat.st_mode) < 0) perror_msg("unable to preserve permissions of `%s'", dest); } return status; }
int __lchown (const char *file, uid_t owner, gid_t group) { return lchown (file, owner, group); }
int attribs_set(struct asfd *asfd, const char *path, struct stat *statp, uint64_t winattr, struct conf *conf) { struct utimbuf ut; ut.actime=statp->st_atime; ut.modtime=statp->st_mtime; #ifdef HAVE_WIN32 win32_chmod(path, statp->st_mode, winattr); set_file_times(asfd, path, &ut, statp, conf); return 0; #endif /* ***FIXME**** optimize -- don't do if already correct */ /* * For link, change owner of link using lchown, but don't * try to do a chmod as that will update the file behind it. */ /* Watch out, a metadata restore will have cmd set to CMD_METADATA or CMD_ENC_META, but that is OK at the moment because we are not doing meta stuff on links. */ if(S_ISLNK(statp->st_mode)) { // Change owner of link, not of real file. if(lchown(path, statp->st_uid, statp->st_gid)<0) { berrno be; berrno_init(&be); logw(asfd, conf, "Unable to set file owner %s: ERR=%s", path, berrno_bstrerror(&be, errno)); return -1; } } else { if(chown(path, statp->st_uid, statp->st_gid)<0) { berrno be; berrno_init(&be); logw(asfd, conf, "Unable to set file owner %s: ERR=%s", path, berrno_bstrerror(&be, errno)); return -1; } if(chmod(path, statp->st_mode) < 0) { berrno be; berrno_init(&be); logw(asfd, conf, "Unable to set file modes %s: ERR=%s", path, berrno_bstrerror(&be, errno)); return -1; } if(set_file_times(asfd, path, &ut, statp, conf)) return -1; #ifdef HAVE_CHFLAGS /* * FreeBSD user flags * * Note, this should really be done before the utime() above, * but if the immutable bit is set, it will make the utimes() * fail. */ if(chflags(path, statp->st_flags)<0) { berrno be; berrno_init(&be); logw(conf, "Unable to set file flags %s: ERR=%s", path, berrno_bstrerror(&be, errno)); return -1; } #endif } return 0; }
bool set_attributes(const char *path, char cmd, struct stat *statp, int64_t winattr, struct cntr *cntr) { struct utimbuf ut; bool ok = true; ut.actime = statp->st_atime; ut.modtime = statp->st_mtime; #ifdef HAVE_WIN32 win32_chmod(path, statp->st_mode, winattr); set_file_times(path, &ut, statp, cntr); return true; #endif /* ***FIXME**** optimize -- don't do if already correct */ /* * For link, change owner of link using lchown, but don't * try to do a chmod as that will update the file behind it. */ /* watch out, a metadata restore will have cmd set to CMD_METADATA or CMD_ENC_META, but that is OK at the moment because we are not doing meta stuff on links. */ if (cmd==CMD_SOFT_LINK) { /* Change owner of link, not of real file */ if (lchown(path, statp->st_uid, statp->st_gid) < 0) { berrno be; logw(cntr, "Unable to set file owner %s: ERR=%s", path, be.bstrerror()); ok = false; } } else { if (chown(path, statp->st_uid, statp->st_gid) < 0) { berrno be; logw(cntr, "Unable to set file owner %s: ERR=%s", path, be.bstrerror()); ok = false; } if (chmod(path, statp->st_mode) < 0) { berrno be; logw(cntr, "Unable to set file modes %s: ERR=%s", path, be.bstrerror()); ok = false; } if(set_file_times(path, &ut, statp, cntr)) ok=false; #ifdef HAVE_CHFLAGS /* * FreeBSD user flags * * Note, this should really be done before the utime() above, * but if the immutable bit is set, it will make the utimes() * fail. */ if (chflags(path, statp->st_flags) < 0) { berrno be; logw(cntr, "Unable to set file flags %s: ERR=%s", path, be.bstrerror()); ok = false; } #endif } return ok; }
int main(int argc, char **argv) { char * base = uninit; char * bp = uninit; char * cp = uninit; char * cwd = 0; char * group = 0; char * linkname = 0; char * linkprefix = 0; char * name = uninit; char * owner = 0; char * todir = uninit; char * toname = uninit; int bnlen = -1; int cc = 0; int dodir = 0; int dolink = 0; int dorelsymlink = 0; int dotimes = 0; int exists = 0; int fromfd = -1; int len = -1; int lplen = 0; int onlydir = 0; int opt = -1; int tdlen = -1; int tofd = -1; int wc = -1; mode_t mode = 0755; uid_t uid = -1; gid_t gid = -1; struct stat sb; struct stat tosb; struct utimbuf utb; char buf[BUFSIZ]; program = strrchr(argv[0], '/'); if (!program) program = strrchr(argv[0], '\\'); program = program ? program+1 : argv[0]; while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { switch (opt) { case 'C': cwd = optarg; break; case 'D': onlydir = 1; break; case 'd': dodir = 1; break; case 'l': dolink = 1; break; case 'L': linkprefix = optarg; lplen = strlen(linkprefix); dolink = 1; break; case 'R': dolink = dorelsymlink = 1; break; case 'm': mode = strtoul(optarg, &cp, 8); if (mode == 0 && cp == optarg) usage(); break; case 'o': owner = optarg; break; case 'g': group = optarg; break; case 't': dotimes = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 2 - onlydir) usage(); todir = argv[argc-1]; if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && mkdirs(todir, 0777) < 0) { fail("cannot mkdir -p %s", todir); } if (onlydir) return 0; if (!cwd) { cwd = GETCWD(0, PATH_MAX); if (!cwd) fail("could not get CWD"); } /* make sure we can get into todir. */ xchdir(todir); todir = GETCWD(0, PATH_MAX); if (!todir) fail("could not get CWD in todir"); tdlen = strlen(todir); /* back to original directory. */ xchdir(cwd); uid = owner ? touid(owner) : -1; gid = group ? togid(group) : -1; while (--argc > 0) { name = *argv++; len = strlen(name); base = xbasename(name); bnlen = strlen(base); toname = (char*)xmalloc(tdlen + 1 + bnlen + 1); sprintf(toname, "%s/%s", todir, base); retry: exists = (lstat(toname, &tosb) == 0); if (dodir) { /* -d means create a directory, always */ if (exists && !S_ISDIR(tosb.st_mode)) { int rv = unlink(toname); if (rv) fail("cannot unlink %s", toname); exists = 0; } if (!exists && mkdir(toname, mode) < 0) { /* we probably have two nsinstall programs in a race here. */ if (errno == EEXIST && !stat(toname, &sb) && S_ISDIR(sb.st_mode)) { fprintf(stderr, "directory creation race: %s\n", toname); goto retry; } fail("cannot make directory %s", toname); } if ((owner || group) && chown(toname, uid, gid) < 0) fail("cannot change owner of %s", toname); } else if (dolink) { if (*name == '/') { /* source is absolute pathname, link to it directly */ linkname = 0; } else { if (linkprefix) { /* -L implies -l and prefixes names with a $cwd arg. */ len += lplen + 1; linkname = (char*)xmalloc(len + 1); sprintf(linkname, "%s/%s", linkprefix, name); } else if (dorelsymlink) { /* Symlink the relative path from todir to source name. */ linkname = (char*)xmalloc(PATH_MAX); if (*todir == '/') { /* todir is absolute: skip over common prefix. */ lplen = relatepaths(todir, cwd, linkname); strcpy(linkname + lplen, name); } else { /* todir is named by a relative path: reverse it. */ reversepath(todir, name, len, linkname); xchdir(cwd); } len = strlen(linkname); } name = linkname; } /* Check for a pre-existing symlink with identical content. */ if (exists && (!S_ISLNK(tosb.st_mode) || readlink(toname, buf, sizeof buf) != len || strncmp(buf, name, len) != 0)) { int rmrv; rmrv = (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); if (rmrv < 0) { fail("destination exists, cannot remove %s", toname); } exists = 0; } if (!exists && symlink(name, toname) < 0) { if (errno == EEXIST) { fprintf(stderr, "symlink creation race: %s\n", toname); fail("symlink was attempted in working directory %s " "from %s to %s.\n", cwd, name, toname); goto retry; } diagnosePath(toname); fail("cannot make symbolic link %s", toname); } #ifdef HAVE_LCHOWN if ((owner || group) && lchown(toname, uid, gid) < 0) fail("cannot change owner of %s", toname); #endif if (linkname) { free(linkname); linkname = 0; } } else { /* Copy from name to toname, which might be the same file. */ fromfd = open(name, O_RDONLY); if (fromfd < 0 || fstat(fromfd, &sb) < 0) fail("cannot access %s", name); if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0)) { int rmrv; rmrv = (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); if (rmrv < 0) { fail("destination exists, cannot remove %s", toname); } } tofd = open(toname, O_CREAT | O_WRONLY, 0666); if (tofd < 0) fail("cannot create %s", toname); bp = buf; while ((cc = read(fromfd, bp, sizeof buf)) > 0) { while ((wc = write(tofd, bp, cc)) > 0) { if ((cc -= wc) == 0) break; bp += wc; } if (wc < 0) fail("cannot write to %s", toname); } if (cc < 0) fail("cannot read from %s", name); if (ftruncate(tofd, sb.st_size) < 0) fail("cannot truncate %s", toname); /* ** On OpenVMS we can't chmod() until the file is closed, and we ** have to utime() last since fchown/chmod alter the timestamps. */ #ifndef VMS if (dotimes) { utb.actime = sb.st_atime; utb.modtime = sb.st_mtime; if (utime(toname, &utb) < 0) fail("cannot set times of %s", toname); } #ifdef HAVE_FCHMOD if (fchmod(tofd, mode) < 0) #else if (chmod(toname, mode) < 0) #endif fail("cannot change mode of %s", toname); #endif if ((owner || group) && fchown(tofd, uid, gid) < 0) fail("cannot change owner of %s", toname); /* Must check for delayed (NFS) write errors on close. */ if (close(tofd) < 0) fail("close reports write error on %s", toname); close(fromfd); #ifdef VMS if (chmod(toname, mode) < 0) fail("cannot change mode of %s", toname); if (dotimes) { utb.actime = sb.st_atime; utb.modtime = sb.st_mtime; if (utime(toname, &utb) < 0) fail("cannot set times of %s", toname); } #endif } free(toname); } free(cwd); free(todir); return 0; }
int setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; int rval, gotstat, islink, fdval; rval = 0; fdval = fd != -1; islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim); if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; } /* * Changing the ownership probably won't succeed, unless we're root * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting * the mode; current BSD behavior is to remove all setuid bits on * chown. If chown fails, lose setuid/setgid bits. */ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) if (fdval ? fchmod(fd, fs->st_mode) : (islink ? lchmod(to.p_path, fs->st_mode) : chmod(to.p_path, fs->st_mode))) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) if (fdval ? fchflags(fd, fs->st_flags) : (islink ? lchflags(to.p_path, fs->st_flags) : chflags(to.p_path, fs->st_flags))) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); }
int extractfile(char *name) { int flags; uid_t uid; gid_t gid; mode_t mode; struct timeval timep[2]; struct entry *ep; curfile.name = name; curfile.action = USING; timep[0].tv_sec = curfile.dip->di_atime; timep[0].tv_usec = curfile.dip->di_atimensec / 1000; timep[1].tv_sec = curfile.dip->di_mtime; timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; uid = curfile.dip->di_uid; gid = curfile.dip->di_gid; mode = curfile.dip->di_mode; flags = curfile.dip->di_flags; switch (mode & IFMT) { default: fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); skipfile(); return (FAIL); case IFSOCK: vprintf(stdout, "skipped socket %s\n", name); skipfile(); return (GOOD); case IFDIR: if (mflag) { ep = lookupname(name); if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } vprintf(stdout, "extract file %s\n", name); return (genliteraldir(name, curfile.ino)); case IFLNK: lnkbuf[0] = '\0'; pathlen = 0; getfile(xtrlnkfile, xtrlnkskip); if (pathlen == 0) { vprintf(stdout, "%s: zero length symbolic link (ignored)\n", name); return (GOOD); } if (linkit(lnkbuf, name, SYMLINK) == GOOD) { lchown(name, uid, gid); lchmod(name, mode); lutimes(name, timep); return (GOOD); } return (FAIL); case IFIFO: vprintf(stdout, "extract fifo %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag && !Nflag) unlink(name); if (mkfifo(name, mode) < 0) { fprintf(stderr, "%s: cannot create fifo: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } chown(name, uid, gid); chmod(name, mode); utimes(name, timep); chflags(name, flags); skipfile(); return (GOOD); case IFCHR: case IFBLK: vprintf(stdout, "extract special file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) unlink(name); if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { fprintf(stderr, "%s: cannot create special file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } chown(name, uid, gid); chmod(name, mode); utimes(name, timep); chflags(name, flags); skipfile(); return (GOOD); case IFREG: vprintf(stdout, "extract file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) unlink(name); if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { fprintf(stderr, "%s: cannot create file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } fchown(ofile, uid, gid); fchmod(ofile, mode); getfile(xtrfile, xtrskip); close(ofile); utimes(name, timep); chflags(name, flags); return (GOOD); } /* NOTREACHED */ }
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; }
int main(int argc, char *argv[]) { struct stat stat_buf; int lc; char *msg; int i; if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { Tst_count = 0; for (i = 0; test_cases[i].desc != NULL; i++) { uid_t user_id = test_cases[i].user_id; gid_t group_id = test_cases[i].group_id; char *test_desc = test_cases[i].desc; /* * Call lchown(2) with different user id and * group id (numeric values) to set it on * symlink of testfile. */ TEST(lchown(SFILE, user_id, group_id)); if (TEST_RETURN == -1) { tst_resm(TFAIL, "lchown() Fails to %s, errno %d", test_desc, TEST_ERRNO); continue; } /* * Perform functional verification if test * executed without (-f) option. */ if (STD_FUNCTIONAL_TEST) { /* * Get the testfile information using * lstat(2). */ if (lstat(SFILE, &stat_buf) < 0) { tst_brkm(TFAIL, cleanup, "lstat(2) " "%s failed, errno %d", SFILE, TEST_ERRNO); } if (user_id == -1) { if (i > 0) user_id = test_cases[i-1].user_id; else user_id = geteuid(); } if (group_id == -1) { if (i > 0) group_id = test_cases[i-1].group_id; else group_id = getegid(); } /* * Check for expected Ownership ids * set on testfile. */ if ((stat_buf.st_uid != user_id) || (stat_buf.st_gid != group_id)) { tst_resm(TFAIL, "%s: incorrect ownership set, " "Expected %d %d", SFILE, user_id, group_id); } else { tst_resm(TPASS, "lchown() succeeds to " "%s of %s", test_desc, SFILE); } } else { tst_resm(TPASS, "call succeeded"); } } } cleanup(); tst_exit(); }
extern 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), 0777, 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 seperately * 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"); } } lchown(file_header->name, file_header->uid, file_header->gid); if ((file_header->mode & S_IFMT) != S_IFLNK) { chmod(file_header->name, file_header->mode); } if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { struct utimbuf t; t.actime = t.modtime = file_header->mtime; utime(file_header->name, &t); } }
int main(int argc, char **argv) { FTS *ftsp; FTSENT *p; int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval; char *cp; myname = (cp = strrchr(*argv, '/')) ? cp + 1 : *argv; ischown = myname[2] == 'o'; Hflag = Lflag = Pflag = hflag = vflag = 0; while ((ch = getopt(argc, argv, "HLPRfhv")) != -1) switch (ch) { case 'H': Hflag = 1; Lflag = Pflag = 0; break; case 'L': Lflag = 1; Hflag = Pflag = 0; break; case 'P': Pflag = 1; Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; case 'f': fflag = 1; break; case 'h': hflag = 1; break; case 'v': vflag++; break; default: usage(); } argv += optind; argc -= optind; if (argc < 2) usage(); fts_options = FTS_PHYSICAL; if (Rflag) { if (hflag && (Lflag || Hflag)) errx(1, "the -R and -h options may not be specified together"); if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } } uid = gid = -1; if (ischown) { if ((cp = strchr(*argv, ':')) != NULL) { *cp++ = '\0'; a_gid(cp); } #ifdef SUPPORT_DOT else if ((cp = strchr(*argv, '.')) != NULL) { warnx("separation of user and group with a period is deprecated"); *cp++ = '\0'; a_gid(cp); } #endif a_uid(*argv); } else a_gid(*argv); if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) err(1, NULL); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { case FTS_D: /* Change it at FTS_DP. */ if (!Rflag) fts_set(ftsp, p, FTS_SKIP); continue; case FTS_DNR: /* Warn, chown, continue. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; case FTS_ERR: /* Warn, continue. */ case FTS_NS: warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; continue; case FTS_SL: /* Ignore. */ case FTS_SLNONE: /* * The only symlinks that end up here are ones that * don't point to anything and ones that we found * doing a physical walk. */ if (hflag) break; else continue; default: break; } if ((uid == (uid_t)(-1) || uid == p->fts_statp->st_uid) && (gid == (gid_t)(-1) || gid == p->fts_statp->st_gid)) continue; if (hflag) { if (lchown(p->fts_accpath, uid, gid) && !fflag) { chownerr(p->fts_path); rval = 1; } else { if (vflag) printf("%s\n", p->fts_accpath); } } else { if (chown(p->fts_accpath, uid, gid) && !fflag) { chownerr(p->fts_path); rval = 1; } else { if (vflag) { printf("%s", p->fts_accpath); if (vflag > 1) { if (ischown) { printf(": %d:%d -> %d:%d", (int)p->fts_statp->st_uid, (int)p->fts_statp->st_gid, (uid == (uid_t)-1) ? (int)p->fts_statp->st_uid : (int)uid, (gid == (gid_t)-1) ? (int) p->fts_statp->st_gid : (int)gid); } else { printf(": %d -> %d", (int)p->fts_statp->st_gid, (gid == (gid_t)-1) ? (int)p->fts_statp->st_gid : (int)gid); } } printf("\n"); } } } } if (errno) err(1, "fts_read"); exit(rval); }
static unsigned int call_syscall(struct syscall_desc *scall, char *argv[]) { struct stat64 sb; long long flags; unsigned int i; char *endp; int name, rval; union { char *str; long long num; } args[MAX_ARGS]; #ifdef HAS_FREEBSD_ACL int entry_id = ACL_FIRST_ENTRY; acl_t acl, newacl; acl_entry_t entry, newentry; #endif /* * Verify correctness of the arguments. */ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { if (scall->sd_args[i] == TYPE_NONE) { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) break; fprintf(stderr, "too many arguments [%s]\n", argv[i]); exit(1); } else { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { if (scall->sd_args[i] & TYPE_OPTIONAL) break; fprintf(stderr, "too few arguments\n"); exit(1); } if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) { if (strcmp(argv[i], "NULL") == 0) args[i].str = NULL; else if (strcmp(argv[i], "DEADCODE") == 0) args[i].str = (void *)0xdeadc0de; else args[i].str = argv[i]; } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) { args[i].num = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) { if (strcmp(argv[i], "AT_FDCWD") == 0) { args[i].num = AT_FDCWD; } else if (strcmp(argv[i], "BADFD") == 0) { /* In case AT_FDCWD is -1 on some systems... */ if (AT_FDCWD == -1) args[i].num = -2; else args[i].num = -1; } else { int pos; pos = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } args[i].num = descriptor_get(pos); } } } } /* * Call the given syscall. */ #define NUM(n) (args[(n)].num) #define STR(n) (args[(n)].str) switch (scall->sd_action) { case ACTION_OPEN: flags = str2flags(open_flags, STR(1)); if (flags & O_CREAT) { if (i == 2) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = open(STR(0), (int)flags, (mode_t)NUM(2)); } else { if (i == 3) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = open(STR(0), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_OPENAT: flags = str2flags(open_flags, STR(2)); if (flags & O_CREAT) { if (i == 3) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags, (mode_t)NUM(3)); } else { if (i == 4) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_CREATE: rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1)); if (rval >= 0) close(rval); break; case ACTION_UNLINK: rval = unlink(STR(0)); break; case ACTION_UNLINKAT: rval = unlinkat(NUM(0), STR(1), (int)str2flags(unlinkat_flags, STR(2))); break; case ACTION_MKDIR: rval = mkdir(STR(0), (mode_t)NUM(1)); break; case ACTION_MKDIRAT: rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_RMDIR: rval = rmdir(STR(0)); break; case ACTION_LINK: rval = link(STR(0), STR(1)); break; case ACTION_LINKAT: rval = linkat(NUM(0), STR(1), NUM(2), STR(3), (int)str2flags(linkat_flags, STR(4))); break; case ACTION_SYMLINK: rval = symlink(STR(0), STR(1)); break; case ACTION_SYMLINKAT: rval = symlinkat(STR(0), NUM(1), STR(2)); break; case ACTION_RENAME: rval = rename(STR(0), STR(1)); break; case ACTION_RENAMEAT: rval = renameat(NUM(0), STR(1), NUM(2), STR(3)); break; case ACTION_MKFIFO: rval = mkfifo(STR(0), (mode_t)NUM(1)); break; case ACTION_MKFIFOAT: rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_MKNOD: case ACTION_MKNODAT: { mode_t ntype; dev_t dev; int fa; switch (scall->sd_action) { case ACTION_MKNOD: fa = 0; break; case ACTION_MKNODAT: fa = 1; break; default: abort(); } dev = makedev(NUM(fa + 3), NUM(fa + 4)); if (strcmp(STR(fa + 1), "c") == 0) /* character device */ ntype = S_IFCHR; else if (strcmp(STR(fa + 1), "b") == 0) /* block device */ ntype = S_IFBLK; else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */ ntype = S_IFIFO; else if (strcmp(STR(fa + 1), "d") == 0) /* directory */ ntype = S_IFDIR; else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */ ntype = S_IFREG; else { fprintf(stderr, "wrong argument 1\n"); exit(1); } switch (scall->sd_action) { case ACTION_MKNOD: rval = mknod(STR(0), ntype | NUM(2), dev); break; case ACTION_MKNODAT: rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev); break; default: abort(); } break; } case ACTION_BIND: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_BINDAT case ACTION_BINDAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CONNECT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_CONNECTAT case ACTION_CONNECTAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CHMOD: rval = chmod(STR(0), (mode_t)NUM(1)); break; case ACTION_FCHMOD: rval = fchmod(NUM(0), (mode_t)NUM(1)); break; #ifdef HAS_LCHMOD case ACTION_LCHMOD: rval = lchmod(STR(0), (mode_t)NUM(1)); break; #endif case ACTION_FCHMODAT: rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2), str2flags(fchmodat_flags, STR(3))); break; case ACTION_CHOWN: rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWN: rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_LCHOWN: rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWNAT: rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3), (int)str2flags(fchownat_flags, STR(4))); break; #ifdef HAS_CHFLAGS case ACTION_CHFLAGS: rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_FCHFLAGS case ACTION_FCHFLAGS: rval = fchflags(NUM(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_CHFLAGSAT case ACTION_CHFLAGSAT: rval = chflagsat(NUM(0), STR(1), (unsigned long)str2flags(chflags_flags, STR(2)), (int)str2flags(chflagsat_flags, STR(3))); break; #endif #ifdef HAS_LCHFLAGS case ACTION_LCHFLAGS: rval = lchflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif case ACTION_TRUNCATE: rval = truncate64(STR(0), NUM(1)); break; case ACTION_FTRUNCATE: rval = ftruncate64(NUM(0), NUM(1)); break; case ACTION_STAT: rval = stat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTAT: rval = fstat64(NUM(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_LSTAT: rval = lstat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTATAT: rval = fstatat(NUM(0), STR(1), &sb, (int)str2flags(fstatat_flags, STR(2))); if (rval == 0) { show_stats(&sb, STR(3)); return (i); } break; case ACTION_PATHCONF: case ACTION_FPATHCONF: case ACTION_LPATHCONF: { long lrval; name = str2name(pathconf_names, STR(1)); if (name == -1) { fprintf(stderr, "unknown name %s", STR(1)); exit(1); } errno = 0; switch (scall->sd_action) { case ACTION_PATHCONF: lrval = pathconf(STR(0), name); break; case ACTION_FPATHCONF: lrval = fpathconf(NUM(0), name); break; case ACTION_LPATHCONF: lrval = lpathconf(STR(0), name); break; default: abort(); } if (lrval == -1 && errno == 0) { printf("unlimited\n"); return (i); } else if (lrval >= 0) { printf("%ld\n", lrval); return (i); } rval = -1; break; } #ifdef HAS_FREEBSD_ACL case ACTION_PREPENDACL: rval = -1; acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) break; newacl = acl_from_text(STR(1)); if (acl == NULL) break; while (acl_get_entry(newacl, entry_id, &newentry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_create_entry_np(&acl, &entry, 0)) break; if (acl_copy_entry(entry, newentry)) break; } rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl); break; case ACTION_READACL: acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) rval = -1; else rval = 0; break; #endif case ACTION_WRITE: rval = write(NUM(0), STR(1), strlen(STR(1))); break; default: fprintf(stderr, "unsupported syscall\n"); exit(1); } #undef STR #undef NUM if (rval < 0) { const char *serrno; serrno = err2str(errno); fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); printf("%s\n", serrno); exit(1); } printf("0\n"); return (i); }
void set_file_attributes (char const *to, enum file_attributes attr, char const *from, const struct stat *st, mode_t mode, struct timespec *new_time) { if (attr & FA_TIMES) { struct timespec times[2]; if (new_time) times[0] = times[1] = *new_time; else { times[0] = get_stat_atime (st); times[1] = get_stat_mtime (st); } if (lutimens (to, times) != 0) pfatal ("Failed to set the timestamps of %s %s", S_ISLNK (mode) ? "symbolic link" : "file", quotearg (to)); } if (attr & FA_IDS) { static uid_t euid = -1; static gid_t egid = -1; uid_t uid; uid_t gid; if (euid == -1) { euid = geteuid (); egid = getegid (); } uid = (euid == st->st_uid) ? -1 : st->st_uid; gid = (egid == st->st_gid) ? -1 : st->st_gid; /* May fail if we are not privileged to set the file owner, or we are not in group instat.st_gid. Ignore those errors. */ if ((uid != -1 || gid != -1) && lchown (to, uid, gid) != 0 && (errno != EPERM || (uid != -1 && lchown (to, (uid = -1), gid) != 0 && errno != EPERM))) pfatal ("Failed to set the %s of %s %s", (uid == -1) ? "owner" : "owning group", S_ISLNK (mode) ? "symbolic link" : "file", quotearg (to)); } if (attr & FA_XATTRS) if (copy_attr (from, to)) fatal_exit (0); /* FIXME: There may be other attributes to preserve. */ if (attr & FA_MODE) { #if 0 && defined HAVE_LCHMOD /* The "diff --git" format does not store the file permissions of symlinks, so don't try to set symlink file permissions even on systems where we could. */ if (lchmod (to, mode)) #else if (! S_ISLNK (mode) && chmod (to, mode) != 0) #endif pfatal ("Failed to set the permissions of %s %s", S_ISLNK (mode) ? "symbolic link" : "file", quotearg (to)); } }
int create_inode(char *pathname, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk) { long long start = sBlk->inode_table_start + start_block; squashfs_inode_header header; char *block_ptr; int bytes = lookup_entry(inode_table_hash, start), file_fd; TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset); if(bytes == -1) { ERROR("create_inode: inode block 0x%llx out of range!\n", start); return FALSE; } block_ptr = inode_table + bytes + offset; if(swap) { squashfs_base_inode_header sinode; memcpy(&sinode, block_ptr, sizeof(header.base)); SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header)); } else memcpy(&header.base, block_ptr, sizeof(header.base)); if(created_inode[header.base.inode_number - 1]) { TRACE("create_inode: hard link\n"); if(link(created_inode[header.base.inode_number - 1], pathname) == -1) { ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno)); return FALSE; } return TRUE; } switch(header.base.inode_type) { case SQUASHFS_FILE_TYPE: { unsigned int frag_bytes; unsigned int blocks; unsigned int offset; long long start; squashfs_reg_inode_header *inode = &header.reg; if(swap) { squashfs_reg_inode_header sinode; memcpy(&sinode, block_ptr, sizeof(sinode)); SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(*inode)); frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size; offset = inode->offset; blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >> sBlk->block_log; start = inode->start_block; TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start, block_ptr + sizeof(*inode), inode->mode)) { set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE); file_count ++; } break; } case SQUASHFS_LREG_TYPE: { unsigned int frag_bytes; unsigned int blocks; unsigned int offset; long long start; squashfs_lreg_inode_header *inode = &header.lreg; if(swap) { squashfs_lreg_inode_header sinode; memcpy(&sinode, block_ptr, sizeof(sinode)); SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(*inode)); frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size; offset = inode->offset; blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >> sBlk->block_log; start = inode->start_block; TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start, block_ptr + sizeof(*inode), inode->mode)) { set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE); file_count ++; } break; } case SQUASHFS_SYMLINK_TYPE: { squashfs_symlink_inode_header *inodep = &header.symlink; char name[65536]; if(swap) { squashfs_symlink_inode_header sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size); strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size); name[inodep->symlink_size] = '\0'; if(symlink(name, pathname) == -1) { ERROR("create_inode: failed to create symlink %s, because %s\n", pathname, strerror(errno)); break; } if(geteuid() == 0) { uid_t uid_value = (uid_t) uid_table[inodep->uid]; uid_t guid_value = inodep->guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[inodep->guid]; if(lchown(pathname, uid_value, guid_value) == -1) ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); } sym_count ++; break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: { squashfs_dev_inode_header *inodep = &header.dev; if(swap) { squashfs_dev_inode_header sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev); if(geteuid() == 0) { if(mknod(pathname, inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? S_IFCHR : S_IFBLK, makedev((inodep->rdev >> 8) & 0xff, inodep->rdev & 0xff)) == -1) { ERROR("create_inode: failed to create %s device %s, because %s\n", inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", pathname, strerror(errno)); break; } set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, inodep->mtime, TRUE); dev_count ++; } else ERROR("create_inode: could not create %s device %s, because you're not superuser!\n", inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", pathname, strerror(errno)); break; } case SQUASHFS_FIFO_TYPE: TRACE("create_inode: fifo\n"); if(mknod(pathname, S_IFIFO, 0) == -1) { ERROR("create_inode: failed to create fifo %s, because %s\n", pathname, strerror(errno)); break; } set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid, header.base.mtime, TRUE); fifo_count ++; break; case SQUASHFS_SOCKET_TYPE: TRACE("create_inode: socket\n"); ERROR("create_inode: socket %s ignored\n", pathname); break; default: ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type); return FALSE; }
/* Extract the data postioned at src_stream to either filesystem, stdout or * buffer depending on the value of 'function' which is defined in bbtargz.h * * prefix doesnt have to be just a directory, it may prefix the filename as well. * * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have * 'dpkg.' as their prefix * * For this reason if prefix does point to a dir then it must end with a * trailing '/' or else the last dir will be assumed to be the file prefix */ static char * extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry, const int function, const char *prefix, int *err) { FILE *dst_stream = NULL; char *full_name = NULL; char *full_link_name = NULL; char *buffer = NULL; struct utimbuf t; *err = 0; /* prefix doesnt have to be a proper path it may prepend * the filename as well */ if (prefix != NULL) { /* strip leading '/' in filename to extract as prefix may not be dir */ /* Cant use concat_path_file here as prefix might not be a directory */ char *path = file_entry->name; if (strncmp("./", path, 2) == 0) { path += 2; if (strlen(path) == 0) /* Do nothing, current dir already exists. */ return NULL; } full_name = xmalloc(strlen(prefix) + strlen(path) + 1); strcpy(full_name, prefix); strcat(full_name, path); if ( file_entry->link_name ){ full_link_name = xmalloc(strlen(prefix) + strlen(file_entry->link_name) + 1); strcpy(full_link_name, prefix); strcat(full_link_name, file_entry->link_name); } } else { full_name = xstrdup(file_entry->name); if ( file_entry->link_name ) full_link_name = xstrdup(file_entry->link_name); } if (function & extract_to_stream) { if (S_ISREG(file_entry->mode)) { *err = copy_file_chunk(src_stream, out_stream, file_entry->size); archive_offset += file_entry->size; } } else if (function & extract_one_to_buffer) { if (S_ISREG(file_entry->mode)) { buffer = (char *) xmalloc(file_entry->size + 1); fread(buffer, 1, file_entry->size, src_stream); buffer[file_entry->size] = '\0'; archive_offset += file_entry->size; goto cleanup; } } else if (function & extract_all_to_fs) { struct stat oldfile; int stat_res; stat_res = lstat (full_name, &oldfile); if (stat_res == 0) { /* The file already exists */ if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) { if (!S_ISDIR(oldfile.st_mode)) { unlink(full_name); /* Directories might not be empty etc */ } } else { if ((function & extract_quiet) != extract_quiet) { *err = -1; error_msg("%s not created: newer or same age file exists", file_entry->name); } seek_sub_file(src_stream, file_entry->size); goto cleanup; } } if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */ char *buf, *parent; buf = xstrdup(full_name); parent = dirname(buf); if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) { if ((function & extract_quiet) != extract_quiet) { *err = -1; error_msg("couldn't create leading directories"); } } free (buf); } switch(file_entry->mode & S_IFMT) { case S_IFREG: if (file_entry->link_name) { /* Found a cpio hard link */ if (link(full_link_name, full_name) != 0) { if ((function & extract_quiet) != extract_quiet) { *err = -1; perror_msg("Cannot link from %s to '%s'", file_entry->name, file_entry->link_name); } } } else { if ((dst_stream = wfopen(full_name, "w")) == NULL) { *err = -1; seek_sub_file(src_stream, file_entry->size); goto cleanup; } archive_offset += file_entry->size; *err = copy_file_chunk(src_stream, dst_stream, file_entry->size); fclose(dst_stream); } break; case S_IFDIR: if (stat_res != 0) { if (mkdir(full_name, file_entry->mode) < 0) { if ((function & extract_quiet) != extract_quiet) { *err = -1; perror_msg("Cannot make dir %s", full_name); } } } break; case S_IFLNK: if (symlink(file_entry->link_name, full_name) < 0) { if ((function & extract_quiet) != extract_quiet) { *err = -1; perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name); } goto cleanup; } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: if (mknod(full_name, file_entry->mode, file_entry->device) == -1) { if ((function & extract_quiet) != extract_quiet) { *err = -1; perror_msg("Cannot create node %s", file_entry->name); } goto cleanup; } break; default: *err = -1; perror_msg("Don't know how to handle %s", full_name); } /* Changing a symlink's properties normally changes the properties of the * file pointed to, so dont try and change the date or mode, lchown does * does the right thing, but isnt available in older versions of libc */ if (S_ISLNK(file_entry->mode)) { #if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1) lchown(full_name, file_entry->uid, file_entry->gid); #endif } else { if (function & extract_preserve_date) { t.actime = file_entry->mtime; t.modtime = file_entry->mtime; utime(full_name, &t); } chown(full_name, file_entry->uid, file_entry->gid); chmod(full_name, file_entry->mode); } } else { /* If we arent extracting data we have to skip it, * if data size is 0 then then just do it anyway * (saves testing for it) */ seek_sub_file(src_stream, file_entry->size); } /* extract_list and extract_verbose_list can be used in conjunction * with one of the above four extraction functions, so do this seperately */ if (function & extract_verbose_list) { fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), file_entry->uid, file_entry->gid, (int) file_entry->size, time_string(file_entry->mtime)); } if ((function & extract_list) || (function & extract_verbose_list)){ /* fputs doesnt add a trailing \n, so use fprintf */ fprintf(out_stream, "%s\n", file_entry->name); } cleanup: free(full_name); if ( full_link_name ) free(full_link_name); return buffer; }
int _do_chown(EncFS_Context *, const string &cyName, uid_t u, gid_t g) { int res = lchown(cyName.c_str(), u, g); return (res == -1) ? -errno : ESUCCESS; }
int main(int argc, char **argv) { int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; mode_t mode = 0755; char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; uid_t uid; gid_t gid; struct stat sb, tosb, fromsb; struct utimbuf utb; program = argv[0]; cwd = linkname = linkprefix = owner = group = 0; onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { switch (opt) { case 'C': cwd = optarg; break; case 'D': onlydir = 1; break; case 'd': dodir = 1; break; case 'l': dolink = 1; break; case 'L': linkprefix = optarg; lplen = strlen(linkprefix); dolink = 1; break; case 'R': dolink = dorelsymlink = 1; break; case 'm': mode = strtoul(optarg, &cp, 8); if (mode == 0 && cp == optarg) usage(); break; case 'o': owner = optarg; break; case 'g': group = optarg; break; case 't': dotimes = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 2 - onlydir) usage(); todir = argv[argc-1]; if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && mkdirs(todir, 0777) < 0) { fail("cannot make directory %s", todir); } if (onlydir) return 0; if (!cwd) { #ifndef NEEDS_GETCWD #ifndef GETCWD_CANT_MALLOC cwd = getcwd(0, PATH_MAX); #else cwd = malloc(PATH_MAX + 1); cwd = getcwd(cwd, PATH_MAX); #endif #else cwd = malloc(PATH_MAX + 1); cwd = getwd(cwd); #endif } xchdir(todir); #ifndef NEEDS_GETCWD #ifndef GETCWD_CANT_MALLOC todir = getcwd(0, PATH_MAX); #else todir = malloc(PATH_MAX + 1); todir = getcwd(todir, PATH_MAX); #endif #else todir = malloc(PATH_MAX + 1); todir = getwd(todir); #endif tdlen = strlen(todir); xchdir(cwd); tdlen = strlen(todir); uid = owner ? touid(owner) : (uid_t)(-1); gid = group ? togid(group) : (gid_t)(-1); while (--argc > 0) { name = *argv++; len = strlen(name); base = xbasename(name); bnlen = strlen(base); toname = xmalloc((unsigned int)(tdlen + 1 + bnlen + 1)); sprintf(toname, "%s%s%s", todir, _DIRECTORY_SEPARATOR, base); exists = (lstat(toname, &tosb) == 0); if (dodir) { /* -d means create a directory, always */ if (exists && !S_ISDIR(tosb.st_mode)) { (void) unlink(toname); exists = 0; } if (!exists && mkdir(toname, mode) < 0) fail("cannot make directory %s", toname); if ((owner || group) && chown(toname, uid, gid) < 0) fail("cannot change owner of %s", toname); } else if (dolink) { if (access(name, R_OK) != 0) { fail("cannot access %s", name); } if (*name == '/') { /* source is absolute pathname, link to it directly */ linkname = 0; } else { if (linkprefix) { /* -L implies -l and prefixes names with a $cwd arg. */ len += lplen + 1; linkname = xmalloc((unsigned int)(len + 1)); sprintf(linkname, "%s/%s", linkprefix, name); } else if (dorelsymlink) { /* Symlink the relative path from todir to source name. */ linkname = xmalloc(PATH_MAX); if (*todir == '/') { /* todir is absolute: skip over common prefix. */ lplen = relatepaths(todir, cwd, linkname); strcpy(linkname + lplen, name); } else { /* todir is named by a relative path: reverse it. */ reversepath(todir, name, len, linkname); xchdir(cwd); } len = strlen(linkname); } name = linkname; } /* Check for a pre-existing symlink with identical content. */ if ((exists && (!S_ISLNK(tosb.st_mode) || readlink(toname, buf, sizeof buf) != len || strncmp(buf, name, (unsigned int)len) != 0)) || ((stat(name, &fromsb) == 0) && (fromsb.st_mtime > tosb.st_mtime))) { (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); exists = 0; } if (!exists && symlink(name, toname) < 0) fail("cannot make symbolic link %s", toname); #ifdef HAVE_LCHOWN if ((owner || group) && lchown(toname, uid, gid) < 0) fail("cannot change owner of %s", toname); #endif if (linkname) { free(linkname); linkname = 0; } } else { /* Copy from name to toname, which might be the same file. */ if( stat(name, &sb) == 0 && S_IFDIR & sb.st_mode ) { /* then is directory: must explicitly create destination dir */ /* and manually copy files over */ copydir( name, todir, mode, group, owner, dotimes, uid, gid ); } else { copyfile(name, toname, mode, group, owner, dotimes, uid, gid); } } free(toname); } free(cwd); free(todir); return 0; }
void UnistdLchown(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { ReturnValue->Val->Integer = lchown(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); }
static void uv__fs_work(struct uv__work* w) { int retry_on_eintr; uv_fs_t* req; ssize_t r; req = container_of(w, uv_fs_t, work_req); retry_on_eintr = !(req->fs_type == UV_FS_CLOSE || req->fs_type == UV_FS_READ); do { errno = 0; #define X(type, action) \ case UV_FS_ ## type: \ r = action; \ break; switch (req->fs_type) { X(ACCESS, access(req->path, req->flags)); X(CHMOD, chmod(req->path, req->mode)); X(CHOWN, chown(req->path, req->uid, req->gid)); X(CLOSE, close(req->file)); X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); X(LCHOWN, lchown(req->path, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); X(FSYNC, uv__fs_fsync(req)); X(FTRUNCATE, ftruncate(req->file, req->off)); X(FUTIME, uv__fs_futime(req)); X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); X(LINK, link(req->path, req->new_path)); X(MKDIR, mkdir(req->path, req->mode)); X(MKDTEMP, uv__fs_mkdtemp(req)); X(OPEN, uv__fs_open(req)); X(READ, uv__fs_read(req)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); X(REALPATH, uv__fs_realpath(req)); X(RENAME, rename(req->path, req->new_path)); X(RMDIR, rmdir(req->path)); X(SENDFILE, uv__fs_sendfile(req)); X(STAT, uv__fs_stat(req->path, &req->statbuf)); X(SYMLINK, symlink(req->path, req->new_path)); X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); X(WRITE, uv__fs_write_all(req)); default: abort(); } #undef X } while (r == -1 && errno == EINTR && retry_on_eintr); if (r == -1) req->result = UV__ERR(errno); else req->result = r; if (r == 0 && (req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_FSTAT || req->fs_type == UV_FS_LSTAT)) { req->ptr = &req->statbuf; } }