summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/protocols/dumprestore.h3
-rw-r--r--sbin/dump/dump.h2
-rw-r--r--sbin/dump/traverse.c184
-rw-r--r--sbin/restore/dirs.c66
-rw-r--r--sbin/restore/extern.h4
-rw-r--r--sbin/restore/restore.h1
-rw-r--r--sbin/restore/tape.c303
7 files changed, 516 insertions, 47 deletions
diff --git a/include/protocols/dumprestore.h b/include/protocols/dumprestore.h
index 6abf922..0b69e2d 100644
--- a/include/protocols/dumprestore.h
+++ b/include/protocols/dumprestore.h
@@ -97,7 +97,8 @@ union u_spcl {
int64_t c_birthtime; /* creation time, seconds */
int64_t c_atime; /* last access time, seconds */
int64_t c_mtime; /* last modified time, seconds */
- int32_t c_spare4[7]; /* old block pointers */
+ int32_t c_extsize; /* external attribute size */
+ int32_t c_spare4[6]; /* old block pointers */
u_int32_t c_file_flags; /* status flags (chflags) */
int32_t c_spare5[2]; /* old blocks, generation number */
u_int32_t c_uid; /* file owner */
diff --git a/sbin/dump/dump.h b/sbin/dump/dump.h
index 2224782..d467668 100644
--- a/sbin/dump/dump.h
+++ b/sbin/dump/dump.h
@@ -105,8 +105,6 @@ int mapfiles(ino_t maxino, long *tapesize);
int mapdirs(ino_t maxino, long *tapesize);
/* file dumping routines */
-void ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino);
-void ufs2_blksout(ufs2_daddr_t *blkp, int frags, ino_t ino);
void bread(ufs2_daddr_t blkno, char *buf, int size);
ssize_t cread(int fd, void *buf, size_t nbytes, off_t offset);
void dumpino(union dinode *dp, ino_t ino);
diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c
index b05e7a6..cb170d1 100644
--- a/sbin/dump/traverse.c
+++ b/sbin/dump/traverse.c
@@ -75,7 +75,13 @@ union dinode {
static int dirindir(ino_t ino, ufs2_daddr_t blkno, int level, long *size,
long *tapesize, int nodump, ino_t maxino);
-static void dmpindir(ino_t ino, ufs2_daddr_t blk, int level, off_t *size);
+static void dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int level,
+ off_t *size);
+static void ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino);
+static void ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags,
+ ino_t ino, int last);
+static int appendextdata(union dinode *dp);
+static void writeextdata(union dinode *dp, ino_t ino, int added);
static int searchdir(ino_t ino, ufs2_daddr_t blkno, long size, long filesize,
long *tapesize, int nodump, ino_t maxino);
static long blockest(union dinode *dp);
@@ -450,7 +456,7 @@ searchdir(
void
dumpino(union dinode *dp, ino_t ino)
{
- int ind_level, cnt;
+ int ind_level, cnt, last, added;
off_t size;
char buf[TP_BSIZE];
@@ -470,6 +476,7 @@ dumpino(union dinode *dp, ino_t ino)
if (sblock->fs_magic == FS_UFS1_MAGIC) {
spcl.c_mode = dp->dp1.di_mode;
spcl.c_size = dp->dp1.di_size;
+ spcl.c_extsize = 0;
spcl.c_atime = _time32_to_time(dp->dp1.di_atime);
spcl.c_atimensec = dp->dp1.di_atimensec;
spcl.c_mtime = _time32_to_time(dp->dp1.di_mtime);
@@ -483,6 +490,7 @@ dumpino(union dinode *dp, ino_t ino)
} else {
spcl.c_mode = dp->dp2.di_mode;
spcl.c_size = dp->dp2.di_size;
+ spcl.c_extsize = dp->dp2.di_extsize;
spcl.c_atime = _time64_to_time(dp->dp2.di_atime);
spcl.c_atimensec = dp->dp2.di_atimensec;
spcl.c_mtime = _time64_to_time(dp->dp2.di_mtime);
@@ -512,6 +520,7 @@ dumpino(union dinode *dp, ino_t ino)
DIP(dp, di_size) < sblock->fs_maxsymlinklen) {
spcl.c_addr[0] = 1;
spcl.c_count = 1;
+ added = appendextdata(dp);
writeheader(ino);
if (sblock->fs_magic == FS_UFS1_MAGIC)
memmove(buf, (caddr_t)dp->dp1.di_db,
@@ -521,6 +530,7 @@ dumpino(union dinode *dp, ino_t ino)
(u_long)DIP(dp, di_size));
buf[DIP(dp, di_size)] = '\0';
writerec(buf, 0);
+ writeextdata(dp, ino, added);
return;
}
/* FALLTHROUGH */
@@ -535,7 +545,9 @@ dumpino(union dinode *dp, ino_t ino)
case S_IFSOCK:
case S_IFCHR:
case S_IFBLK:
+ added = appendextdata(dp);
writeheader(ino);
+ writeextdata(dp, ino, added);
return;
default:
@@ -543,18 +555,21 @@ dumpino(union dinode *dp, ino_t ino)
DIP(dp, di_mode) & IFMT);
return;
}
- if (DIP(dp, di_size) > NDADDR * sblock->fs_bsize)
+ if (DIP(dp, di_size) > NDADDR * sblock->fs_bsize) {
cnt = NDADDR * sblock->fs_frag;
- else
+ last = 0;
+ } else {
cnt = howmany(DIP(dp, di_size), sblock->fs_fsize);
+ last = 1;
+ }
if (sblock->fs_magic == FS_UFS1_MAGIC)
ufs1_blksout(&dp->dp1.di_db[0], cnt, ino);
else
- ufs2_blksout(&dp->dp2.di_db[0], cnt, ino);
+ ufs2_blksout(dp, &dp->dp2.di_db[0], cnt, ino, last);
if ((size = DIP(dp, di_size) - NDADDR * sblock->fs_bsize) <= 0)
return;
for (ind_level = 0; ind_level < NIADDR; ind_level++) {
- dmpindir(ino, DIP(dp, di_ib[ind_level]), ind_level, &size);
+ dmpindir(dp, ino, DIP(dp, di_ib[ind_level]), ind_level, &size);
if (size <= 0)
return;
}
@@ -564,13 +579,14 @@ dumpino(union dinode *dp, ino_t ino)
* Read indirect blocks, and pass the data blocks to be dumped.
*/
static void
-dmpindir(ino_t ino, ufs2_daddr_t blk, int ind_level, off_t *size)
+dmpindir(union dinode *dp, ino_t ino, ufs2_daddr_t blk, int ind_level,
+ off_t *size)
{
union {
ufs1_daddr_t ufs1[MAXBSIZE / sizeof(ufs1_daddr_t)];
ufs2_daddr_t ufs2[MAXBSIZE / sizeof(ufs2_daddr_t)];
} idblk;
- int i, cnt;
+ int i, cnt, last;
if (blk != 0)
bread(fsbtodb(sblock, blk), (char *)&idblk,
@@ -578,23 +594,26 @@ dmpindir(ino_t ino, ufs2_daddr_t blk, int ind_level, off_t *size)
else
memset(&idblk, 0, sblock->fs_bsize);
if (ind_level <= 0) {
- if (*size < NINDIR(sblock) * sblock->fs_bsize)
- cnt = howmany(*size, sblock->fs_fsize);
- else
+ if (*size > NINDIR(sblock) * sblock->fs_bsize) {
cnt = NINDIR(sblock) * sblock->fs_frag;
+ last = 0;
+ } else {
+ cnt = howmany(*size, sblock->fs_fsize);
+ last = 1;
+ }
*size -= NINDIR(sblock) * sblock->fs_bsize;
if (sblock->fs_magic == FS_UFS1_MAGIC)
ufs1_blksout(idblk.ufs1, cnt, ino);
else
- ufs2_blksout(idblk.ufs2, cnt, ino);
+ ufs2_blksout(dp, idblk.ufs2, cnt, ino, last);
return;
}
ind_level--;
for (i = 0; i < NINDIR(sblock); i++) {
if (sblock->fs_magic == FS_UFS1_MAGIC)
- dmpindir(ino, idblk.ufs1[i], ind_level, size);
+ dmpindir(dp, ino, idblk.ufs1[i], ind_level, size);
else
- dmpindir(ino, idblk.ufs2[i], ind_level, size);
+ dmpindir(dp, ino, idblk.ufs2[i], ind_level, size);
if (*size <= 0)
return;
}
@@ -603,7 +622,7 @@ dmpindir(ino_t ino, ufs2_daddr_t blk, int ind_level, off_t *size)
/*
* Collect up the data into tape record sized buffers and output them.
*/
-void
+static void
ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino)
{
ufs1_daddr_t *bp;
@@ -638,13 +657,25 @@ ufs1_blksout(ufs1_daddr_t *blkp, int frags, ino_t ino)
/*
* Collect up the data into tape record sized buffers and output them.
*/
-void
-ufs2_blksout(ufs2_daddr_t *blkp, int frags, ino_t ino)
+static void
+ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, ino_t ino,
+ int last)
{
ufs2_daddr_t *bp;
- int i, j, count, blks, tbperdb;
+ int i, j, count, resid, blks, tbperdb, added;
+ static int writingextdata = 0;
+ /*
+ * Calculate the number of TP_BSIZE blocks to be dumped.
+ * For filesystems with a fragment size bigger than TP_BSIZE,
+ * only part of the final fragment may need to be dumped.
+ */
blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
+ if (last) {
+ resid = howmany(fragoff(sblock, dp->dp2.di_size), TP_BSIZE);
+ if (resid > 0)
+ blks -= howmany(sblock->fs_fsize, TP_BSIZE) - resid;
+ }
tbperdb = sblock->fs_bsize >> tp_bshift;
for (i = 0; i < blks; i += TP_NINDIR) {
if (i + TP_NINDIR > blks)
@@ -657,6 +688,8 @@ ufs2_blksout(ufs2_daddr_t *blkp, int frags, ino_t ino)
else
spcl.c_addr[j - i] = 0;
spcl.c_count = count - i;
+ if (last && !writingextdata)
+ added = appendextdata(dp);
writeheader(ino);
bp = &blkp[i / tbperdb];
for (j = i; j < count; j += tbperdb, bp++)
@@ -667,7 +700,122 @@ ufs2_blksout(ufs2_daddr_t *blkp, int frags, ino_t ino)
dumpblock(*bp, (count - j) * TP_BSIZE);
}
spcl.c_type = TS_ADDR;
+ spcl.c_count = 0;
+ if (last && !writingextdata) {
+ writingextdata = 1;
+ writeextdata(dp, ino, added);
+ writingextdata = 0;
+ }
+ }
+}
+
+/*
+ * If there is room in the current block for the extended attributes
+ * as well as the file data, update the header to reflect the added
+ * attribute data at the end. Attributes are placed at the end so that
+ * old versions of restore will correctly restore the file and simply
+ * discard the extra data at the end that it does not understand.
+ * The attribute data is dumped following the file data by the
+ * writeextdata() function (below).
+ */
+static int
+appendextdata(union dinode *dp)
+{
+ int i, blks, tbperdb;
+
+ /*
+ * If no extended attributes, there is nothing to do.
+ */
+ if (spcl.c_extsize == 0)
+ return (0);
+ /*
+ * If there is not enough room at the end of this block
+ * to add the extended attributes, then rather than putting
+ * part of them here, we simply push them entirely into a
+ * new block rather than putting some here and some later.
+ */
+ if (spcl.c_extsize > NXADDR * sblock->fs_bsize)
+ blks = howmany(NXADDR * sblock->fs_bsize, TP_BSIZE);
+ else
+ blks = howmany(spcl.c_extsize, TP_BSIZE);
+ if (spcl.c_count + blks > TP_NINDIR)
+ return (0);
+ /*
+ * Update the block map in the header to indicate the added
+ * extended attribute. They will be appended after the file
+ * data by the writeextdata() routine.
+ */
+ tbperdb = sblock->fs_bsize >> tp_bshift;
+ for (i = 0; i < blks; i++)
+ if (&dp->dp2.di_extb[i / tbperdb] != 0)
+ spcl.c_addr[spcl.c_count + i] = 1;
+ else
+ spcl.c_addr[spcl.c_count + i] = 0;
+ spcl.c_count += blks;
+ return (blks);
+}
+
+/*
+ * Dump the extended attribute data. If there was room in the file
+ * header, then all we need to do is output the data blocks. If there
+ * was not room in the file header, then an additional TS_ADDR header
+ * is created to hold the attribute data.
+ */
+static void
+writeextdata(union dinode *dp, ino_t ino, int added)
+{
+ int i, frags, blks, tbperdb, last;
+ ufs2_daddr_t *bp;
+ off_t size;
+
+ /*
+ * If no extended attributes, there is nothing to do.
+ */
+ if (spcl.c_extsize == 0)
+ return;
+ /*
+ * If there was no room in the file block for the attributes,
+ * dump them out in a new block, otherwise just dump the data.
+ */
+ if (added == 0) {
+ if (spcl.c_extsize > NXADDR * sblock->fs_bsize) {
+ frags = NXADDR * sblock->fs_frag;
+ last = 0;
+ } else {
+ frags = howmany(spcl.c_extsize, sblock->fs_fsize);
+ last = 1;
+ }
+ ufs2_blksout(dp, &dp->dp2.di_extb[0], frags, ino, last);
+ } else {
+ if (spcl.c_extsize > NXADDR * sblock->fs_bsize)
+ blks = howmany(NXADDR * sblock->fs_bsize, TP_BSIZE);
+ else
+ blks = howmany(spcl.c_extsize, TP_BSIZE);
+ tbperdb = sblock->fs_bsize >> tp_bshift;
+ for (i = 0; i < blks; i += tbperdb) {
+ bp = &dp->dp2.di_extb[i / tbperdb];
+ if (*bp != 0) {
+ if (i + tbperdb <= blks)
+ dumpblock(*bp, (int)sblock->fs_bsize);
+ else
+ dumpblock(*bp, (blks - i) * TP_BSIZE);
+ }
+ }
+
}
+ /*
+ * If an indirect block is added for extended attributes, then
+ * di_exti below should be changed to the structure element
+ * that references the extended attribute indirect block. This
+ * definition is here only to make it compile without complaint.
+ */
+#define di_exti di_spare[0]
+ /*
+ * If the extended attributes fall into an indirect block,
+ * dump it as well.
+ */
+ if ((size = spcl.c_extsize - NXADDR * sblock->fs_bsize) > 0)
+ dmpindir(dp, ino, dp->dp2.di_exti, 0, &size);
}
/*
diff --git a/sbin/restore/dirs.c b/sbin/restore/dirs.c
index f12f932..406a0f0 100644
--- a/sbin/restore/dirs.c
+++ b/sbin/restore/dirs.c
@@ -85,6 +85,7 @@ struct modeinfo {
uid_t uid;
gid_t gid;
int flags;
+ int extsize;
};
/*
@@ -114,6 +115,7 @@ static void flushent(void);
static struct inotab *inotablookup(ino_t);
static RST_DIR *opendirfile(const char *);
static void putdir(char *, long);
+static void putdirattrs(char *, long);
static void putent(struct direct *);
static void rst_seekdir(RST_DIR *, long, long);
static long rst_telldir(RST_DIR *);
@@ -184,7 +186,7 @@ extractdirs(int genmode)
return;
}
itp = allocinotab(&curfile, seekpt);
- getfile(putdir, xtrnull);
+ getfile(putdir, putdirattrs, xtrnull);
putent(&nulldir);
flushent();
itp->t_size = seekpt - itp->t_seekpt;
@@ -410,6 +412,17 @@ flushent(void)
}
/*
+ * Save extended attributes for a directory entry to a file.
+ */
+static void
+putdirattrs(char *buf, long size)
+{
+
+ if (mf != NULL)
+ (void) fwrite(buf, 1, size, mf);
+}
+
+/*
* Seek to an entry in a directory.
* Only values returned by rst_telldir should be passed to rst_seekdir.
* This routine handles many directories in a single file.
@@ -543,8 +556,9 @@ setdirmodes(int flags)
FILE *mf;
struct modeinfo node;
struct entry *ep;
- char *cp;
+ char *cp, *buf;
const char *tmpdir;
+ int bufsize;
vprintf(stdout, "Set directory mode, owner, and times.\n");
if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0')
@@ -564,10 +578,27 @@ setdirmodes(int flags)
return;
}
clearerr(mf);
+ bufsize = 0;
for (;;) {
(void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
if (feof(mf))
break;
+ if (node.extsize > 0) {
+ if (bufsize < node.extsize) {
+ if (bufsize > 0)
+ free(buf);
+ if ((buf = malloc(node.extsize)) != 0) {
+ bufsize = node.extsize;
+ } else {
+ bufsize = 0;
+ }
+ }
+ if (bufsize >= node.extsize) {
+ (void) fread(buf, 1, node.extsize, mf);
+ } else {
+ (void) fseek(mf, node.extsize, SEEK_CUR);
+ }
+ }
ep = lookupino(node.ino);
if (command == 'i' || command == 'x') {
if (ep == NULL)
@@ -582,18 +613,28 @@ setdirmodes(int flags)
}
if (ep == NULL) {
panic("cannot find directory inode %d\n", node.ino);
- } else {
- cp = myname(ep);
- if (!Nflag) {
- (void) chown(cp, node.uid, node.gid);
- (void) chmod(cp, node.mode);
- utimes(cp, node.ctimep);
- utimes(cp, node.mtimep);
- (void) chflags(cp, node.flags);
+ continue;
+ }
+ cp = myname(ep);
+ if (!Nflag) {
+ if (node.extsize > 0) {
+ if (bufsize >= node.extsize) {
+ set_extattr_file(cp, buf, node.extsize);
+ } else {
+ fprintf(stderr, "Cannot restore %s%s\n",
+ "extended attributes for ", cp);
+ }
}
- ep->e_flags &= ~NEW;
+ (void) chown(cp, node.uid, node.gid);
+ (void) chmod(cp, node.mode);
+ utimes(cp, node.ctimep);
+ utimes(cp, node.mtimep);
+ (void) chflags(cp, node.flags);
}
+ ep->e_flags &= ~NEW;
}
+ if (bufsize > 0)
+ free(buf);
if (ferror(mf))
panic("error setting directory modes\n");
(void) fclose(mf);
@@ -668,7 +709,7 @@ allocinotab(struct context *ctxp, long seekpt)
itp = calloc(1, sizeof(struct inotab));
if (itp == NULL)
- panic("no memory directory table\n");
+ panic("no memory for directory table\n");
itp->t_next = inotab[INOHASH(ctxp->ino)];
inotab[INOHASH(ctxp->ino)] = itp;
itp->t_ino = ctxp->ino;
@@ -684,6 +725,7 @@ allocinotab(struct context *ctxp, long seekpt)
node.ctimep[0].tv_usec = ctxp->atime_nsec / 1000;
node.ctimep[1].tv_sec = ctxp->birthtime_sec;
node.ctimep[1].tv_usec = ctxp->birthtime_nsec / 1000;
+ node.extsize = ctxp->extsize;
node.mode = ctxp->mode;
node.flags = ctxp->file_flags;
node.uid = ctxp->uid;
diff --git a/sbin/restore/extern.h b/sbin/restore/extern.h
index 603a561..cbecc86 100644
--- a/sbin/restore/extern.h
+++ b/sbin/restore/extern.h
@@ -54,7 +54,8 @@ void freeentry(struct entry *);
void freename(char *);
int genliteraldir(char *, ino_t);
char *gentempname(struct entry *);
-void getfile(void (*)(char *, long), void (*)(char *, long));
+void getfile(void (*)(char *, long), void (*)(char *, long),
+ void (*)(char *, long));
void getvol(long);
void initsymtable(char *);
int inodetype(ino_t);
@@ -86,6 +87,7 @@ struct direct *rst_readdir(RST_DIR *);
void rst_closedir(void *);
void runcmdshell(void);
char *savename(char *);
+void set_extattr_file(char *, void *, int);
void setdirmodes(int);
void setinput(char *, int);
void setup(void);
diff --git a/sbin/restore/restore.h b/sbin/restore/restore.h
index 43e4db5..8c6a87b 100644
--- a/sbin/restore/restore.h
+++ b/sbin/restore/restore.h
@@ -115,6 +115,7 @@ struct context {
int atime_nsec; /* access time nanoseconds */
int mtime_nsec; /* modified time nanoseconds */
int birthtime_nsec; /* creation time nanoseconds */
+ int extsize; /* size of extended attribute data */
off_t size; /* size of file */
char *name; /* name of file */
} curfile;
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