diff options
Diffstat (limited to 'sbin/restore/tape.c')
-rw-r--r-- | sbin/restore/tape.c | 303 |
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; |