summaryrefslogtreecommitdiffstats
path: root/sbin/restore
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/restore
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/restore')
-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
4 files changed, 348 insertions, 26 deletions
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