summaryrefslogtreecommitdiffstats
path: root/sbin/restore/tape.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/restore/tape.c')
-rw-r--r--sbin/restore/tape.c303
1 files changed, 290 insertions, 13 deletions
diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c
index eb9802f..15c204ac 100644
--- a/sbin/restore/tape.c
+++ b/sbin/restore/tape.c
@@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$");
#include <sys/mtio.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/extattr.h>
+#include <sys/acl.h>
#include <ufs/ufs/dinode.h>
#include <protocols/dumprestore.h>
@@ -94,10 +96,16 @@ int oldinofmt; /* FreeBSD 1 inode format needs cvt */
#define FLUSHTAPEBUF() blkcnt = ntrec + 1
+char *namespace_names[] = EXTATTR_NAMESPACE_NAMES;
+
static void accthdr(struct s_spcl *);
static int checksum(int *);
static void findinode(struct s_spcl *);
static void findtapeblksize(void);
+static char *setupextattr(int);
+static void xtrattr(char *, long);
+static void set_extattr_link(char *, void *, int);
+static void set_extattr_fd(int, char *, void *, int);
static int gethead(struct s_spcl *);
static void readtape(char *);
static void setdumpnum(void);
@@ -271,7 +279,7 @@ setup(void)
panic("no memory for active inode map\n");
usedinomap = map;
curfile.action = USING;
- getfile(xtrmap, xtrmapskip);
+ getfile(xtrmap, xtrmapskip, xtrmapskip);
if (spcl.c_type != TS_BITS) {
fprintf(stderr, "Cannot find file dump list\n");
done(1);
@@ -281,7 +289,7 @@ setup(void)
panic("no memory for file dump list\n");
dumpmap = map;
curfile.action = USING;
- getfile(xtrmap, xtrmapskip);
+ getfile(xtrmap, xtrmapskip, xtrmapskip);
/*
* If there may be whiteout entries on the tape, pretend that the
* whiteout inode exists, so that the whiteout entries can be
@@ -557,8 +565,10 @@ extractfile(char *name)
uid_t uid;
gid_t gid;
mode_t mode;
+ int extsize;
struct timeval mtimep[2], ctimep[2];
struct entry *ep;
+ char *buf;
curfile.name = name;
curfile.action = USING;
@@ -570,6 +580,7 @@ extractfile(char *name)
ctimep[0].tv_usec = curfile.atime_nsec / 1000;
ctimep[1].tv_sec = curfile.birthtime_sec;
ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
+ extsize = curfile.extsize;
uid = curfile.uid;
gid = curfile.gid;
mode = curfile.mode;
@@ -600,13 +611,16 @@ extractfile(char *name)
case IFLNK:
lnkbuf[0] = '\0';
pathlen = 0;
- getfile(xtrlnkfile, xtrlnkskip);
+ buf = setupextattr(extsize);
+ getfile(xtrlnkfile, xtrattr, xtrlnkskip);
if (pathlen == 0) {
vprintf(stdout,
"%s: zero length symbolic link (ignored)\n", name);
return (GOOD);
}
if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
+ if (extsize > 0)
+ set_extattr_link(name, buf, extsize);
(void) lchown(name, uid, gid);
(void) lchmod(name, mode);
(void) lutimes(name, ctimep);
@@ -630,7 +644,13 @@ extractfile(char *name)
skipfile();
return (FAIL);
}
- skipfile();
+ if (extsize == 0) {
+ skipfile();
+ } else {
+ buf = setupextattr(extsize);
+ getfile(xtrnull, xtrattr, xtrnull);
+ set_extattr_file(name, buf, extsize);
+ }
(void) chown(name, uid, gid);
(void) chmod(name, mode);
(void) utimes(name, ctimep);
@@ -654,7 +674,13 @@ extractfile(char *name)
skipfile();
return (FAIL);
}
- skipfile();
+ if (extsize == 0) {
+ skipfile();
+ } else {
+ buf = setupextattr(extsize);
+ getfile(xtrnull, xtrattr, xtrnull);
+ set_extattr_file(name, buf, extsize);
+ }
(void) chown(name, uid, gid);
(void) chmod(name, mode);
(void) utimes(name, ctimep);
@@ -677,7 +703,10 @@ extractfile(char *name)
skipfile();
return (FAIL);
}
- getfile(xtrfile, xtrskip);
+ buf = setupextattr(extsize);
+ getfile(xtrfile, xtrattr, xtrskip);
+ if (extsize > 0)
+ set_extattr_fd(ofile, name, buf, extsize);
(void) fchown(ofile, uid, gid);
(void) fchmod(ofile, mode);
(void) futimes(ofile, ctimep);
@@ -690,6 +719,185 @@ extractfile(char *name)
}
/*
+ * Set attributes for a file.
+ */
+void
+set_extattr_file(char *name, void *buf, int size)
+{
+ struct extattr *eap, *eaend;
+
+ vprintf(stdout, "Set attributes for %s:", name);
+ eaend = buf + size;
+ for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
+ /*
+ * Make sure this entry is complete.
+ */
+ if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
+ dprintf(stdout, "\n\t%scorrupted",
+ eap == buf ? "" : "remainder ");
+ break;
+ }
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
+ continue;
+ vprintf(stdout, "\n\t%s, (%d bytes), %*s",
+ namespace_names[eap->ea_namespace], eap->ea_length,
+ eap->ea_namelength, eap->ea_name);
+ /*
+ * First we try the general attribute setting interface.
+ * However, some attributes can only be set by root or
+ * by using special interfaces (for example, ACLs).
+ */
+ if (extattr_set_file(name, eap->ea_namespace, eap->ea_name,
+ EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
+ dprintf(stdout, " (set using extattr_set_file)");
+ continue;
+ }
+ /*
+ * If the general interface refuses to set the attribute,
+ * then we try all the specialized interfaces that we
+ * know about.
+ */
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+ !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
+ if (acl_set_file(name, ACL_TYPE_ACCESS,
+ EXTATTR_CONTENT(eap)) != -1) {
+ dprintf(stdout, " (set using acl_set_file)");
+ continue;
+ }
+ }
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+ !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
+ if (acl_set_file(name, ACL_TYPE_DEFAULT,
+ EXTATTR_CONTENT(eap)) != -1) {
+ dprintf(stdout, " (set using acl_set_file)");
+ continue;
+ }
+ }
+ vprintf(stdout, " (unable to set)");
+ }
+ vprintf(stdout, "\n");
+}
+
+/*
+ * Set attributes for a symbolic link.
+ */
+static void
+set_extattr_link(char *name, void *buf, int size)
+{
+ struct extattr *eap, *eaend;
+
+ vprintf(stdout, "Set attributes for %s:", name);
+ eaend = buf + size;
+ for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
+ /*
+ * Make sure this entry is complete.
+ */
+ if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
+ dprintf(stdout, "\n\t%scorrupted",
+ eap == buf ? "" : "remainder ");
+ break;
+ }
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
+ continue;
+ vprintf(stdout, "\n\t%s, (%d bytes), %*s",
+ namespace_names[eap->ea_namespace], eap->ea_length,
+ eap->ea_namelength, eap->ea_name);
+ /*
+ * First we try the general attribute setting interface.
+ * However, some attributes can only be set by root or
+ * by using special interfaces (for example, ACLs).
+ */
+ if (extattr_set_link(name, eap->ea_namespace, eap->ea_name,
+ EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
+ dprintf(stdout, " (set using extattr_set_link)");
+ continue;
+ }
+ /*
+ * If the general interface refuses to set the attribute,
+ * then we try all the specialized interfaces that we
+ * know about.
+ */
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+ !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
+ if (acl_set_link_np(name, ACL_TYPE_ACCESS,
+ EXTATTR_CONTENT(eap)) != -1) {
+ dprintf(stdout, " (set using acl_set_link_np)");
+ continue;
+ }
+ }
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+ !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
+ if (acl_set_link_np(name, ACL_TYPE_DEFAULT,
+ EXTATTR_CONTENT(eap)) != -1) {
+ dprintf(stdout, " (set using acl_set_link_np)");
+ continue;
+ }
+ }
+ vprintf(stdout, " (unable to set)");
+ }
+ vprintf(stdout, "\n");
+}
+
+/*
+ * Set attributes on a file descriptor.
+ */
+static void
+set_extattr_fd(int fd, char *name, void *buf, int size)
+{
+ struct extattr *eap, *eaend;
+
+ vprintf(stdout, "Set attributes for %s:", name);
+ eaend = buf + size;
+ for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
+ /*
+ * Make sure this entry is complete.
+ */
+ if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
+ dprintf(stdout, "\n\t%scorrupted",
+ eap == buf ? "" : "remainder ");
+ break;
+ }
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
+ continue;
+ vprintf(stdout, "\n\t%s, (%d bytes), %*s",
+ namespace_names[eap->ea_namespace], eap->ea_length,
+ eap->ea_namelength, eap->ea_name);
+ /*
+ * First we try the general attribute setting interface.
+ * However, some attributes can only be set by root or
+ * by using special interfaces (for example, ACLs).
+ */
+ if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name,
+ EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
+ dprintf(stdout, " (set using extattr_set_fd)");
+ continue;
+ }
+ /*
+ * If the general interface refuses to set the attribute,
+ * then we try all the specialized interfaces that we
+ * know about.
+ */
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+ !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
+ if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) {
+ dprintf(stdout, " (set using acl_set_fd)");
+ continue;
+ }
+ }
+ if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+ !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
+ if (acl_set_file(name, ACL_TYPE_DEFAULT,
+ EXTATTR_CONTENT(eap)) != -1) {
+ dprintf(stdout, " (set using acl_set_file)");
+ continue;
+ }
+ }
+ vprintf(stdout, " (unable to set)");
+ }
+ vprintf(stdout, "\n");
+}
+
+/*
* skip over bit maps on the tape
*/
void
@@ -708,7 +916,7 @@ skipfile(void)
{
curfile.action = SKIP;
- getfile(xtrnull, xtrnull);
+ getfile(xtrnull, xtrnull, xtrnull);
}
/*
@@ -718,15 +926,20 @@ skipfile(void)
* to the skip function.
*/
void
-getfile(void (*fill)(char *, long), void (*skip)(char *, long))
+getfile(void (*datafill)(char *, long), void (*attrfill)(char *, long),
+ void (*skip)(char *, long))
{
int i;
- int curblk = 0;
- quad_t size = spcl.c_size;
+ off_t size;
+ int curblk, attrsize;
+ void (*fillit)(char *, long);
static char clearedbuf[MAXBSIZE];
char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
char junk[TP_BSIZE];
+ curblk = 0;
+ size = spcl.c_size;
+ attrsize = spcl.c_extsize;
if (spcl.c_type == TS_END)
panic("ran off end of tape\n");
if (spcl.c_magic != FS_UFS2_MAGIC)
@@ -734,6 +947,12 @@ getfile(void (*fill)(char *, long), void (*skip)(char *, long))
if (!gettingfile && setjmp(restart) != 0)
return;
gettingfile++;
+ fillit = datafill;
+ if (size == 0 && attrsize > 0) {
+ fillit = attrfill;
+ size = attrsize;
+ attrsize = 0;
+ }
loop:
for (i = 0; i < spcl.c_count; i++) {
if (!readmapflag && i > TP_NINDIR) {
@@ -748,13 +967,13 @@ loop:
if (readmapflag || spcl.c_addr[i]) {
readtape(&buf[curblk++][0]);
if (curblk == fssize / TP_BSIZE) {
- (*fill)((char *)buf, (long)(size > TP_BSIZE ?
+ (*fillit)((char *)buf, (long)(size > TP_BSIZE ?
fssize : (curblk - 1) * TP_BSIZE + size));
curblk = 0;
}
} else {
if (curblk > 0) {
- (*fill)((char *)buf, (long)(size > TP_BSIZE ?
+ (*fillit)((char *)buf, (long)(size > TP_BSIZE ?
curblk * TP_BSIZE :
(curblk - 1) * TP_BSIZE + size));
curblk = 0;
@@ -763,6 +982,20 @@ loop:
TP_BSIZE : size));
}
if ((size -= TP_BSIZE) <= 0) {
+ if (size > -TP_BSIZE && curblk > 0) {
+ (*fillit)((char *)buf,
+ (long)((curblk * TP_BSIZE) + size));
+ curblk = 0;
+ }
+ if (attrsize > 0) {
+ fillit = attrfill;
+ size = attrsize;
+ attrsize = 0;
+ continue;
+ }
+ if (spcl.c_count - i > 1)
+ dprintf(stdout, "skipping %d junk block(s)\n",
+ spcl.c_count - i - 1);
for (i++; i < spcl.c_count; i++) {
if (!readmapflag && i > TP_NINDIR) {
if (Dflag) {
@@ -788,12 +1021,55 @@ loop:
curfile.name, blksread);
}
if (curblk > 0)
- (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
+ panic("getfile: lost data\n");
findinode(&spcl);
gettingfile = 0;
}
/*
+ * These variables are shared between the next two functions.
+ */
+static int extbufsize = 0;
+static char *extbuf;
+static int extloc;
+
+/*
+ * Allocate a buffer into which to extract extended attributes.
+ */
+static char *
+setupextattr(int extsize)
+{
+
+ extloc = 0;
+ if (extsize <= extbufsize)
+ return (extbuf);
+ if (extbufsize > 0)
+ free(extbuf);
+ if ((extbuf = malloc(extsize)) != NULL) {
+ extbufsize = extsize;
+ return (extbuf);
+ }
+ extbufsize = 0;
+ extbuf = NULL;
+ fprintf(stderr, "Cannot extract %d bytes %s for inode %d, name %s\n",
+ extsize, "of extended attributes", curfile.ino, curfile.name);
+ return (NULL);
+}
+
+/*
+ * Extract the next block of extended attributes.
+ */
+static void
+xtrattr(char *buf, long size)
+{
+
+ if (extloc + size > extbufsize)
+ panic("overrun attribute buffer\n");
+ memmove(&extbuf[extloc], buf, size);
+ extloc += size;
+}
+
+/*
* Write out the next block of a file.
*/
static void
@@ -1283,6 +1559,7 @@ findinode(struct s_spcl *header)
curfile.mtime_nsec = header->c_mtimensec;
curfile.birthtime_sec = header->c_birthtime;
curfile.birthtime_nsec = header->c_birthtimensec;
+ curfile.extsize = header->c_extsize;
curfile.size = header->c_size;
curfile.ino = header->c_inumber;
break;
OpenPOWER on IntegriCloud