summaryrefslogtreecommitdiffstats
path: root/sbin/dump
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2007-02-26 08:15:56 +0000
committermckusick <mckusick@FreeBSD.org>2007-02-26 08:15:56 +0000
commit01ee9020b350e550aa823f81efbe79cba3e5cb58 (patch)
tree2804c9d36c181a4e54a05d8bca1ea7ca7d284525 /sbin/dump
parent22aa654f0bcb07fd20f8c8543209224495888a8e (diff)
downloadFreeBSD-src-01ee9020b350e550aa823f81efbe79cba3e5cb58.zip
FreeBSD-src-01ee9020b350e550aa823f81efbe79cba3e5cb58.tar.gz
Update the dump program to save extended attributes. Update
the restore program to restore all dumped extended attributes. If the restore is running as root, it will always be able to restore all extended attributes. If it is not running as root, it makes a best effort to set them. Using the -v command line flag or the `verbose' command in interactive mode will display all the extended attributes being set on files (and at the end on directories) that are being restored. It will note any extended attributes that could not be set. The extended attributes are placed on the dump image immediately following each file's data. Older versions of restore can work with the newer dump images. Old versions of restore will correctly restore the file data and then (silently) skip over the extended attribute data and proceed to the next file. This resolves PR 93085 which will be closed once the code has been MFC'ed. Note that this code will not compile until these header files have been updated: <protocols/dumprestore.h> and <sys/extattr.h>. PR: bin/93085 Comments from: Poul-Henning Kamp and Robert Watson MFC after: 3 weeks
Diffstat (limited to 'sbin/dump')
-rw-r--r--sbin/dump/dump.h2
-rw-r--r--sbin/dump/traverse.c184
2 files changed, 166 insertions, 20 deletions
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);
}
/*
OpenPOWER on IntegriCloud