mv.c revision 9e647765f079a9527bc9430bd6805745b590091b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* mv file1 file2
* mv dir1 dir2
* mv file1 ... filen dir1
*/
#include <signal.h>
#include <locale.h>
#include <stdarg.h>
#include <libcmdutils.h>
#include <aclutils.h>
#include "getresponse.h"
#define DELIM '/'
#define FALSE 0
#define TRUE 1
static char *dname(char *);
static int lnkfil(char *, char *);
static int cpymve(char *, char *);
static int chkfiles(char *, char **);
static int rcopy(char *, char *);
static int chk_different(char *, char *);
static int copydir(char *, char *);
static int copyspecial(char *);
static int getrealpath(char *, char *);
static void usage(void);
static void Perror(char *);
static void Perror2(char *, char *);
static int use_stdin(void);
static int copyattributes(char *, char *);
static int copy_sysattr(char *, char *);
static char *cmd;
static int silent = 0;
static int fflg = 0;
static int iflg = 0;
static int pflg = 0;
static int Rflg = 0; /* recursive copy */
static int rflg = 0; /* recursive copy */
static int sflg = 0;
static int Hflg = 0; /* follow cmd line arg symlink to dir */
static int Lflg = 0; /* follow symlinks */
static int Pflg = 0; /* do not follow symlinks */
static int atflg = 0;
static int attrsilent = 0;
static int targetexists = 0;
static int cmdarg; /* command line argument */
static int saflg = 0; /* 'cp' extended system attr. */
static int srcfd = -1;
static int targfd = -1;
static int sourcedirfd = -1;
static int targetdirfd = -1;
static int srcattrfd = -1;
static int targattrfd = -1;
/* Extended system attributes support */
static int open_source(char *);
static int open_target_srctarg_attrdirs(char *, char *);
static int open_attrdirp(char *);
static int traverse_attrfile(struct dirent *, char *, char *, int);
static void rewind_attrdir(DIR *);
static void close_all();
int
{
int c, i, r, errflg = 0;
int (*move)(char *, char *);
/*
* Determine command invoked (mv, cp, or ln)
*/
++cmd;
else
/*
* Set flags based on command.
*/
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
if (init_yes() < 0) {
exit(3);
}
else {
gettext("Invalid command name (%s); expecting "
"mv, cp, or ln.\n"), cmd);
exit(1);
}
/*
* Check for options:
* cp [ -r|-R [-H|-L|-P]] [-afip@/] file1 [file2 ...] target
* cp [-afiprR@/] file1 [file2 ...] target
* ln [-f] [-n] [-s] file1 [file2 ...] target
* ln [-f] [-n] [-s] file1 [file2 ...]
* mv [-f|i] file1 [file2 ...] target
* mv [-f|i] dir1 target
*/
if (cpy) {
switch (c) {
case 'f':
fflg++;
break;
case 'i':
iflg++;
break;
case 'p':
pflg++;
#ifdef XPG4
attrsilent = 1;
atflg = 0;
saflg = 0;
#else
if (atflg == 0)
attrsilent = 1;
#endif
break;
case 'H':
/*
* If more than one of -H, -L, or -P are
* specified, only the last option specified
* determines the behavior.
*/
Hflg++;
break;
case 'L':
Lflg++;
break;
case 'P':
Pflg++;
break;
case 'R':
/*
* The default behavior of cp -R|-r
* when specified without -H|-L|-P
* is -L.
*/
Rflg++;
/*FALLTHROUGH*/
case 'r':
rflg++;
break;
case 'a':
pflg++;
Pflg++;
Rflg++;
rflg++;
break;
case '@':
atflg++;
attrsilent = 0;
#ifdef XPG4
pflg = 0;
#endif
break;
case '/':
saflg++;
attrsilent = 0;
#ifdef XPG4
pflg = 0;
#endif
break;
default:
errflg++;
}
/* -R or -r must be specified with -H, -L, or -P */
errflg++;
}
} else if (mve) {
switch (c) {
case 'f':
silent++;
#ifdef XPG4
iflg = 0;
#endif
break;
case 'i':
iflg++;
#ifdef XPG4
silent = 0;
#endif
break;
default:
errflg++;
}
} else { /* ln */
switch (c) {
case 'f':
silent++;
break;
case 'n':
/* silently ignored; this is the default */
break;
case 's':
sflg++;
break;
default:
errflg++;
}
}
/*
* For BSD compatibility allow - to delimit the end of
* options for mv.
*/
optind++;
/*
* Check for sufficient arguments
* or a usage error.
*/
gettext("%s: Insufficient arguments (%d)\n"),
usage();
}
if (errflg != 0)
usage();
/*
* If there is more than a source and target,
* the last argument (the target) must be a directory
* which really exists.
*/
if (argc > 2) {
gettext("%s: %s not found\n"),
exit(2);
}
gettext("%s: Target %s must be a directory\n"),
usage();
}
}
gettext("%s: Target %s file name length exceeds PATH_MAX"
exit(78);
}
if (argc == 1) {
if (!lnk)
usage();
} else {
}
/*
* Perform a multiple argument mv|cp|ln by
* multiple invocations of cpymve() or lnkfil().
*/
if (lnk)
else
r = 0;
for (i = 0; i < argc; i++) {
cmdarg = 1;
}
/*
* Show errors by nonzero exit code.
*/
return (r?2:0);
}
static int
{
if (sflg) {
/*
* If target is a directory make complete
* name of the new symbolic link within that
* directory.
*/
gettext("%s: Insufficient memory "
exit(3);
}
}
/*
* Check to see if the file exists already.
* In this case we use lstat() instead of stat():
* unlink(2) and symlink(2) will operate on the file
* itself, not its reference, if the file is a symlink.
*/
/*
* Check if the silent flag is set ie. the -f option
* is used. If so, use unlink to remove the current
* target to replace with the new target, specified
* on the command line. Proceed with symlink.
*/
if (silent) {
/*
* Don't allow silent (-f) removal of an existing
* directory; could leave unreferenced directory
* entries.
*/
gettext("%s: cannot create link "
"over directory %s\n"), cmd,
target);
return (1);
}
gettext("%s: cannot unlink %s: "),
perror("");
return (1);
}
}
}
/*
* Create a symbolic link to the source.
*/
gettext("%s: cannot create %s: "),
perror("");
return (1);
}
return (0);
}
case 1: return (1);
case 2: return (0);
/* default - fall through */
}
/*
* Make sure source file is not a directory,
* we cannot link directories...
*/
return (1);
}
/*
* hard link, call link() and return.
*/
gettext("%s: %s is on a different file system\n"),
else {
gettext("%s: cannot create link %s: "),
perror("");
}
return (1);
} else {
return (0);
}
}
static int
{
int n;
int ret = 0;
int attret = 0;
int sattret = 0;
int errno_save;
int error = 0;
case 1: return (1);
case 2: return (0);
/* default - fall through */
}
/*
* If it's a recursive copy and source
* is a directory, then call rcopy (from copydir).
*/
if (cpy) {
int rc;
avl_index_t where = 0;
/*
* We will be recursing into the directory so
* save the inode information to a search tree
* to avoid getting into an endless loop.
*/
if (rc == 0) {
/*
* We've already visited this directory.
* Don't remove the search tree entry
* to make sure we don't get into an
* endless loop if revisited from a
* different part of the hierarchy.
*/
"%s: cycle detected: %s\n"),
} else {
}
return (1);
}
cmdarg = 0;
/*
* Create a tnode to get an index to the matching
* node (same dev and inode) in the search tree,
* then use the index to remove the matching node
* so it we do not wrongly detect a cycle when
* revisiting this directory from another part of
* the hierarchy.
*/
return (1);
}
}
return (rc);
return (copyspecial(target));
} else {
goto copy;
}
}
if (mve) {
return (0);
gettext("%s: %s is a directory\n"),
return (1);
}
gettext("%s: cannot rename %s to %s: "),
perror("");
return (1);
}
/*
* cannot move a non-directory (source) onto an existing
* directory (target)
*
*/
gettext("%s: cannot mv a non directory %s "
"over existing directory"
return (1);
}
#ifdef XPG4
/* existing target dir must be empty */
errno_save = errno;
gettext("%s: cannot rmdir %s: "),
errno = errno_save;
perror("");
return (1);
}
}
#endif
return (n);
}
/* doors cannot be moved across filesystems */
gettext("%s: %s: cannot move door "
return (1);
}
/* sockets cannot be moved across filesystems */
gettext("%s: %s: cannot move socket "
return (1);
}
/*
* File cannot be renamed, try to recreate the symbolic
* link or special device, or copy the file wholesale
* between file systems.
*/
register int m;
gettext("%s: cannot unlink %s: "),
perror("");
return (1);
}
sizeof (symln) - 1)) < 0) {
return (1);
}
symln[m] = '\0';
return (1);
}
#ifdef XPG4
if (m < 0) {
" change owner and group of"
perror("");
}
#endif
goto cleanup;
}
gettext("%s: cannot unlink %s: "),
perror("");
return (1);
}
return (1);
}
goto cleanup;
}
gettext("%s: cannot rmdir %s: "),
perror("");
return (1);
}
} else {
gettext("%s: cannot unlink %s: "),
perror("");
return (1);
}
}
copy:
/*
* If the source file is a symlink, and either
* -P or -H flag (only if -H is specified and the
* source file is not a command line argument)
* were specified, then action is taken on the symlink
* itself, not the file referenced by the symlink.
* Note: this is executed for 'cp' only.
*/
int m;
if (m < 0) {
return (1);
}
symln[m] = '\0';
/*
* Copy the sym link to the target.
* Note: If the target exists, write a
* diagnostic message, do nothing more
* with the source file, and return to
* process any remaining files.
*/
return (1);
}
if (m < 0) {
"cp: cannot change owner and "
"group of %s:"), target);
perror("");
}
} else {
/*
* Copy the file. If it happens to be a
* symlink, copy the file referenced
* by the symlink.
*/
if (fi < 0) {
gettext("%s: cannot open %s: "),
perror("");
return (1);
}
if (fo < 0) {
/*
* If -f and creat() failed, unlink
* and try again.
*/
if (fflg) {
}
}
if (fo < 0) {
gettext("%s: cannot create %s: "),
perror("");
return (1);
} else {
/* stat the new file, its used below */
}
/*
* Set target's permissions to the source
* before any copying so that any partially
* copied file will have the source's
* permissions (at most) or umask permissions
* whichever is the most restrictive.
*
* ACL for regular files
*/
s1acl)) < 0) {
error++;
gettext("%s: "
"Failed to set "
"acl entries "
"on %s\n"), cmd,
target);
/*
* else: silent and
* continue
*/
}
}
}
gettext("%s: cannot access %s\n"),
return (1);
}
"%s: %s and %s are identical\n"),
return (1);
}
return (1);
}
return (1);
}
}
/* Copy regular extended attributes */
if (attret != 0 && !attrsilent) {
"%s: Failed to preserve"
" extended attributes of file"
}
/* Copy extended system attributes */
return (1);
}
if (attrsilent) {
attret = 0;
}
}
/*
* XPG4: the write system call will clear setgid
* and setuid bits, so set them again.
*/
return (1);
/*
* Reapply ACL, since chmod may have
* altered ACL
*/
error++;
gettext("%s: Failed to "
"set acl entries "
/*
* else: silent and
* continue
*/
}
}
return (1);
}
if (cpy) {
return (1);
return (0);
}
goto cleanup;
}
return (1);
gettext("%s: cannot unlink %s: "),
perror("");
return (1);
}
return (1);
return (ret);
}
/*NOTREACHED*/
return (ret);
}
/*
* create_tnode()
*
* Create a node for use with the search tree which contains the
* inode information (device id and inode number).
*
* Input
* dev - device id
* ino - inode number
*
* Output
* tnode - NULL on error, otherwise returns a tnode structure
* which contains the input device id and inode number.
*/
static tree_node_t *
{
}
return (tnode);
}
static int
{
int error;
/*
* Make sure source file exists.
*/
/*
* Keep the old error message except when someone tries to
* points to a file.
*/
else
return (1);
}
/*
*/
}
"%s: failed to get acl entries: %s\n", source,
return (1);
}
/* else: just permission bits */
}
/*
* If stat fails, then the target doesn't exist,
* we will create a new target with default file type of regular.
*/
targetexists = 0;
/*
* If target is a directory,
* make complete name of new file
* within that directory.
*/
gettext("%s: Insufficient memory to "
exit(3);
}
}
targetexists++;
/*
* For cp and mv, it is an error if the
* source and target are the same file.
* Check for the same inode and file
* system, but don't check for the same
* absolute pathname because it is an
* error when the source and target are
* hard links to the same file.
*/
"%s: %s and %s are identical\n"),
return (1);
}
}
if (lnk) {
/*
* For ln, it is an error if the source and
* target are identical files (same inode,
* same file system, and filenames resolve
* to same absolute pathname).
*/
return (1);
}
}
gettext("%s: %s: File exists\n"),
return (1);
}
/*
* overwrite:
* If the user does not have access to
* the target, ask ----if it is not
* silent and user invoked command
* interactively.
*
* override:
* If not silent, and stdin is a terminal, and
* there's no write access, and the file isn't a
* symbolic link, ask for permission.
*
* XPG4: both overwrite and override:
* ask only one question.
*
* TRANSLATION_NOTE - The following messages will
* contain the first character of the strings for
* "yes" and "no" defined in the file
* "nl_langinfo.po". After substitution, the
* message will appear as follows:
* <cmd>: overwrite <filename> (y/n)?
* where <cmd> is the name of the command
* (cp, mv) and <filename> is the destination file
*/
gettext("%s: overwrite %s and override "
if (yes() == 0) {
return (2);
}
gettext("%s: overwrite %s (%s/%s)? "),
if (yes() == 0) {
return (2);
}
} else if (override) {
gettext("%s: %s: override protection "
/*CSTYLED*/
"%o (%s/%s)? "),
/*CSTYLED*/
if (yes() == 0) {
return (2);
}
}
gettext("%s: cannot unlink %s: "),
perror("");
return (1);
}
}
}
return (0);
}
/*
* check whether source and target are different
* return 1 when they are different
* return 0 when they are identical, or when unable to resolve a pathname
*/
static int
{
/*
* IDENTICAL will be true for hard links, therefore
* check whether the filenames are different
*/
return (0);
}
"%s: %s and %s are identical\n"),
return (0);
}
}
return (1);
}
/*
* get real path (resolved absolute pathname)
* return 1 on success, 0 on failure
*/
static int
{
int errno_save = errno;
errno = errno_save;
perror("");
return (0);
}
return (1);
}
static int
{
int errs = 0;
return (1);
}
/*
* Save s1 (stat information for source dir) so that
* mod and access times can be reserved during "cp -p"
* or mv, since s1 gets overwritten.
*/
}
for (;;) {
if (dp == 0) {
return (errs);
}
continue;
continue;
sizeof (fromname) - 1) {
gettext("%s : %s/%s: Name too long\n"),
errs++;
continue;
}
}
}
static char *
{
register char *p;
/*
* Return just the file name given the complete path.
* Like basename(1).
*/
p = name;
/*
* While there are characters left,
* set name to start after last
* delimiter.
*/
while (*p)
if (*p++ == DELIM && *p)
name = p;
return (name);
}
static void
usage(void)
{
/*
* Display usage message.
*/
if (mve) {
"Usage: mv [-f] [-i] f1 f2\n"
" mv [-f] [-i] f1 ... fn d1\n"
" mv [-f] [-i] d1 d2\n"));
} else if (lnk) {
#ifdef XPG4
"Usage: ln [-f] [-s] f1 [f2]\n"
" ln [-f] [-s] f1 ... fn d1\n"
" ln [-f] -s d1 d2\n"));
#else
"Usage: ln [-f] [-n] [-s] f1 [f2]\n"
" ln [-f] [-n] [-s] f1 ... fn d1\n"
" ln [-f] [-n] -s d1 d2\n"));
#endif
} else if (cpy) {
"Usage: cp [-a] [-f] [-i] [-p] [-@] [-/] f1 f2\n"
" cp [-a] [-f] [-i] [-p] [-@] [-/] f1 ... fn d1\n"
" cp [-r|-R [-H|-L|-P]] [-a] [-f] [-i] [-p] [-@] "
"[-/] d1 ... dn-1 dn\n"));
}
exit(2);
}
/*
* chg_time()
*
* Try to preserve modification and access time.
* If 1) pflg is not set, or 2) pflg is set and this is the Solaris version,
* don't report a utimensat() failure.
* If this is the XPG4 version and utimensat fails, if 1) pflg is set (cp -p)
* or 2) we are doing a mv, print a diagnostic message; arrange for a non-zero
* exit status only if pflg is set.
* utimensat(2) is being used to achieve granularity in nanoseconds
* (if supported by the underlying file system) while setting file times.
*/
static int
{
int rc;
#ifdef XPG4
perror("");
if (pflg)
return (1);
}
#endif
return (0);
}
/*
* chg_mode()
*
* This function is called upon "cp -p" or mv across filesystems.
*
* Try to preserve the owner and group id. If chown() fails,
* only print a diagnostic message if doing a mv in the XPG4 version;
* try to clear S_ISUID and S_ISGID bits in the target. If unable to clear
* S_ISUID and S_ISGID bits, print a diagnostic message and arrange for a
* non-zero exit status because this is a security violation.
* Try to preserve permissions.
* If this is the XPG4 version and chmod() fails, print a diagnostic message
* and arrange for a non-zero exit status.
* If this is the Solaris version and chmod() fails, do not print a
* diagnostic message or exit with a non-zero value.
*/
static int
{
int clearflg = 0; /* controls message printed upon chown() error */
/* Don't change mode if target is symlink */
return (0);
#ifdef XPG4
if (mve) {
perror("");
}
#endif
/* try to clear S_ISUID and S_ISGID */
++clearflg;
}
}
if (clearflg) {
"%s: cannot clear S_ISUID and S_ISGID bits in"
perror("");
/* cp -p should get non-zero exit; mv should not */
if (pflg)
return (1);
}
#ifdef XPG4
else {
perror("");
/* cp -p should get non-zero exit; mv should not */
if (pflg)
return (1);
}
#endif
}
return (0);
}
static void
Perror(char *s)
{
}
static void
{
}
/*
* used for cp -R and for mv across file systems
*/
static int
{
int sattret = 0;
int pret = 0; /* need separate flag if -p is specified */
int error = 0;
s1acl_save = NULL;
return (1);
}
return (1);
}
} else {
}
return (1);
}
/*
* Save s1 (stat information for source dir) and acl info,
* if any, so that ownership, modes, times, and acl's can
* be reserved during "cp -p" or mv.
* s1 gets overwritten when doing the recursive copy.
*/
if (s1acl_save == NULL) {
"Insufficient memory to save acl"
" entry\n"), cmd);
if (pflg)
return (1);
}
#ifdef XPG4
else {
"Insufficient memory to save acl"
" entry\n"), cmd);
if (pflg)
return (1);
}
#endif
}
}
/*
* Once we created a directory, go ahead and set
* its attributes, e.g. acls and time. The info
* may get overwritten if we continue traversing
* down the tree.
*
* ACL for directory
*/
if (s1acl_save != NULL) {
error++;
#ifdef XPG4
#else
if (pflg) {
#endif
"%s: failed to set acl entries "
if (pflg) {
s1acl_save = NULL;
ret++;
}
}
/* else: silent and continue */
}
s1acl_save = NULL;
}
if (!attrsilent && attret != 0) {
" extended attributes of directory"
} else {
/*
* Otherwise ignore failure.
*/
attret = 0;
}
/* Copy extended system attributes */
if (sattret != 0) {
"%s: Failed to preserve "
"extended system attributes "
}
}
}
return (1);
return (ret);
}
static int
copyspecial(char *target)
{
int ret = 0;
"cp: cannot create special file %s: "), target);
perror("");
return (1);
}
if (pflg) {
}
return (ret);
}
static int
use_stdin(void)
{
#ifdef XPG4
return (1);
#else
#endif
}
/* Copy non-system extended attributes */
static int
{
int error = 0;
int aclerror;
int clearflg = 0;
return (0);
if (!attrsilent) {
"%s: cannot preserve extended attributes, "
"operation not supported on file"
}
return (1);
}
if (open_source(source) != 0)
return (1);
return (1);
if (open_attrdirp(source) != 0)
return (1);
if (!attrsilent) {
gettext("%s: failed to set file mode"
" correctly on attribute directory of"
perror("");
++error;
}
}
if (!attrsilent) {
gettext("%s: failed to set file"
" ownership correctly on attribute"
perror("");
++error;
}
}
/*
* Now that we are the owner we can update st_ctime by calling
* utimensat.
*/
if (!attrsilent) {
gettext("%s: cannot set attribute times"
perror("");
++error;
}
}
/*
* Now set owner and group of attribute directory, implies
* changing the ACL of the hidden attribute directory first.
*/
ACL_NO_TRIVIAL, &attrdiracl)) != 0) {
if (!attrsilent) {
"%s: failed to get acl entries of"
" attribute directory for"
" %s : %s\n"), cmd,
++error;
}
}
if (attrdiracl) {
if (!attrsilent) {
"%s: failed to set acl entries"
" on attribute directory "
++error;
}
attrdiracl = NULL;
}
}
}
int ret;
continue;
else if (ret > 0) {
++error;
goto out;
}
ACL_NO_TRIVIAL, &xacl)) != 0) {
if (!attrsilent) {
"%s: failed to get acl entries of"
" attribute %s for"
++error;
}
}
}
/*
* preserve ACL
*/
if (!attrsilent) {
"%s: failed to set acl entries on"
" attribute %s for"
++error;
}
}
}
if (!attrsilent) {
++error;
}
goto next;
}
if (!attrsilent) {
gettext("%s: cannot change"
" owner and group of"
" attribute %s for" " file"
perror("");
++error;
}
/* try to clear S_ISUID and S_ISGID */
++clearflg;
}
}
if (!attrsilent) {
gettext("%s: cannot set attribute"
perror("");
++error;
}
}
if (clearflg) {
"%s: cannot clear S_ISUID and "
"S_ISGID bits in attribute %s"
" for file"
} else {
if (!attrsilent) {
"%s: cannot set permissions of attribute"
perror("");
++error;
}
}
}
if (!attrsilent) {
"%s: failed to set acl entries on"
" attribute %s for"
++error;
}
}
}
next:
}
if (srcattrfd != -1)
if (targattrfd != -1)
(void) close(targattrfd);
}
out:
}
if (attrdiracl != NULL) {
attrdiracl = NULL;
}
close_all();
return (error == 0 ? 0 : 1);
}
/* Copy extended system attributes from source to target */
static int
{
int error = 0;
int target_sa_support = 0;
return (0);
if (open_source(source) != 0)
return (1);
/*
* Gets non default extended system attributes from the
* source file to copy to the target. The target has
* the defaults set when its created and thus no need
* to copy the defaults.
*/
"%s: cannot preserve extended system "
"attribute, operation not supported on file"
error++;
goto out;
}
} else {
target_sa_support = 1;
}
if (target_sa_support) {
target) != 0) {
error++;
goto out;
}
if (open_attrdirp(source) != 0) {
error++;
goto out;
}
} else {
}
int ret;
0)) == -1)
continue;
else if (ret > 0) {
++error;
goto out;
}
/*
* Gets non default extended system attributes from the
* attribute file to copy to the target. The target has
* the defaults set when its created and thus no need
* to copy the defaults.
*/
goto next;
/*
* Copy non default extended system attributes of named
* attribute file.
*/
if (fsetattr(targattrfd,
XATTR_VIEW_READWRITE, res) != 0) {
++error;
"Failed to copy extended system "
"attributes from attribute file "
"%s of %s to %s\n"), cmd,
}
}
next:
if (srcattrfd != -1)
if (targattrfd != -1)
(void) close(targattrfd);
}
}
/* Copy source file non default extended system attributes to target */
++error;
"copy extended system attributes from "
}
out:
close_all();
return (error == 0 ? 0 : 1);
}
/* Open the source file */
int
open_source(char *src)
{
int error = 0;
srcfd = -1;
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
gettext("%s: cannot open file"
perror("");
}
++error;
}
out:
if (error)
close_all();
return (error == 0 ? 0 : 1);
}
/* Open source attribute dir, target and target attribute dir. */
int
{
int error = 0;
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
gettext("%s: cannot open file"
perror("");
}
++error;
goto out;
}
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
gettext("%s: cannot open attribute"
perror("");
}
++error;
goto out;
}
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
gettext("%s: could not retrieve stat"
" information for attribute directory"
perror("");
}
++error;
goto out;
}
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
gettext("%s: cannot open attribute"
perror("");
}
++error;
}
out:
if (error)
close_all();
return (error == 0 ? 0 : 1);
}
int
open_attrdirp(char *source)
{
int tmpfd = -1;
int error = 0;
/*
* dup sourcedirfd for use by fdopendir().
* fdopendir will take ownership of given fd and will close
* it when closedir() is called.
*/
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
"%s: unable to dup attribute directory"
perror("");
++error;
}
goto out;
}
if (pflg && attrsilent) {
error++;
goto out;
}
if (!attrsilent) {
gettext("%s: failed to open attribute"
perror("");
++error;
}
}
out:
if (error)
close_all();
return (error == 0 ? 0 : 1);
}
/* Skips through ., .., and system attribute 'view' files */
int
{
int error = 0;
return (-1);
O_RDONLY)) == -1) {
if (!attrsilent) {
gettext("%s: cannot open attribute %s on"
perror("");
++error;
goto out;
}
}
if (!attrsilent) {
gettext("%s: could not stat attribute"
" %s on file"
perror("");
++error;
}
goto out;
}
if (first) {
if (!attrsilent) {
gettext("%s: could not create attribute"
target);
perror("");
++error;
}
goto out;
}
} else {
O_RDONLY)) == -1) {
if (!attrsilent) {
gettext("%s: could not open attribute"
target);
perror("");
++error;
}
goto out;
}
}
if (!attrsilent) {
gettext("%s: could not stat attribute"
" %s on file"
perror("");
++error;
}
}
out:
if (error) {
if (srcattrfd != -1)
if (targattrfd != -1)
(void) close(targattrfd);
}
return (error == 0 ? 0 :1);
}
void
{
int pwdfd;
} else {
if (!attrsilent) {
"failed to rewind attribute dir\n"),
cmd);
}
}
}
void
{
if (srcattrfd != -1)
if (targattrfd != -1)
(void) close(targattrfd);
if (sourcedirfd != -1)
(void) close(sourcedirfd);
if (targetdirfd != -1)
(void) close(targetdirfd);
}
if (srcfd != -1)
if (targfd != -1)
}