summaryrefslogtreecommitdiff
path: root/usr/src/cmd/tar/tar.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/tar/tar.c')
-rw-r--r--usr/src/cmd/tar/tar.c1462
1 files changed, 1186 insertions, 276 deletions
diff --git a/usr/src/cmd/tar/tar.c b/usr/src/cmd/tar/tar.c
index d68c4e0e34..80e72adb35 100644
--- a/usr/src/cmd/tar/tar.c
+++ b/usr/src/cmd/tar/tar.c
@@ -61,26 +61,32 @@
#include <stdarg.h>
#include <widec.h>
#include <sys/mtio.h>
-#include <libintl.h>
#include <sys/acl.h>
#include <strings.h>
#include <deflt.h>
#include <limits.h>
#include <iconv.h>
#include <assert.h>
+#include <libgen.h>
+#include <libintl.h>
#include <aclutils.h>
-#include "getresponse.h"
+#include <libnvpair.h>
+#include <archives.h>
#if defined(__SunOS_5_6) || defined(__SunOS_5_7)
extern int defcntl();
#endif
-#include <archives.h>
+#if defined(_PC_SATTR_ENABLED)
+#include <attr.h>
+#include <libcmdutils.h>
+#endif
/* Trusted Extensions */
#include <zone.h>
#include <tsol/label.h>
#include <sys/tsol/label_macro.h>
+#include "getresponse.h"
/*
* Source compatibility
*/
@@ -180,6 +186,14 @@ int utimes(const char *path, const struct timeval timeval_ptr[]);
#define PUT_AS_LINK 1
#define PUT_NOTAS_LINK 0
+#ifndef VIEW_READONLY
+#define VIEW_READONLY "SUNWattr_ro"
+#endif
+
+#ifndef VIEW_READWRITE
+#define VIEW_READWRITE "SUNWattr_rw"
+#endif
+
#if _FILE_OFFSET_BITS == 64
#define FMT_off_t "lld"
#define FMT_off_t_o "llo"
@@ -199,6 +213,31 @@ struct sec_attr {
char attr_info[1];
} *attr;
+#if defined(O_XATTR)
+typedef enum {
+ ATTR_OK,
+ ATTR_SKIP,
+ ATTR_CHDIR_ERR,
+ ATTR_OPEN_ERR,
+ ATTR_XATTR_ERR,
+ ATTR_SATTR_ERR
+} attr_status_t;
+#endif
+
+#if defined(O_XATTR)
+typedef enum {
+ ARC_CREATE,
+ ARC_RESTORE
+} arc_action_t;
+#endif
+
+typedef struct attr_data {
+ char *attr_parent;
+ char *attr_path;
+ int attr_parentfd;
+ int attr_rw_sysattr;
+} attr_data_t;
+
/*
*
* Tar has been changed to support extended attributes.
@@ -306,7 +345,7 @@ struct sec_attr {
static struct xattr_hdr *xattrhead;
static struct xattr_buf *xattrp;
static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
-static char *xattraname; /* attribute name */
+static char *xattrapath; /* attribute name */
static char *xattr_linkaname; /* attribute attribute is linked to */
static char Hiddendir; /* are we processing hidden xattr dir */
static char xattrbadhead;
@@ -394,7 +433,7 @@ static void assert_string(char *s, char *msg);
static int istape(int fd, int type);
static void backtape(void);
static void build_table(struct file_list *table[], char *file);
-static void check_prefix(char **namep, char **dirp, char **compp);
+static int check_prefix(char **namep, char **dirp, char **compp);
static void closevol(void);
static void copy(void *dst, void *src);
static int convtoreg(off_t);
@@ -421,7 +460,7 @@ static void newvol(void);
static void passtape(void);
static void putempty(blkcnt_t n);
static int putfile(char *longname, char *shortname, char *parent,
- int filetype, int lev, int symlink_lev);
+ attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
static void readtape(char *buffer);
static void seekdisk(blkcnt_t blocks);
static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
@@ -429,8 +468,8 @@ static void splitfile(char *longname, int ifd, char *name,
char *prefix, int filetype);
static void tomodes(struct stat *sp);
static void usage(void);
-static void xblocks(off_t bytes, int ofile);
-static void xsfile(int ofd);
+static int xblocks(int issysattr, off_t bytes, int ofile);
+static int xsfile(int issysattr, int ofd);
static void resugname(int dirfd, char *name, int symflag);
static int bcheck(char *bstr);
static int checkdir(char *name);
@@ -466,7 +505,8 @@ static char *getname(gid_t);
static char *getgroup(gid_t);
static int checkf(char *name, int mode, int howmuch);
static int writetbuf(char *buffer, int n);
-static int wantit(char *argv[], char **namep, char **dirp, char **comp);
+static int wantit(char *argv[], char **namep, char **dirp, char **comp,
+ attr_data_t **attrinfo);
static void append_ext_attr(char *shortname, char **secinfo, int *len);
static int get_xdata(void);
static void gen_num(const char *keyword, const u_longlong_t number);
@@ -481,17 +521,18 @@ static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
iconv_t iconv_cd, int xhdrflg, int max_val);
static int c_utf8(char *target, const char *source);
-static int getstat(int dirfd, char *longname, char *shortname);
-static void xattrs_put(char *, char *, char *);
+static int getstat(int dirfd, char *longname, char *shortname,
+ char *attrparent);
+static void xattrs_put(char *, char *, char *, char *);
static void prepare_xattr(char **, char *, char *,
char, struct linkbuf *, int *);
-static int put_link(char *name, char *longname, char *component, char *prefix,
- int filetype, char typeflag);
+static int put_link(char *name, char *longname, char *component,
+ char *longattrname, char *prefix, int filetype, char typeflag);
static int put_extra_attributes(char *longname, char *shortname,
- char *prefix, int filetype, char typeflag);
-static int put_xattr_hdr(char *longname, char *shortname, char *prefix,
- int typeflag, int filetype, struct linkbuf *lp);
-static int read_xattr_hdr();
+ char *longattrname, char *prefix, int filetype, char typeflag);
+static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
+ char *prefix, int typeflag, int filetype, struct linkbuf *lp);
+static int read_xattr_hdr(attr_data_t **attrinfo);
/* Trusted Extensions */
#define AUTO_ZONE "/zone"
@@ -503,12 +544,14 @@ static int rebuild_lk_comp_path(char *str, char **namep);
static void get_parent(char *path, char *dir);
static char *get_component(char *path);
-static int retry_attrdir_open(char *name);
+static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
+ char *name, int oflag, mode_t mode);
static char *skipslashes(char *string, char *start);
static void chop_endslashes(char *path);
static struct stat stbuf;
+static char *myname;
static int checkflag = 0;
#ifdef _iBCS2
static int Fileflag;
@@ -523,6 +566,7 @@ static int bflag, kflag, Aflag;
static int Pflag; /* POSIX conformant archive */
static int Eflag; /* Allow files greater than 8GB */
static int atflag; /* traverse extended attributes */
+static int saflag; /* traverse extended sys attributes */
static int Dflag; /* Data change flag */
/* Trusted Extensions */
static int Tflag; /* Trusted Extensions attr flags */
@@ -657,6 +701,11 @@ main(int argc, char *argv[])
usage();
tfile = NULL;
+ if ((myname = strdup(argv[0])) == NULL) {
+ (void) fprintf(stderr, gettext(
+ "tar: cannot allocate program name\n"));
+ exit(1);
+ }
if (init_yes() < 0) {
(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
@@ -737,7 +786,12 @@ main(int argc, char *argv[])
case '@':
atflag++;
break;
-#endif
+#endif /* O_XATTR */
+#if defined(_PC_SATTR_ENABLED)
+ case '/':
+ saflag++;
+ break;
+#endif /* _PC_SATTR_ENABLED */
case 'u':
uflag++; /* moved code after signals caught */
rflag++;
@@ -1047,10 +1101,14 @@ usage(void)
if (sysv3_env) {
(void) fprintf(stderr, gettext(
#if defined(O_XATTR)
+#if defined(_PC_SATTR_ENABLED)
+ "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@/[0-7]][bfFk][X...] "
+#else
"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@[0-7]][bfFk][X...] "
+#endif /* _PC_SATTR_ENABLED */
#else
"Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw[0-7]][bfFk][X...] "
-#endif
+#endif /* O_XATTR */
"[blocksize] [tarfile] [filename] [size] [exclude-file...] "
"{file | -I include-file | -C directory file}...\n"));
} else
@@ -1058,10 +1116,14 @@ usage(void)
{
(void) fprintf(stderr, gettext(
#if defined(O_XATTR)
+#if defined(_PC_SATTR_ENABLED)
+ "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@/[0-7]][bfk][X...] "
+#else
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@[0-7]][bfk][X...] "
+#endif /* _PC_SATTR_ENABLED */
#else
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw[0-7]][bfk][X...] "
-#endif
+#endif /* O_XATTR */
"[blocksize] [tarfile] [size] [exclude-file...] "
"{file | -I include-file | -C directory file}...\n"));
}
@@ -1196,7 +1258,7 @@ dorep(char *argv[])
if (chdir(*++argv) < 0)
vperror(0, gettext(
- "can't change directories to %s"), *argv);
+ "can't change directories to %s"), *argv);
else
(void) getcwd(wdir, (sizeof (wdir)));
argv++;
@@ -1235,7 +1297,7 @@ dorep(char *argv[])
*cp2 = '\0';
if (chdir(file) < 0) {
vperror(0, gettext(
- "can't change directories to %s"), file);
+ "can't change directories to %s"), file);
continue;
}
*cp2 = '/';
@@ -1243,13 +1305,15 @@ dorep(char *argv[])
}
parent = getcwd(tempdir, (sizeof (tempdir)));
- archtype = putfile(file, cp2, parent, NORMAL_FILE,
+
+ archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
LEV0, SYMLINK_LEV0);
#if defined(O_XATTR)
if (!exitflag) {
- if (atflag && archtype == PUT_NOTAS_LINK) {
- xattrs_put(file, cp2, parent);
+ if ((atflag || saflag) &&
+ (archtype == PUT_NOTAS_LINK)) {
+ xattrs_put(file, cp2, parent, NULL);
}
}
#endif
@@ -1447,7 +1511,11 @@ top:
xattr_linkp = NULL;
xattrhead = NULL;
} else {
- if (xattraname[0] == '.' && xattraname[1] == '\0' &&
+ char *aname = basename(xattrapath);
+ size_t xindex = aname - xattrapath;
+
+ if (xattrapath[xindex] == '.' &&
+ xattrapath[xindex + 1] == '\0' &&
xattrp->h_typeflag == '5') {
Hiddendir = 1;
sp->st_mode =
@@ -1495,9 +1563,102 @@ passtape(void)
readtape(buf);
}
+#if defined(O_XATTR)
+static int
+is_sysattr(char *name)
+{
+ return ((strcmp(name, VIEW_READONLY) == 0) ||
+ (strcmp(name, VIEW_READWRITE) == 0));
+}
+#endif
+
+#if defined(O_XATTR)
+/*
+ * Verify the attribute, attrname, is an attribute we want to restore.
+ * Never restore read-only system attribute files. Only restore read-write
+ * system attributes files when -/ was specified, and only traverse into
+ * the 2nd level attribute directory containing only system attributes if
+ * -@ was specified. This keeps us from archiving
+ * <attribute name>/<read-write system attribute file>
+ * when -/ was specified without -@.
+ *
+ * attrname - attribute file name
+ * attrparent - attribute's parent name within the base file's attribute
+ * directory hierarchy
+ */
+static attr_status_t
+verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
+ int *rw_sysattr)
+{
+#if defined(_PC_SATTR_ENABLED)
+ int attr_supported;
+
+ /* Never restore read-only system attribute files */
+ if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
+ *rw_sysattr = 0;
+ return (ATTR_SKIP);
+ } else {
+ *rw_sysattr = (attr_supported == _RW_SATTR);
+ }
+#else
+ /*
+ * Only need to check if this attribute is an extended system
+ * attribute.
+ */
+ if (*rw_sysattr = is_sysattr(attrname)) {
+ return (ATTR_SKIP);
+ } else {
+ return (ATTR_OK);
+ }
+#endif /* _PC_SATTR_ENABLED */
+
+ /*
+ * If the extended system attribute file is specified with the
+ * arc_rwsysattr flag, as being transient (default extended
+ * attributes), then don't archive it.
+ */
+ if (*rw_sysattr && !arc_rwsysattr) {
+ return (ATTR_SKIP);
+ }
+
+ /*
+ * Only restore read-write system attribute files
+ * when -/ was specified. Only restore extended
+ * attributes when -@ was specified.
+ */
+ if (atflag) {
+ if (!saflag) {
+ /*
+ * Only archive/restore the hidden directory "." if
+ * we're processing the top level hidden attribute
+ * directory. We don't want to process the
+ * hidden attribute directory of the attribute
+ * directory that contains only extended system
+ * attributes.
+ */
+ if (*rw_sysattr || (Hiddendir &&
+ (attrparent != NULL))) {
+ return (ATTR_SKIP);
+ }
+ }
+ } else if (saflag) {
+ /*
+ * Only archive/restore read-write extended system attribute
+ * files of the base file.
+ */
+ if (!*rw_sysattr || (attrparent != NULL)) {
+ return (ATTR_SKIP);
+ }
+ } else {
+ return (ATTR_SKIP);
+ }
+
+ return (ATTR_OK);
+}
+#endif
static int
-putfile(char *longname, char *shortname, char *parent,
+putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
int filetype, int lev, int symlink_lev)
{
int infile = -1; /* deliberately invalid */
@@ -1509,6 +1670,8 @@ putfile(char *longname, char *shortname, char *parent,
char filetmp[PATH_MAX + 1];
char *cp;
char *name;
+ char *attrparent = NULL;
+ char *longattrname = NULL;
struct dirent *dp;
DIR *dirp;
int i;
@@ -1517,6 +1680,7 @@ putfile(char *longname, char *shortname, char *parent,
int dirfd = -1;
int rc = PUT_NOTAS_LINK;
int archtype = 0;
+ int rw_sysattr = 0;
char newparent[PATH_MAX + MAXNAMLEN + 1];
char *prefix = "";
char *tmpbuf;
@@ -1533,28 +1697,24 @@ putfile(char *longname, char *shortname, char *parent,
xhdr_flgs = 0;
if (filetype == XATTR_FILE) {
- dirfd = attropen(get_component(longname), ".", O_RDONLY);
+ attrparent = attrinfo->attr_parent;
+ longattrname = attrinfo->attr_path;
+ dirfd = attrinfo->attr_parentfd;
} else {
dirfd = open(".", O_RDONLY);
}
if (dirfd == -1) {
(void) fprintf(stderr, gettext(
- "tar: unable to open%sdirectory %s\n"),
+ "tar: unable to open%sdirectory %s%s%s%s\n"),
(filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
+ (attrparent == NULL) ? "" : gettext("of attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
(filetype == XATTR_FILE) ? longname : parent);
goto out;
}
- if (filetype == XATTR_FILE) {
- if (fchdir(dirfd) < 0) {
- (void) fprintf(stderr, gettext(
- "tar: unable to fchdir into attribute directory"
- " of file %s\n"), longname);
- goto out;
- }
- }
-
if (lev > MAXLEV) {
(void) fprintf(stderr,
gettext("tar: directory nesting too deep, %s not dumped\n"),
@@ -1562,7 +1722,7 @@ putfile(char *longname, char *shortname, char *parent,
goto out;
}
- if (getstat(dirfd, longname, shortname))
+ if (getstat(dirfd, longname, shortname, attrparent))
goto out;
if (hflag) {
@@ -1588,7 +1748,12 @@ putfile(char *longname, char *shortname, char *parent,
*/
if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
(void) fprintf(stderr, gettext(
- "tar: %s same as archive file\n"), longname);
+ "tar: %s%s%s%s%s same as archive file\n"),
+ rw_sysattr ? gettext("system ") : "",
+ (longattrname == NULL) ? "" : gettext("attribute "),
+ (longattrname == NULL) ? "" : longattrname,
+ (longattrname == NULL) ? "" : gettext(" of "),
+ longname);
Errflg = 1;
goto out;
}
@@ -1605,8 +1770,13 @@ putfile(char *longname, char *shortname, char *parent,
!S_ISBLK(stbuf.st_mode) &&
(Eflag == 0)) {
(void) fprintf(stderr, gettext(
- "tar: %s too large to archive. "
- "Use E function modifier.\n"), longname);
+ "tar: %s%s%s%s%s too large to archive. "
+ "Use E function modifier.\n"),
+ rw_sysattr ? gettext("system ") : "",
+ (longattrname == NULL) ? "" : gettext("attribute "),
+ (longattrname == NULL) ? "" : longattrname,
+ (longattrname == NULL) ? "" : gettext(" of "),
+ longname);
if (errflag)
exitflag = 1;
Errflg = 1;
@@ -1787,8 +1957,8 @@ putfile(char *longname, char *shortname, char *parent,
}
}
- if (put_extra_attributes(longname, shortname, prefix,
- filetype, '5') != 0)
+ if (put_extra_attributes(longname, shortname,
+ longattrname, prefix, filetype, '5') != 0)
goto out;
#if defined(O_XATTR)
@@ -1817,8 +1987,8 @@ putfile(char *longname, char *shortname, char *parent,
0);
#endif
if (filetype == XATTR_FILE && Hiddendir) {
- (void) fprintf(vfile, "a %s attribute . ",
- longname);
+ (void) fprintf(vfile, "a %s attribute %s ",
+ longname, longattrname);
} else {
(void) fprintf(vfile, "a %s/ ", longname);
@@ -1835,9 +2005,9 @@ putfile(char *longname, char *shortname, char *parent,
* If hidden dir then break now since xattrs_put() will do
* the iterating of the directory.
*
- * At the moment, there can't be attributes on attributes
- * or directories within the attributes hidden directory
- * hierarchy.
+ * At the moment, there can only be system attributes on
+ * attributes. There can be no attributes on attributes or
+ * directories within the attributes hidden directory hierarchy.
*/
if (filetype == XATTR_FILE)
break;
@@ -1854,7 +2024,7 @@ putfile(char *longname, char *shortname, char *parent,
if ((dirp = opendir(".")) == NULL) {
vperror(0, gettext(
- "can't open directory %s"), longname);
+ "can't open directory %s"), longname);
if (chdir(parent) < 0)
vperror(0, gettext("cannot change back?: %s"),
parent);
@@ -1873,12 +2043,13 @@ putfile(char *longname, char *shortname, char *parent,
} else
l = -1;
- archtype = putfile(buf, cp, newparent,
+ archtype = putfile(buf, cp, newparent, NULL,
NORMAL_FILE, lev + 1, symlink_lev);
if (!exitflag) {
- if (atflag && archtype == PUT_NOTAS_LINK) {
- xattrs_put(buf, cp, newparent);
+ if ((atflag || saflag) &&
+ (archtype == PUT_NOTAS_LINK)) {
+ xattrs_put(buf, cp, newparent, NULL);
}
}
if (exitflag)
@@ -1962,17 +2133,18 @@ putfile(char *longname, char *shortname, char *parent,
break;
case S_IFREG:
if ((infile = openat(dirfd, shortname, 0)) < 0) {
- vperror(0, "%s%s%s", longname,
+ vperror(0, "unable to open %s%s%s%s", longname,
+ rw_sysattr ? gettext(" system") : "",
(filetype == XATTR_FILE) ?
gettext(" attribute ") : "",
- (filetype == XATTR_FILE) ?
- shortname : "");
+ (filetype == XATTR_FILE) ? (longattrname == NULL) ?
+ shortname : longattrname : "");
goto out;
}
blocks = TBLOCKS(stbuf.st_size);
- if (put_link(name, longname, shortname,
+ if (put_link(name, longname, shortname, longattrname,
prefix, filetype, '1') == 0) {
(void) close(infile);
rc = PUT_AS_LINK;
@@ -2018,11 +2190,12 @@ putfile(char *longname, char *shortname, char *parent,
DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
0);
#endif
- (void) fprintf(vfile, "a %s%s%s ", longname,
- (filetype == XATTR_FILE) ?
- gettext(" attribute ") : "",
+ (void) fprintf(vfile, "a %s%s%s%s ", longname,
+ rw_sysattr ? gettext(" system") : "",
+ (filetype == XATTR_FILE) ? gettext(
+ " attribute ") : "",
(filetype == XATTR_FILE) ?
- shortname : "");
+ longattrname : "");
if (NotTape)
(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
K(blocks));
@@ -2032,8 +2205,8 @@ putfile(char *longname, char *shortname, char *parent,
blocks);
}
- if (put_extra_attributes(longname, shortname, prefix,
- filetype, '0') != 0)
+ if (put_extra_attributes(longname, shortname, longattrname,
+ prefix, filetype, '0') != 0)
goto out;
/*
@@ -2082,7 +2255,7 @@ putfile(char *longname, char *shortname, char *parent,
blocks = TBLOCKS(stbuf.st_size);
stbuf.st_size = (off_t)0;
- if (put_link(name, longname, shortname,
+ if (put_link(name, longname, shortname, longattrname,
prefix, filetype, '6') == 0) {
rc = PUT_AS_LINK;
goto out;
@@ -2132,8 +2305,8 @@ putfile(char *longname, char *shortname, char *parent,
&stbuf, stbuf.st_dev, prefix) != 0)
goto out;
- if (put_extra_attributes(longname, shortname, prefix,
- filetype, '6') != 0)
+ if (put_extra_attributes(longname, shortname, longattrname,
+ prefix, filetype, '6') != 0)
goto out;
(void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
@@ -2144,8 +2317,8 @@ putfile(char *longname, char *shortname, char *parent,
case S_IFCHR:
stbuf.st_size = (off_t)0;
blocks = TBLOCKS(stbuf.st_size);
- if (put_link(name, longname,
- shortname, prefix, filetype, '3') == 0) {
+ if (put_link(name, longname, shortname, longattrname,
+ prefix, filetype, '3') == 0) {
rc = PUT_AS_LINK;
goto out;
}
@@ -2193,7 +2366,7 @@ putfile(char *longname, char *shortname, char *parent,
filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
goto out;
- if (put_extra_attributes(longname, shortname,
+ if (put_extra_attributes(longname, shortname, longattrname,
prefix, filetype, '3') != 0)
goto out;
@@ -2205,8 +2378,8 @@ putfile(char *longname, char *shortname, char *parent,
case S_IFBLK:
stbuf.st_size = (off_t)0;
blocks = TBLOCKS(stbuf.st_size);
- if (put_link(name, longname,
- shortname, prefix, filetype, '4') == 0) {
+ if (put_link(name, longname, shortname, longattrname,
+ prefix, filetype, '4') == 0) {
rc = PUT_AS_LINK;
goto out;
}
@@ -2254,7 +2427,7 @@ putfile(char *longname, char *shortname, char *parent,
filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
goto out;
- if (put_extra_attributes(longname, shortname,
+ if (put_extra_attributes(longname, shortname, longattrname,
prefix, filetype, '4') != 0)
goto out;
@@ -2273,9 +2446,7 @@ putfile(char *longname, char *shortname, char *parent,
}
out:
- if (dirfd != -1) {
- if (filetype == XATTR_FILE)
- (void) chdir(parent);
+ if ((dirfd != -1) && (filetype != XATTR_FILE)) {
(void) close(dirfd);
}
return (rc);
@@ -2417,6 +2588,210 @@ convtoreg(off_t size)
return (0);
}
+#if defined(O_XATTR)
+static int
+save_cwd(void)
+{
+ return (open(".", O_RDONLY));
+}
+#endif
+
+#if defined(O_XATTR)
+static void
+rest_cwd(int *cwd)
+{
+ if (*cwd != -1) {
+ if (fchdir(*cwd) < 0) {
+ vperror(0, gettext(
+ "Cannot fchdir to attribute directory"));
+ exit(1);
+ }
+ (void) close(*cwd);
+ *cwd = -1;
+ }
+}
+#endif
+
+/*
+ * Verify the underlying file system supports the attribute type.
+ * Only archive extended attribute files when '-@' was specified.
+ * Only archive system extended attribute files if '-/' was specified.
+ */
+#if defined(O_XATTR)
+static attr_status_t
+verify_attr_support(char *filename, arc_action_t actflag)
+{
+ /*
+ */
+ if (atflag) {
+ /* Verify extended attributes are supported */
+ if (pathconf(filename, (actflag == ARC_CREATE) ?
+ _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) != 1) {
+#if defined(_PC_SATTR_ENABLED)
+ if (saflag) {
+ /* Verify system attributes are supported */
+ if (sysattr_support(filename,
+ (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
+ _PC_SATTR_ENABLED) != 1) {
+ return (ATTR_SATTR_ERR);
+ }
+ } else
+ return (ATTR_XATTR_ERR);
+#else
+ return (ATTR_XATTR_ERR);
+#endif /* _PC_SATTR_ENABLED */
+ }
+
+#if defined(_PC_SATTR_ENABLED)
+ } else if (saflag) {
+ /* Verify system attributes are supported */
+ if (sysattr_support(filename, (actflag == ARC_CREATE) ?
+ _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
+ return (ATTR_SATTR_ERR);
+ }
+#endif /* _PC_SATTR_ENABLED */
+ } else {
+ return (ATTR_SKIP);
+ }
+
+ return (ATTR_OK);
+}
+#endif
+
+#if defined(O_XATTR)
+/*
+ * Recursively open attribute directories until the attribute directory
+ * containing the specified attribute, attrname, is opened.
+ *
+ * Currently, only 2 directory levels of attributes are supported, (i.e.,
+ * extended system attributes on extended attributes). The following are
+ * the possible input combinations:
+ * 1. Open the attribute directory of the base file (don't change
+ * into it).
+ * attrinfo->parent = NULL
+ * attrname = '.'
+ * 2. Open the attribute directory of the base file and change into it.
+ * attrinfo->parent = NULL
+ * attrname = <attr> | <sys_attr>
+ * 3. Open the attribute directory of the base file, change into it,
+ * then recursively call open_attr_dir() to open the attribute's
+ * parent directory (don't change into it).
+ * attrinfo->parent = <attr>
+ * attrname = '.'
+ * 4. Open the attribute directory of the base file, change into it,
+ * then recursively call open_attr_dir() to open the attribute's
+ * parent directory and change into it.
+ * attrinfo->parent = <attr>
+ * attrname = <attr> | <sys_attr>
+ *
+ * An attribute directory will be opened only if the underlying file system
+ * supports the attribute type, and if the command line specifications (atflag
+ * and saflag) enable the processing of the attribute type.
+ *
+ * On succesful return, attrinfo->parentfd will be the file descriptor of the
+ * opened attribute directory. In addition, if the attribute is a read-write
+ * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
+ * it will be set to 0.
+ *
+ * Possible return values:
+ * ATTR_OK Successfully opened and, if needed, changed into the
+ * attribute directory containing attrname.
+ * ATTR_SKIP The command line specifications don't enable the
+ * processing of the attribute type.
+ * ATTR_CHDIR_ERR An error occurred while trying to change into an
+ * attribute directory.
+ * ATTR_OPEN_ERR An error occurred while trying to open an
+ * attribute directory.
+ * ATTR_XATTR_ERR The underlying file system doesn't support extended
+ * attributes.
+ * ATTR_SATTR_ERR The underlying file system doesn't support extended
+ * system attributes.
+ */
+static int
+open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
+{
+ attr_status_t rc;
+ int firsttime = (attrinfo->attr_parentfd == -1);
+ int saveerrno;
+
+ /*
+ * open_attr_dir() was recursively called (input combination number 4),
+ * close the previously opened file descriptor as we've already changed
+ * into it.
+ */
+ if (!firsttime) {
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ }
+
+ /*
+ * Verify that the underlying file system supports the restoration
+ * of the attribute.
+ */
+ if ((rc = verify_attr_support(dirp, ARC_RESTORE)) != ATTR_OK) {
+ return (rc);
+ }
+
+ /* Open the base file's attribute directory */
+ if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
+ /*
+ * Save the errno from the attropen so it can be reported
+ * if the retry of the attropen fails.
+ */
+ saveerrno = errno;
+ if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
+ NULL, ".", O_RDONLY, 0)) == -1) {
+ /*
+ * Reset typeflag back to real value so passtape
+ * will skip ahead correctly.
+ */
+ dblock.dbuf.typeflag = _XATTR_HDRTYPE;
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ errno = saveerrno;
+ return (ATTR_OPEN_ERR);
+ }
+ }
+
+ /*
+ * Change into the parent attribute's directory unless we are
+ * processing the hidden attribute directory of the base file itself.
+ */
+ if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
+ if (fchdir(attrinfo->attr_parentfd) != 0) {
+ saveerrno = errno;
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ errno = saveerrno;
+ return (ATTR_CHDIR_ERR);
+ }
+ }
+
+ /* Determine if the attribute should be processed */
+ if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
+ &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
+ saveerrno = errno;
+ (void) close(attrinfo->attr_parentfd);
+ attrinfo->attr_parentfd = -1;
+ errno = saveerrno;
+ return (rc);
+ }
+
+ /*
+ * If the attribute is an extended attribute, or extended system
+ * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
+ * recursively call open_attr_dir() to open the attribute directory
+ * of the parent attribute.
+ */
+ if (firsttime && (attrinfo->attr_parent != NULL)) {
+ return (open_attr_dir(attrname, attrinfo->attr_parent,
+ attrinfo->attr_parentfd, attrinfo));
+ }
+
+ return (ATTR_OK);
+}
+#endif
+
static void
#ifdef _iBCS2
doxtract(char *argv[], int tbl_cnt)
@@ -2433,15 +2808,18 @@ doxtract(char *argv[])
int fcnt = 0; /* count # files in argv list */
int dir;
int dirfd = -1;
+ int cwd = -1;
+ int rw_sysattr = 0;
+ int saveerrno;
uid_t Uid;
char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
char dirname[PATH_MAX+1];
char templink[PATH_MAX+1]; /* temp link with terminating NULL */
- char origdir[PATH_MAX+1];
int once = 1;
int error;
int symflag;
int want;
+ attr_data_t *attrinfo = NULL; /* attribute info */
acl_t *aclp = NULL; /* acl info */
char dot[] = "."; /* dirp for using realpath */
timestruc_t time_zero; /* used for call to doDirTimes */
@@ -2480,10 +2858,26 @@ doxtract(char *argv[])
dir = 0;
ofile = -1;
+ if (dirfd != -1) {
+ (void) close(dirfd);
+ dirfd = -1;
+ }
+ if (ofile != -1) {
+ if (close(ofile) != 0)
+ vperror(2, gettext("close error"));
+ }
+
+#if defined(O_XATTR)
+ if (cwd != -1) {
+ rest_cwd(&cwd);
+ }
+#endif
+
/* namep is set by wantit to point to the full name */
- if ((want = wantit(argv, &namep, &dirp, &comp)) == 0) {
+ if ((want = wantit(argv, &namep, &dirp, &comp,
+ &attrinfo)) == 0) {
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattr_linkp = NULL;
@@ -2522,51 +2916,49 @@ doxtract(char *argv[])
dircreate = checkdir(&dirname[0]);
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
- dirfd = attropen(dirp, ".", O_RDONLY);
- } else {
- dirfd = open(dirp, O_RDONLY);
- }
-#else
- dirfd = open(dirp, O_RDONLY);
-#endif
+ if (xattrp != NULL) {
+ int rc;
- if (dirfd == -1) {
-#if defined(O_XATTR)
- if (xattrp) {
- dirfd = retry_attrdir_open(dirp);
- }
-#endif
- if (dirfd == -1) {
-#if defined(O_XATTR)
- if (xattrp) {
+ if (((cwd = save_cwd()) == -1) ||
+ ((rc = open_attr_dir(comp, dirp, cwd,
+ attrinfo)) != ATTR_OK)) {
+ if (cwd == -1) {
+ vperror(0, gettext(
+ "unable to save current working "
+ "directory while processing "
+ "attribute %s of %s"),
+ dirp, attrinfo->attr_path);
+ } else if (rc != ATTR_SKIP) {
(void) fprintf(vfile,
gettext("tar: cannot open "
- "attribute %s of file %s: %s\n"),
- xattraname, dirp, strerror(errno));
- /*
- * Reset typeflag back to real
- * value so passtape will skip
- * ahead correctly.
- */
- dblock.dbuf.typeflag = _XATTR_HDRTYPE;
- free(xattrhead);
- xattrp = NULL;
- xattr_linkp = NULL;
- xattrhead = NULL;
- } else {
- (void) fprintf(vfile,
- gettext("tar: cannot open %s %s\n"),
- dirp, strerror(errno));
+ "%sattribute %s of file %s: %s\n"),
+ attrinfo->attr_rw_sysattr ? gettext(
+ "system ") : "",
+ comp, dirp, strerror(errno));
}
-#else
- (void) fprintf(vfile,
- gettext("tar: cannot open %s %s\n"),
- dirp, strerror(errno));
-#endif
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+
passtape();
continue;
+ } else {
+ dirfd = attrinfo->attr_parentfd;
+ rw_sysattr = attrinfo->attr_rw_sysattr;
}
+ } else {
+ dirfd = open(dirp, O_RDONLY);
+ }
+#else
+ dirfd = open(dirp, O_RDONLY);
+#endif
+ if (dirfd == -1) {
+ (void) fprintf(vfile, gettext(
+ "tar: cannot open %s: %s\n"),
+ dirp, strerror(errno));
+ passtape();
+ continue;
}
if (xhdr_flgs & _X_LINKPATH)
@@ -2635,18 +3027,51 @@ doxtract(char *argv[])
* Dir is automatically created, we only
* need to update mode and perm's.
*/
- if ((xattrp != (struct xattr_buf *)NULL) && Hiddendir == 1) {
- if (fchownat(dirfd, ".", stbuf.st_uid,
- stbuf.st_gid, 0) != 0) {
- vperror(0, gettext(
- "%s: failed to set ownership of attribute"
- " directory"), namep);
+ if ((xattrp != NULL) && Hiddendir == 1) {
+ bytes = stbuf.st_size;
+ blocks = TBLOCKS(bytes);
+ if (vflag) {
+ (void) fprintf(vfile,
+ "x %s%s%s, %" FMT_off_t " bytes, ", namep,
+ gettext(" attribute "),
+ xattrapath, bytes);
+ if (NotTape)
+ (void) fprintf(vfile,
+ "%" FMT_blkcnt_t "K\n", K(blocks));
+ else
+ (void) fprintf(vfile, gettext("%"
+ FMT_blkcnt_t " tape blocks\n"),
+ blocks);
}
- if (fchmod(dirfd, stbuf.st_mode) != 0) {
- vperror(0, gettext(
- "%s: failed to set permissions of"
- " attribute directory"), namep);
+ /*
+ * Set the permissions and mode of the attribute
+ * unless the attribute is a system attribute (can't
+ * successfully do this) or the hidden attribute
+ * directory (".") of an attribute (when the attribute
+ * is restored, the hidden attribute directory of an
+ * attribute is transient). Note: when the permissions
+ * and mode are set for the hidden attribute directory
+ * of a file on a system supporting extended system
+ * attributes, even though it returns successfully, it
+ * will not have any affect since the attribute
+ * directory is transient.
+ */
+ if (attrinfo->attr_parent == NULL) {
+ if (fchownat(dirfd, ".", stbuf.st_uid,
+ stbuf.st_gid, 0) != 0) {
+ vperror(0, gettext(
+ "%s%s%s: failed to set ownership "
+ "of attribute directory"), namep,
+ gettext(" attribute "), xattrapath);
+ }
+
+ if (fchmod(dirfd, stbuf.st_mode) != 0) {
+ vperror(0, gettext(
+ "%s%s%s: failed to set permissions "
+ "of attribute directory"), namep,
+ gettext(" attribute "), xattrapath);
+ }
}
goto filedone;
}
@@ -2683,7 +3108,8 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), namep, linkp);
+ "x %s linked to %s\n"), namep,
+ linkp);
xcnt++; /* increment # files extracted */
continue;
}
@@ -2723,14 +3149,15 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), namep, linkp);
+ "x %s linked to %s\n"), namep,
+ linkp);
xcnt++; /* increment # files extracted */
continue;
}
if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
(int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
vperror(0, gettext(
- "%s: mknod failed"), namep);
+ "%s: mknod failed"), namep);
continue;
}
bytes = stbuf.st_size;
@@ -2771,7 +3198,8 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), namep, linkp);
+ "x %s linked to %s\n"), namep,
+ linkp);
xcnt++; /* increment # files extracted */
continue;
}
@@ -2833,28 +3261,16 @@ doxtract(char *argv[])
}
#if defined(O_XATTR)
if (xattrp && xattr_linkp) {
- if (getcwd(origdir, (PATH_MAX+1)) ==
- (char *)NULL) {
- vperror(0, gettext(
- "A parent directory cannot"
- " be read"));
- exit(1);
- }
-
if (fchdir(dirfd) < 0) {
vperror(0, gettext(
"Cannot fchdir to attribute "
- "directory"));
+ "directory %s"),
+ (attrinfo->attr_parent == NULL) ?
+ dirp : attrinfo->attr_parent);
exit(1);
}
- error = link(xattr_linkaname, xattraname);
- if (chdir(origdir) < 0) {
- vperror(0, gettext(
- "Cannot chdir out of attribute "
- "directory"));
- exit(1);
- }
+ error = link(xattr_linkaname, xattrapath);
} else {
error = link(linkp, namep);
}
@@ -2868,23 +3284,23 @@ doxtract(char *argv[])
namep, (xattr_linkp != NULL) ?
gettext(" attribute ") : "",
(xattr_linkp != NULL) ?
- xattraname : "");
+ xattrapath : "");
continue;
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s%s%s linked to %s%s%s\n"), namep,
+ "x %s%s%s linked to %s%s%s\n"), namep,
(xattr_linkp != NULL) ?
gettext(" attribute ") : "",
(xattr_linkp != NULL) ?
xattr_linkaname : "",
- linkp, (xattr_linkp != NULL) ?
- gettext(" attribute ") : "",
+ linkp,
(xattr_linkp != NULL) ?
- xattraname : "");
+ gettext(" attribute ") : "",
+ (xattr_linkp != NULL) ? xattrapath : "");
xcnt++; /* increment # files extracted */
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattr_linkp = NULL;
@@ -2925,20 +3341,58 @@ doxtract(char *argv[])
}
if (vflag)
(void) fprintf(vfile, gettext(
- "%s linked to %s\n"), comp, linkp);
+ "x %s linked to %s\n"), comp,
+ linkp);
xcnt++; /* increment # files extracted */
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
continue;
}
newfile = ((fstatat(dirfd, comp,
&xtractbuf, 0) == -1) ? TRUE : FALSE);
- if ((ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
- stbuf.st_mode & MODEMASK)) < 0) {
+ ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
+ stbuf.st_mode & MODEMASK);
+ saveerrno = errno;
+
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ if (ofile < 0) {
+ ofile = retry_open_attr(dirfd, cwd,
+ dirp, attrinfo->attr_parent, comp,
+ O_RDWR|O_CREAT|O_TRUNC,
+ stbuf.st_mode & MODEMASK);
+ }
+ }
+#endif
+ if (ofile < 0) {
+ errno = saveerrno;
(void) fprintf(stderr, gettext(
- "tar: %s - cannot create\n"), comp);
+ "tar: %s%s%s%s - cannot create\n"),
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribure ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" : gettext(" of "),
+ (xattrp == NULL) ? comp : namep);
if (errflag)
done(1);
else
Errflg = 1;
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ dblock.dbuf.typeflag = _XATTR_HDRTYPE;
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
passtape();
continue;
}
@@ -2955,11 +3409,17 @@ doxtract(char *argv[])
if (extno != 0) { /* file is in pieces */
if (extotal < 1 || extotal > MAXEXT)
(void) fprintf(stderr, gettext(
- "tar: ignoring bad extent info for %s\n"),
- comp);
+ "tar: ignoring bad extent info for "
+ "%s%s%s%s\n"),
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribute ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" : gettext(" of "),
+ (xattrp == NULL) ? comp : namep);
else {
- xsfile(ofile); /* extract it */
- goto filedone;
+ /* extract it */
+ (void) xsfile(rw_sysattr, ofile);
}
}
extno = 0; /* let everyone know file is not split */
@@ -2969,8 +3429,10 @@ doxtract(char *argv[])
(void) fprintf(vfile,
"x %s%s%s, %" FMT_off_t " bytes, ",
(xattrp == NULL) ? "" : dirp,
- (xattrp == NULL) ? "" : gettext(" attribute "),
- (xattrp == NULL) ? namep : comp, bytes);
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext(" system attribute ") :
+ gettext(" attribute ")),
+ (xattrp == NULL) ? namep : xattrapath, bytes);
if (NotTape)
(void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
K(blocks));
@@ -2979,18 +3441,50 @@ doxtract(char *argv[])
FMT_blkcnt_t " tape blocks\n"), blocks);
}
- xblocks(bytes, ofile);
+ if (xblocks(rw_sysattr, bytes, ofile) != 0) {
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
+ continue;
+ }
filedone:
if (mflag == 0 && !symflag) {
if (dir)
doDirTimes(namep, stbuf.st_mtim);
+
else
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ /*
+ * Set the time on the attribute unless
+ * the attribute is a system attribute
+ * (can't successfully do this) or the
+ * hidden attribute directory, "." (the
+ * time on the hidden attribute
+ * directory will be updated when
+ * attributes are restored, otherwise
+ * it's transient).
+ */
+ if (!rw_sysattr && (Hiddendir == 0)) {
+ setPathTimes(dirfd, comp,
+ stbuf.st_mtim);
+ }
+ } else
+ setPathTimes(dirfd, comp,
+ stbuf.st_mtim);
+#else
setPathTimes(dirfd, comp, stbuf.st_mtim);
+#endif
}
/* moved this code from above */
if (pflag && !symflag && Hiddendir == 0) {
- if (xattrp != (struct xattr_buf *)NULL)
+ if (xattrp != NULL)
(void) fchmod(ofile, stbuf.st_mode & MODEMASK);
else
(void) chmod(namep, stbuf.st_mode & MODEMASK);
@@ -3007,7 +3501,7 @@ filedone:
int ret;
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
if (Hiddendir)
ret = facl_set(dirfd, aclp);
else
@@ -3021,8 +3515,14 @@ filedone:
if (ret < 0) {
if (pflag) {
(void) fprintf(stderr, gettext(
- "%s: failed to set acl entries\n"),
- namep);
+ "%s%s%s%s: failed to set acl "
+ "entries\n"), namep,
+ (xattrp == NULL) ? "" :
+ (rw_sysattr ? gettext(
+ " system attribute ") :
+ gettext(" attribute ")),
+ (xattrp == NULL) ? "" :
+ xattrapath);
}
/* else: silent and continue */
}
@@ -3031,7 +3531,7 @@ filedone:
}
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattr_linkp = NULL;
@@ -3048,15 +3548,29 @@ filedone:
convflag || dblock.dbuf.typeflag == '1')) {
if (fstat(ofile, &xtractbuf) == -1)
(void) fprintf(stderr, gettext(
- "tar: cannot stat extracted file %s\n"),
- namep);
+ "tar: cannot stat extracted file "
+ "%s%s%s%s\n"),
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribute ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" :
+ gettext(" of "), namep);
+
else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
!= (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
(void) fprintf(stderr, gettext(
"tar: warning - file permissions have "
- "changed for %s (are 0%o, should be "
+ "changed for %s%s%s%s (are 0%o, should be "
"0%o)\n"),
- namep, xtractbuf.st_mode, stbuf.st_mode);
+ (xattrp == NULL) ? "" : (rw_sysattr ?
+ gettext("system attribute ") :
+ gettext("attribute ")),
+ (xattrp == NULL) ? "" : xattrapath,
+ (xattrp == NULL) ? "" :
+ gettext(" of "), namep,
+ xtractbuf.st_mode, stbuf.st_mode);
+
}
}
if (ofile != -1) {
@@ -3064,6 +3578,7 @@ filedone:
dirfd = -1;
if (close(ofile) != 0)
vperror(2, gettext("close error"));
+ ofile = -1;
}
xcnt++; /* increment # files extracted */
}
@@ -3188,8 +3703,9 @@ filedone:
tp += attrsize;
} while (bytes != 0);
free(secp);
- } else
+ } else {
passtape();
+ }
} /* acl */
} /* for */
@@ -3202,6 +3718,15 @@ filedone:
doDirTimes(NULL, time_zero);
+#if defined(O_XATTR)
+ if (xattrp != NULL) {
+ free(xattrhead);
+ xattrp = NULL;
+ xattr_linkp = NULL;
+ xattrhead = NULL;
+ }
+#endif
+
/*
* Check if the number of files extracted is different from the
* number of files listed on the command line
@@ -3223,8 +3748,8 @@ filedone:
* called by doxtract() and xsfile()
*/
-static void
-xblocks(off_t bytes, int ofile)
+static int
+xblocks(int issysattr, off_t bytes, int ofile)
{
blkcnt_t blocks;
char buf[TBLOCK];
@@ -3239,17 +3764,36 @@ xblocks(off_t bytes, int ofile)
else
write_count = bytes;
if (write(ofile, buf, write_count) < 0) {
+ int saveerrno = errno;
+
if (xhdr_flgs & _X_PATH)
(void) strcpy(tempname, Xtarhdr.x_path);
else
(void) sprintf(tempname, "%.*s", NAMSIZ,
dblock.dbuf.name);
- (void) fprintf(stderr, gettext(
- "tar: %s: HELP - extract write error\n"), tempname);
- done(2);
+ /*
+ * If the extended system attribute being extracted
+ * contains attributes that the user needs privileges
+ * for, then just display a warning message, skip
+ * the extraction of this file, and return.
+ */
+ if ((saveerrno == EPERM) && issysattr) {
+ (void) fprintf(stderr, gettext(
+ "tar: unable to extract system attribute "
+ "%s: insufficient privileges\n"), tempname);
+ Errflg = 1;
+ return (1);
+ } else {
+ (void) fprintf(stderr, gettext(
+ "tar: %s: HELP - extract write error\n"),
+ tempname);
+ done(2);
+ }
}
bytes -= TBLOCK;
}
+
+ return (0);
}
@@ -3265,10 +3809,11 @@ xblocks(off_t bytes, int ofile)
static union hblock savedblock; /* to ensure same file across volumes */
-static void
-xsfile(int ofd)
+static int
+xsfile(int issysattr, int ofd)
{
int i, c;
+ int sysattrerr = 0;
char name[PATH_MAX+1]; /* holds name for diagnostics */
int extents, totalext;
off_t bytes, totalbytes;
@@ -3295,7 +3840,11 @@ canit:
passtape();
if (close(ofd) != 0)
vperror(2, gettext("close error"));
- return;
+ if (sysattrerr) {
+ return (1);
+ } else {
+ return (0);
+ }
}
}
extents = extotal;
@@ -3312,7 +3861,10 @@ canit:
(void) fprintf(vfile, "+++ x %s [extent #%d], %"
FMT_off_t " bytes, %ldK\n", name, extno, bytes,
(long)K(TBLOCKS(bytes)));
- xblocks(bytes, ofd);
+ if (xblocks(issysattr, bytes, ofd) != 0) {
+ sysattrerr = 1;
+ goto canit;
+ }
totalbytes += bytes;
totalext++;
@@ -3361,6 +3913,8 @@ asknicely:
(void) fprintf(vfile, gettext(
"x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
+
+ return (0);
}
@@ -3394,7 +3948,6 @@ notsame(void)
(strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
}
-
static void
#ifdef _iBCS2
dotable(char *argv[], int tbl_cnt)
@@ -3409,7 +3962,7 @@ dotable(char *argv[])
int want;
char aclchar = ' '; /* either blank or '+' */
char templink[PATH_MAX+1];
- char *np;
+ attr_data_t *attrinfo = NULL;
dumping = 0;
@@ -3436,7 +3989,7 @@ dotable(char *argv[])
for (;;) {
/* namep is set by wantit to point to the full name */
- if ((want = wantit(argv, &namep, &dirp, &comp)) == 0)
+ if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
continue;
if (want == -1)
break;
@@ -3460,11 +4013,27 @@ dotable(char *argv[])
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
- np = xattrp->h_names + strlen(xattrp->h_names) + 1;
- (void) printf(gettext("%s attribute %s"),
- xattrp->h_names, np);
+ if (xattrp != NULL) {
+ int issysattr;
+ char *bn = basename(attrinfo->attr_path);
+
+ /*
+ * We could use sysattr_type() to test whether or not
+ * the attribute we are processing is really an
+ * extended system attribute, which as of this writing
+ * just does a strcmp(), however, sysattr_type() may
+ * be changed to issue a pathconf() call instead, which
+ * would require being changed into the parent attribute
+ * directory. So instead, just do simple string
+ * comparisons to see if we are processing an extended
+ * system attribute.
+ */
+ issysattr = is_sysattr(bn);
+ (void) printf(gettext("%s %sattribute %s"),
+ xattrp->h_names,
+ issysattr ? gettext("system ") : "",
+ attrinfo->attr_path);
} else {
(void) printf("%s", namep);
}
@@ -3486,7 +4055,7 @@ dotable(char *argv[])
(void) strcpy(templink, Xtarhdr.x_linkpath);
} else {
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
(void) sprintf(templink,
"file %.*s", NAMSIZ, xattrp->h_names);
} else {
@@ -3507,7 +4076,7 @@ dotable(char *argv[])
* <subject> linked to %s
*/
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
(void) printf(
gettext(" linked to attribute %s"),
xattr_linkp->h_names +
@@ -3533,7 +4102,7 @@ dotable(char *argv[])
" symbolic link to %s"), templink);
(void) printf("\n");
#if defined(O_XATTR)
- if (xattrp != (struct xattr_buf *)NULL) {
+ if (xattrp != NULL) {
free(xattrhead);
xattrp = NULL;
xattrhead = NULL;
@@ -5027,7 +5596,8 @@ mterr(char *operation, int i, int exitcode)
}
static int
-wantit(char *argv[], char **namep, char **dirp, char **component)
+wantit(char *argv[], char **namep, char **dirp, char **component,
+ attr_data_t **attrinfo)
{
char **cp;
int gotit; /* true if we've found a match */
@@ -5044,17 +5614,29 @@ top:
#if defined(O_XATTR)
if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
- if (atflag || tflag) {
- (void) read_xattr_hdr();
- } else {
- passtape();
- }
+ /*
+ * Always needs to read the extended header. If atflag, saflag,
+ * or tflag isn't set, then we'll have the correct info for
+ * passtape() later.
+ */
+ (void) read_xattr_hdr(attrinfo);
goto top;
}
+ /*
+ * Now that we've read the extended header, call passtape() if we aren't
+ * processing extended attributes.
+ */
+ if ((xattrp != NULL) && !atflag && !saflag && !tflag) {
+ passtape();
+ return (0);
+ }
#endif
/* sets *namep to point at the proper name */
- check_prefix(namep, dirp, component);
+ if (check_prefix(namep, dirp, component) != 0) {
+ passtape();
+ return (0);
+ }
if (endtape()) {
if (Bflag) {
@@ -5104,13 +5686,96 @@ top:
return (1);
}
+static int
+fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
+ int rw_sysattr, attr_data_t **attrinfo)
+{
+ size_t pathlen;
+ char *tpath;
+ char *tparent;
+
+ /* parent info */
+ if (attrparent != NULL) {
+ if ((tparent = strdup(attrparent)) == NULL) {
+ vperror(0, gettext(
+ "unable to allocate memory for attribute parent "
+ "name for %sattribute %s/%s of %s"),
+ rw_sysattr ? gettext("system ") : "",
+ attrparent, attr, longname);
+ return (1);
+ }
+ } else {
+ tparent = NULL;
+ }
+
+ /* path info */
+ pathlen = strlen(attr) + 1;
+ if (attrparent != NULL) {
+ pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
+ }
+ if ((tpath = calloc(1, pathlen)) == NULL) {
+ vperror(0, gettext(
+ "unable to allocate memory for full "
+ "attribute path name for %sattribute %s%s%s of %s"),
+ rw_sysattr ? gettext("system ") : "",
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : "/",
+ attr, longname);
+ if (tparent != NULL) {
+ free(tparent);
+ }
+ return (1);
+ }
+ (void) snprintf(tpath, pathlen, "%s%s%s",
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : "/",
+ attr);
+
+ /* fill in the attribute info */
+ if (*attrinfo == NULL) {
+ if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
+ vperror(0, gettext(
+ "unable to allocate memory for attribute "
+ "information for %sattribute %s%s%s of %s"),
+ rw_sysattr ? gettext("system ") : "",
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext("/"),
+ attr, longname);
+ if (tparent != NULL) {
+ free(tparent);
+ }
+ free(tpath);
+ return (1);
+ }
+ } else {
+ if ((*attrinfo)->attr_parent != NULL) {
+ free((*attrinfo)->attr_parent);
+ }
+ if ((*attrinfo)->attr_path != NULL) {
+ free((*attrinfo)->attr_path);
+ }
+ /*
+ * The parent file descriptor is passed in, so don't
+ * close it here as it should be closed by the function
+ * that opened it.
+ */
+ }
+ (*attrinfo)->attr_parent = tparent;
+ (*attrinfo)->attr_path = tpath;
+ (*attrinfo)->attr_rw_sysattr = rw_sysattr;
+ (*attrinfo)->attr_parentfd = atparentfd;
+
+ return (0);
+}
/*
* Return through *namep a pointer to the proper fullname (i.e "<name> |
* <prefix>/<name>"), as represented in the header entry dblock.dbuf.
+ *
+ * Returns 0 if successful, otherwise returns 1.
*/
-static void
+static int
check_prefix(char **namep, char **dirp, char **compp)
{
static char fullname[PATH_MAX + 1];
@@ -5140,7 +5805,7 @@ check_prefix(char **namep, char **dirp, char **compp)
get_parent(fullname, dir);
#if defined(O_XATTR)
- if (xattrp == (struct xattr_buf *)NULL) {
+ if (xattrp == NULL) {
#endif
/*
* Save of real name since were going to chop off the
@@ -5158,13 +5823,15 @@ check_prefix(char **namep, char **dirp, char **compp)
} else {
(void) strcpy(fullname, xattrp->h_names);
(void) strcpy(dir, fullname);
- (void) strcpy(component, xattrp->h_names +
- strlen(xattrp->h_names) + 1);
+ (void) strcpy(component, basename(xattrp->h_names +
+ strlen(xattrp->h_names) + 1));
}
#endif
*namep = fullname;
*dirp = dir;
*compp = component;
+
+ return (0);
}
/*
@@ -6540,12 +7207,13 @@ static void
prepare_xattr(
char **attrbuf,
char *filename,
- char *attrname,
+ char *attrpath,
char typeflag,
struct linkbuf *linkinfo,
int *rlen)
{
char *bufhead; /* ptr to full buffer */
+ char *aptr;
struct xattr_hdr *hptr; /* ptr to header in bufhead */
struct xattr_buf *tptr; /* ptr to pathing pieces */
int totalen; /* total buffer length */
@@ -6558,6 +7226,7 @@ prepare_xattr(
int linkstringlen;
int complen; /* length of pathing section */
int linklen; /* length of link section */
+ int attrnames_index; /* attrnames starting index */
/*
* Release previous buffer
@@ -6576,7 +7245,7 @@ prepare_xattr(
/*
* Add space for two nulls
*/
- stringlen = strlen(attrname) + strlen(filename) + 2;
+ stringlen = strlen(attrpath) + strlen(filename) + 2;
complen = stringlen + sizeof (struct xattr_buf);
len += stringlen;
@@ -6591,7 +7260,10 @@ prepare_xattr(
*/
linkstringlen = strlen(linkinfo->pathname) +
strlen(linkinfo->attrname) + 2;
- len += linkstringlen;
+ linklen = linkstringlen + sizeof (struct xattr_buf);
+ len += linklen;
+ } else {
+ linklen = 0;
}
/*
@@ -6611,12 +7283,6 @@ prepare_xattr(
* Now we can fill in the necessary pieces
*/
- if (linkinfo != (struct linkbuf *)NULL) {
- linklen = linkstringlen + (sizeof (struct xattr_buf));
- } else {
- linklen = 0;
- }
-
/*
* first fill in the fixed header
*/
@@ -6630,16 +7296,39 @@ prepare_xattr(
/*
* Now fill in the filename + attrnames section
+ * The filename and attrnames section can be composed of two or more
+ * path segments separated by a null character. The first segment
+ * is the path to the parent file that roots the entire sequence in
+ * the normal name space. The remaining segments describes a path
+ * rooted at the hidden extended attribute directory of the leaf file of
+ * the previous segment, making it possible to name attributes on
+ * attributes. Thus, if we are just archiving an extended attribute,
+ * the second segment will contain the attribute name. If we are
+ * archiving a system attribute of an extended attribute, then the
+ * second segment will contain the attribute name, and a third segment
+ * will contain the system attribute name. The attribute pathing
+ * information is obtained from 'attrpath'.
*/
tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
(void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
stringlen);
(void) strcpy(tptr->h_names, filename);
- (void) strcpy(&tptr->h_names[strlen(filename) + 1], attrname);
+ attrnames_index = strlen(filename) + 1;
+ (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
tptr->h_typeflag = typeflag;
/*
+ * Split the attrnames section into two segments if 'attrpath'
+ * contains pathing information for a system attribute of an
+ * extended attribute. We split them by replacing the '/' with
+ * a '\0'.
+ */
+ if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
+ *aptr = '\0';
+ }
+
+ /*
* Now fill in the optional link section if we have one
*/
@@ -6675,7 +7364,7 @@ prepare_xattr(
#endif
int
-getstat(int dirfd, char *longname, char *shortname)
+getstat(int dirfd, char *longname, char *shortname, char *attrparent)
{
int i, j;
@@ -6722,7 +7411,11 @@ getstat(int dirfd, char *longname, char *shortname)
if (printerr) {
(void) fprintf(stderr, gettext(
- "tar: %s: %s\n"), longname, strerror(errno));
+ "tar: %s%s%s%s: %s\n"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
+ longname, strerror(errno));
Errflg = 1;
}
return (1);
@@ -6730,60 +7423,208 @@ getstat(int dirfd, char *longname, char *shortname)
return (0);
}
+/*
+ * Recursively archive the extended attributes and/or extended system attributes
+ * of the base file, longname. Note: extended system attribute files will be
+ * archived only if the extended system attributes are not transient (i.e. the
+ * extended system attributes are other than the default values).
+ *
+ * If -@ was specified and the underlying file system supports it, archive the
+ * extended attributes, and if there is a system attribute associated with the
+ * extended attribute, then recursively call xattrs_put() to archive the
+ * hidden attribute directory and the extended system attribute. If -/ was
+ * specified and the underlying file system supports it, archive the extended
+ * system attributes. Read-only extended system attributes are never archived.
+ *
+ * Currently, there cannot be attributes on attributes; only system
+ * attributes on attributes. In addition, there cannot be attributes on
+ * system attributes. A file and it's attribute directory hierarchy looks as
+ * follows:
+ * longname ----> . ("." is the hidden attribute directory)
+ * |
+ * ----------------------------
+ * | |
+ * <sys_attr_name> <attr_name> ----> .
+ * |
+ * <sys_attr_name>
+ *
+ */
#if defined(O_XATTR)
static void
-xattrs_put(char *longname, char *shortname, char *parent)
+xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
{
+ char *filename = (attrparent == NULL) ? shortname : attrparent;
+ int arc_rwsysattr = 0;
int dirfd;
+ int fd = -1;
+ int rw_sysattr = 0;
+ int rc;
DIR *dirp;
struct dirent *dp;
+ attr_data_t *attrinfo = NULL;
- if (pathconf(shortname, _PC_XATTR_EXISTS) != 1) {
+ /*
+ * If the underlying file system supports it, then archive the extended
+ * attributes if -@ was specified, and the extended system attributes
+ * if -/ was specified.
+ */
+ if (verify_attr_support(filename, ARC_CREATE) != ATTR_OK) {
return;
}
- if ((dirfd = attropen(shortname, ".", O_RDONLY)) < 0) {
- (void) fprintf(stderr, gettext(
- "tar: unable to open attribute directory for file %s\n"),
+ /*
+ * Only want to archive a read-write extended system attribute file
+ * if it contains extended system attribute settings that are not the
+ * default values.
+ */
+#if defined(_PC_SATTR_ENABLED)
+ if (saflag) {
+ int filefd;
+ nvlist_t *slist = NULL;
+
+ /* Determine if there are non-transient system attributes */
+ errno = 0;
+ if ((filefd = open(filename, O_RDONLY)) == -1) {
+ if (attrparent == NULL) {
+ vperror(0, gettext(
+ "unable to open file %s"), longname);
+ }
+ return;
+ }
+ if (((slist = sysattr_list(basename(myname), filefd,
+ filename)) != NULL) || (errno != 0)) {
+ arc_rwsysattr = 1;
+ }
+ if (slist != NULL) {
+ (void) nvlist_free(slist);
+ slist = NULL;
+ }
+ (void) close(filefd);
+ }
+#endif /* _PC_SATTR_ENABLED */
+
+ /* open the parent attribute directory */
+ fd = attropen(filename, ".", O_RDONLY);
+ if (fd < 0) {
+ vperror(0, gettext(
+ "unable to open attribute directory for %s%s%sfile %s"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
longname);
return;
}
- if ((dirp = fdopendir(dirfd)) == NULL) {
+ /*
+ * We need to change into the parent's attribute directory to determine
+ * if each of the attributes should be archived.
+ */
+ if (fchdir(fd) < 0) {
+ vperror(0, gettext(
+ "cannot change to attribute directory of %s%s%sfile %s"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
+ longname);
+ (void) close(fd);
+ return;
+ }
+
+ if (((dirfd = dup(fd)) == -1) ||
+ ((dirp = fdopendir(dirfd)) == NULL)) {
(void) fprintf(stderr, gettext(
- "tar: unable to open dir pointer for file %s\n"), longname);
+ "tar: unable to open dir pointer for %s%s%sfile %s\n"),
+ (attrparent == NULL) ? "" : gettext("attribute "),
+ (attrparent == NULL) ? "" : attrparent,
+ (attrparent == NULL) ? "" : gettext(" of "),
+ longname);
+ if (fd > 0) {
+ (void) close(fd);
+ }
return;
}
while (dp = readdir(dirp)) {
- if (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
- dp->d_name[2] == '\0')
+ if (strcmp(dp->d_name, "..") == 0) {
continue;
-
- if (dp->d_name[0] == '.' && dp->d_name[1] == '\0')
+ } else if (strcmp(dp->d_name, ".") == 0) {
Hiddendir = 1;
- else
+ } else {
Hiddendir = 0;
+ }
+
+ /* Determine if this attribute should be archived */
+ if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
+ &rw_sysattr) != ATTR_OK) {
+ continue;
+ }
+
+ /* gather the attribute's information to pass to putfile() */
+ if ((fill_in_attr_info(dp->d_name, longname, attrparent,
+ fd, rw_sysattr, &attrinfo)) == 1) {
+ continue;
+ }
- (void) putfile(longname, dp->d_name, parent,
+ /* add the attribute to the archive */
+ rc = putfile(longname, dp->d_name, parent, attrinfo,
XATTR_FILE, LEV0, SYMLINK_LEV0);
- if (exitflag)
+ if (exitflag) {
break;
+ }
+
+#if defined(_PC_SATTR_ENABLED)
+ /*
+ * If both -/ and -@ were specified, then archive the
+ * attribute's extended system attributes and hidden directory
+ * by making a recursive call to xattrs_put().
+ */
+ if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
+ (Hiddendir == 0)) {
+
+ xattrs_put(longname, shortname, parent, dp->d_name);
+
+ /*
+ * Change back to the parent's attribute directory
+ * to process any further attributes.
+ */
+ if (fchdir(fd) < 0) {
+ vperror(0, gettext(
+ "cannot change back to attribute directory "
+ "of file %s"), longname);
+ break;
+ }
+ }
+#endif /* _PC_SATTR_ENABLED */
}
+ if (attrinfo != NULL) {
+ if (attrinfo->attr_parent != NULL) {
+ free(attrinfo->attr_parent);
+ }
+ free(attrinfo->attr_path);
+ free(attrinfo);
+ }
(void) closedir(dirp);
+ if (fd != -1) {
+ (void) close(fd);
+ }
+
+ /* Change back to the parent directory of the base file */
+ if (attrparent == NULL) {
+ (void) chdir(parent);
+ }
}
#else
static void
-xattrs_put(char *longname, char *shortname, char *parent)
+xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
{
}
#endif /* O_XATTR */
static int
-put_link(char *name, char *longname, char *component,
- char *prefix, int filetype, char type)
+put_link(char *name, char *longname, char *component, char *longattrname,
+ char *prefix, int filetype, char type)
{
if (stbuf.st_nlink > 1) {
@@ -6799,8 +7640,8 @@ put_link(char *name, char *longname, char *component,
if (found) {
#if defined(O_XATTR)
if (filetype == XATTR_FILE)
- if (put_xattr_hdr(longname, component, prefix,
- type, filetype, lp)) {
+ if (put_xattr_hdr(longname, component,
+ longattrname, prefix, type, filetype, lp)) {
goto out;
}
#endif
@@ -6833,8 +7674,9 @@ put_link(char *name, char *longname, char *component,
if (filetype == XATTR_FILE) {
(void) fprintf(vfile, gettext(
"a %s attribute %s link to "
- "attribute %s\n"),
- name, component, lp->attrname);
+ "%s attribute %s\n"),
+ name, component, name,
+ lp->attrname);
} else {
(void) fprintf(vfile, gettext(
"a %s link to %s\n"),
@@ -6853,7 +7695,8 @@ put_link(char *name, char *longname, char *component,
lp->count = stbuf.st_nlink - 1;
if (filetype == XATTR_FILE) {
(void) strcpy(lp->pathname, longname);
- (void) strcpy(lp->attrname, component);
+ (void) strcpy(lp->attrname,
+ component);
} else {
(void) strcpy(lp->pathname, longname);
(void) strcpy(lp->attrname, "");
@@ -6867,8 +7710,8 @@ out:
}
static int
-put_extra_attributes(char *longname, char *shortname, char *prefix,
- int filetype, char typeflag)
+put_extra_attributes(char *longname, char *shortname, char *longattrname,
+ char *prefix, int filetype, char typeflag)
{
static acl_t *aclp = NULL;
int error;
@@ -6878,8 +7721,8 @@ put_extra_attributes(char *longname, char *shortname, char *prefix,
aclp = NULL;
}
#if defined(O_XATTR)
- if (atflag && filetype == XATTR_FILE) {
- if (put_xattr_hdr(longname, shortname, prefix,
+ if ((atflag || saflag) && (filetype == XATTR_FILE)) {
+ if (put_xattr_hdr(longname, shortname, longattrname, prefix,
typeflag, filetype, NULL)) {
return (1);
}
@@ -6927,7 +7770,7 @@ put_extra_attributes(char *longname, char *shortname, char *prefix,
#if defined(O_XATTR)
static int
-put_xattr_hdr(char *longname, char *shortname, char *prefix,
+put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
int typeflag, int filetype, struct linkbuf *lp)
{
char *lname = NULL;
@@ -6943,7 +7786,7 @@ put_xattr_hdr(char *longname, char *shortname, char *prefix,
fatal(gettext("Out of Memory."));
}
sname = malloc(sizeof (char) * strlen(shortname) +
- strlen(".hdr"));
+ strlen(".hdr") + 1);
if (sname == NULL) {
fatal(gettext("Out of Memory."));
}
@@ -6960,7 +7803,7 @@ put_xattr_hdr(char *longname, char *shortname, char *prefix,
/*
* dump extended attr lookup info
*/
- prepare_xattr(&attrbuf, longname, shortname, typeflag, lp, &attrlen);
+ prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
(void) sprintf(lname, "/dev/null/%s", shortname);
@@ -6981,15 +7824,17 @@ put_xattr_hdr(char *longname, char *shortname, char *prefix,
#if defined(O_XATTR)
static int
-read_xattr_hdr()
+read_xattr_hdr(attr_data_t **attrinfo)
{
char buf[TBLOCK];
+ char *attrparent = NULL;
blkcnt_t blocks;
char *tp;
off_t bytes;
int comp_len, link_len;
int namelen;
-
+ int attrparentlen;
+ int parentfilelen;
if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
return (1);
@@ -7037,7 +7882,40 @@ read_xattr_hdr()
else
xattr_linkp = NULL;
- xattraname = xattrp->h_names + strlen(xattrp->h_names) + 1;
+ /*
+ * Gather the attribute path from the filename and attrnames section.
+ * The filename and attrnames section can be composed of two or more
+ * path segments separated by a null character. The first segment
+ * is the path to the parent file that roots the entire sequence in
+ * the normal name space. The remaining segments describes a path
+ * rooted at the hidden extended attribute directory of the leaf file of
+ * the previous segment, making it possible to name attributes on
+ * attributes.
+ */
+ parentfilelen = strlen(xattrp->h_names);
+ xattrapath = xattrp->h_names + parentfilelen + 1;
+ if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
+ /*
+ * The attrnames section contains a system attribute on an
+ * attribute. Save the name of the attribute for use later,
+ * and replace the null separating the attribute name from
+ * the system attribute name with a '/' so that xattrapath can
+ * be used to display messages with the full attribute path name
+ * rooted at the hidden attribute directory of the base file
+ * in normal name space.
+ */
+ attrparent = strdup(xattrapath);
+ attrparentlen = strlen(attrparent);
+ xattrapath[attrparentlen] = '/';
+ }
+ if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
+ xattrapath + attrparentlen + 1, xattrapath, attrparent,
+ -1, 0, attrinfo)) == 1) {
+ free(attrparent);
+ return (1);
+ }
+
+ /* Gather link info */
if (xattr_linkp) {
xattr_linkaname = xattr_linkp->h_names +
strlen(xattr_linkp->h_names) + 1;
@@ -7049,7 +7927,7 @@ read_xattr_hdr()
}
#else
static int
-read_xattr_hdr()
+read_xattr_hdr(attr_data_t **attrinfo)
{
return (0);
}
@@ -7138,10 +8016,13 @@ get_component(char *path)
}
#endif
+#if defined(O_XATTR)
static int
-retry_attrdir_open(char *name)
+retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
+ int oflag, mode_t mode)
{
- int dirfd = -1;
+ int dirfd;
+ int ofilefd = -1;
struct timeval times[2];
mode_t newmode;
struct stat parentstat;
@@ -7152,57 +8033,82 @@ retry_attrdir_open(char *name)
* We couldn't get to attrdir. See if its
* just a mode problem on the parent file.
* for example: a mode such as r-xr--r--
- * won't let us create an attribute dir
- * if it doesn't already exist.
+ * on a ufs file system without extended
+ * system attribute support won't let us
+ * create an attribute dir if it doesn't
+ * already exist, and on a ufs file system
+ * with extended system attribute support
+ * won't let us open the attribute for
+ * write.
*
* If file has a non-trivial ACL, then save it
* off so that we can place it back on after doing
* chmod's.
*/
-
- if (stat(name, &parentstat) == -1) {
- (void) fprintf(stderr, gettext("tar: cannot stat file %s %s\n"),
- name, strerror(errno));
+ if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
+ O_RDONLY)) == -1) {
+ return (-1);
+ }
+ if (fstat(dirfd, &parentstat) == -1) {
+ (void) fprintf(stderr, gettext(
+ "tar: cannot stat %sfile %s: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, strerror(errno));
return (-1);
}
- if ((error = acl_get(name, ACL_NO_TRIVIAL, &aclp)) != 0) {
- (void) fprintf(stderr, gettext("tar: failed to retrieve ACL on"
- " %s %s\n"), name, strerror(errno));
+ if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
+ (void) fprintf(stderr, gettext(
+ "tar: failed to retrieve ACL on %sfile %s: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, strerror(errno));
return (-1);
}
newmode = S_IWUSR | parentstat.st_mode;
- if (chmod(name, newmode) == -1) {
+ if (fchmod(dirfd, newmode) == -1) {
(void) fprintf(stderr,
- gettext("tar: cannot chmod file %s to %o %s\n"),
- name, newmode, strerror(errno));
+ gettext(
+ "tar: cannot fchmod %sfile %s to %o: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
if (aclp)
acl_free(aclp);
return (-1);
}
- dirfd = attropen(name, ".", O_RDONLY);
- /*
- * Don't print error message if attropen() failed,
- * caller will print message.
- */
+ if (pdirfd == -1) {
+ /*
+ * We weren't able to create the attribute directory before.
+ * Now try again.
+ */
+ ofilefd = attropen(dirp, ".", oflag);
+ } else {
+ /*
+ * We weren't able to create open the attribute before.
+ * Now try again.
+ */
+ ofilefd = openat(pdirfd, name, oflag, mode);
+ }
/*
* Put mode back to original
*/
- if (chmod(name, parentstat.st_mode) == -1) {
+ if (fchmod(dirfd, parentstat.st_mode) == -1) {
(void) fprintf(stderr,
- gettext("tar: cannot chmod file %s to %o %s\n"),
- name, newmode, strerror(errno));
+ gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
}
if (aclp) {
- error = acl_set(name, aclp);
+ error = facl_set(dirfd, aclp);
if (error) {
(void) fprintf(stderr,
- gettext("tar: %s: failed to set acl entries\n"),
- name);
+ gettext("tar: failed to set acl entries on "
+ "%sfile %s\n"),
+ (pdirfd == -1) ? "" : gettext("parent of "),
+ (pdirfd == -1) ? dirp : name);
}
acl_free(aclp);
}
@@ -7215,10 +8121,14 @@ retry_attrdir_open(char *name)
times[0].tv_usec = 0;
times[1].tv_sec = parentstat.st_mtime;
times[1].tv_usec = 0;
- (void) utimes(name, times);
- return (dirfd);
+ (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
+
+ (void) close(dirfd);
+
+ return (ofilefd);
}
+#endif
#if !defined(O_XATTR)
static int