mirror of
git://git.suckless.org/sbase
synced 2026-01-26 05:37:54 +00:00
tar: man page update, and more robust & descriptive errors
1. Manual page has been updated to reflect previous change to tar. 2. Error messages are more detailed & secured against unterminated header strings. Previously, sanitize() assumed numeric fields were terminated by space or null, but did not check termination is actually present. 3. Default mode of the blank header in archive() is now 0600. For all file headers, this is immediately set to the file's mode. Only L-headers keep the 0600 value (which are not user visible). GNU tar uses 0644, but 0600 was chosen for symmetry with sbase unarchive(), which also uses 0600 as the initial mode.
This commit is contained in:
parent
5aa63dbe05
commit
6b802ab9fd
14
tar.1
14
tar.1
@ -6,16 +6,18 @@
|
|||||||
.Nd create, list or extract a tape archive
|
.Nd create, list or extract a tape archive
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
|
.Cm x | Cm t | Fl x | Fl t
|
||||||
.Op Fl C Ar dir
|
.Op Fl C Ar dir
|
||||||
.Op Fl J | Fl Z | Fl a | Fl j | Fl z
|
.Op Fl J | Fl Z | Fl a | Fl j | Fl z
|
||||||
.Fl x Op Fl m | Fl t
|
.Op Fl m
|
||||||
|
.Op Fl p
|
||||||
.Op Fl f Ar file
|
.Op Fl f Ar file
|
||||||
.Op Ar file ...
|
.Op Ar file ...
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl C Ar dir
|
.Cm c | Fl c Op Fl C Ar dir
|
||||||
.Op Fl J | Fl Z | Fl a | Fl j | Fl z
|
.Op Fl J | Fl Z | Fl a | Fl j | Fl z
|
||||||
.Op Fl h
|
.Op Fl h
|
||||||
.Fl c Ar path ...
|
.Ar path ...
|
||||||
.Op Fl f Ar file
|
.Op Fl f Ar file
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
@ -66,4 +68,8 @@ The
|
|||||||
utility is compliant with the UStar (Uniform Standard Tape ARchive)
|
utility is compliant with the UStar (Uniform Standard Tape ARchive)
|
||||||
format defined in the
|
format defined in the
|
||||||
.St -p1003.1-88
|
.St -p1003.1-88
|
||||||
specification.
|
specification. For long file paths (>99 bytes), the UStar, 'L' and 'x'
|
||||||
|
header formats are supported for reading (to a maximum size of PATH_MAX
|
||||||
|
or 255 bytes, depending on format), and the 'L' format is supported for
|
||||||
|
writing (with unlimited path size). Link targets are limited to the
|
||||||
|
UStar maximum of 100 bytes.
|
||||||
|
|||||||
40
tar.c
40
tar.c
@ -186,14 +186,14 @@ static void
|
|||||||
putoctal(char *dst, unsigned num, int size)
|
putoctal(char *dst, unsigned num, int size)
|
||||||
{
|
{
|
||||||
if (snprintf(dst, size, "%.*o", size - 1, num) >= size)
|
if (snprintf(dst, size, "%.*o", size - 1, num) >= size)
|
||||||
eprintf("snprintf: input number too large\n");
|
eprintf("putoctal: input number '%o' too large\n", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
archive(const char *path)
|
archive(const char *path)
|
||||||
{
|
{
|
||||||
static const struct header blank = {
|
static const struct header blank = {
|
||||||
"././@LongLink", "0000000" , "0000000", "0000000", "00000000000",
|
"././@LongLink", "0000600", "0000000", "0000000", "00000000000",
|
||||||
"00000000000" , " ", AREG , "" , "ustar", "00",
|
"00000000000" , " ", AREG , "" , "ustar", "00",
|
||||||
};
|
};
|
||||||
char b[BLKSIZ + BLKSIZ], *p;
|
char b[BLKSIZ + BLKSIZ], *p;
|
||||||
@ -221,8 +221,8 @@ archive(const char *path)
|
|||||||
h->type = 'L';
|
h->type = 'L';
|
||||||
putoctal(h->size, n, sizeof(h->size));
|
putoctal(h->size, n, sizeof(h->size));
|
||||||
putoctal(h->chksum, chksum(h), sizeof(h->chksum));
|
putoctal(h->chksum, chksum(h), sizeof(h->chksum));
|
||||||
|
|
||||||
ewrite(tarfd, (char *)h, BLKSIZ);
|
ewrite(tarfd, (char *)h, BLKSIZ);
|
||||||
|
|
||||||
for (p = (char *)path; n > 0; n -= BLKSIZ, p += BLKSIZ) {
|
for (p = (char *)path; n > 0; n -= BLKSIZ, p += BLKSIZ) {
|
||||||
if (n < BLKSIZ) {
|
if (n < BLKSIZ) {
|
||||||
p = memcpy(h--, p, n);
|
p = memcpy(h--, p, n);
|
||||||
@ -285,7 +285,7 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
|||||||
int fd = -1, lnk = h->type == SYMLINK;
|
int fd = -1, lnk = h->type == SYMLINK;
|
||||||
|
|
||||||
if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
|
if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
|
||||||
eprintf("strtol %s: invalid number\n", h->mtime);
|
eprintf("strtol %s: invalid mtime\n", h->mtime);
|
||||||
if (strcmp(fname, ".") && strcmp(fname, "./") && remove(fname) < 0)
|
if (strcmp(fname, ".") && strcmp(fname, "./") && remove(fname) < 0)
|
||||||
if (errno != ENOENT) weprintf("remove %s:", fname);
|
if (errno != ENOENT) weprintf("remove %s:", fname);
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
|||||||
case AREG:
|
case AREG:
|
||||||
case RESERVED:
|
case RESERVED:
|
||||||
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->mode);
|
eprintf("strtol %s: invalid mode\n", h->mode);
|
||||||
fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
|
fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
eprintf("open %s:", fname);
|
eprintf("open %s:", fname);
|
||||||
@ -313,7 +313,7 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
|||||||
break;
|
break;
|
||||||
case DIRECTORY:
|
case DIRECTORY:
|
||||||
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->mode);
|
eprintf("strtol %s: invalid mode\n", h->mode);
|
||||||
if (mkdir(fname, (mode_t)mode) < 0 && errno != EEXIST)
|
if (mkdir(fname, (mode_t)mode) < 0 && errno != EEXIST)
|
||||||
eprintf("mkdir %s:", fname);
|
eprintf("mkdir %s:", fname);
|
||||||
pushdirtime(fname, mtime);
|
pushdirtime(fname, mtime);
|
||||||
@ -321,18 +321,18 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
|||||||
case CHARDEV:
|
case CHARDEV:
|
||||||
case BLOCKDEV:
|
case BLOCKDEV:
|
||||||
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->mode);
|
eprintf("strtol %s: invalid mode\n", h->mode);
|
||||||
if ((major = strtol(h->major, &p, 8)) < 0 || *p != '\0')
|
if ((major = strtol(h->major, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->major);
|
eprintf("strtol %s: invalid major device\n", h->major);
|
||||||
if ((minor = strtol(h->minor, &p, 8)) < 0 || *p != '\0')
|
if ((minor = strtol(h->minor, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->minor);
|
eprintf("strtol %s: invalid minor device\n", h->minor);
|
||||||
type = (h->type == CHARDEV) ? S_IFCHR : S_IFBLK;
|
type = (h->type == CHARDEV) ? S_IFCHR : S_IFBLK;
|
||||||
if (mknod(fname, type | mode, makedev(major, minor)) < 0)
|
if (mknod(fname, type | mode, makedev(major, minor)) < 0)
|
||||||
eprintf("mknod %s:", fname);
|
eprintf("mknod %s:", fname);
|
||||||
break;
|
break;
|
||||||
case FIFO:
|
case FIFO:
|
||||||
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->mode);
|
eprintf("strtol %s: invalid mode\n", h->mode);
|
||||||
if (mknod(fname, S_IFIFO | mode, 0) < 0)
|
if (mknod(fname, S_IFIFO | mode, 0) < 0)
|
||||||
eprintf("mknod %s:", fname);
|
eprintf("mknod %s:", fname);
|
||||||
break;
|
break;
|
||||||
@ -341,9 +341,9 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((uid = strtol(h->uid, &p, 8)) < 0 || *p != '\0')
|
if ((uid = strtol(h->uid, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->uid);
|
eprintf("strtol %s: invalid uid\n", h->uid);
|
||||||
if ((gid = strtol(h->gid, &p, 8)) < 0 || *p != '\0')
|
if ((gid = strtol(h->gid, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid number\n", h->gid);
|
eprintf("strtol %s: invalid gid\n", h->gid);
|
||||||
|
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
for (; l > 0; l -= BLKSIZ)
|
for (; l > 0; l -= BLKSIZ)
|
||||||
@ -404,7 +404,7 @@ c(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
|
|||||||
static void
|
static void
|
||||||
sanitize(struct header *h)
|
sanitize(struct header *h)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i, j, l;
|
||||||
struct {
|
struct {
|
||||||
char *f;
|
char *f;
|
||||||
size_t l;
|
size_t l;
|
||||||
@ -423,10 +423,14 @@ sanitize(struct header *h)
|
|||||||
* NULs as per the ustar specification. Patch all of them to
|
* NULs as per the ustar specification. Patch all of them to
|
||||||
* use NULs so we can perform string operations on them. */
|
* use NULs so we can perform string operations on them. */
|
||||||
for (i = 0; i < LEN(fields); i++){
|
for (i = 0; i < LEN(fields); i++){
|
||||||
for (j = 0; j < fields[i].l && fields[i].f[j] == ' '; j++);
|
j = 0, l = fields[i].l - 1;
|
||||||
for (; j < fields[i].l; j++)
|
for (; j < l && fields[i].f[j] == ' '; j++);
|
||||||
|
for (; j <= l; j++)
|
||||||
if (fields[i].f[j] == ' ')
|
if (fields[i].f[j] == ' ')
|
||||||
fields[i].f[j] = '\0';
|
fields[i].f[j] = '\0';
|
||||||
|
if (fields[i].f[l])
|
||||||
|
eprintf("numeric field #%d (%.*s) is not null or space terminated\n",
|
||||||
|
i, l+1, fields[i].f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +438,7 @@ static void
|
|||||||
chktar(struct header *h)
|
chktar(struct header *h)
|
||||||
{
|
{
|
||||||
const char *reason;
|
const char *reason;
|
||||||
char tmp[sizeof h->chksum], *err = "";
|
char tmp[sizeof h->chksum], *err;
|
||||||
long sum, i;
|
long sum, i;
|
||||||
|
|
||||||
if (h->prefix[0] == '\0' && h->name[0] == '\0') {
|
if (h->prefix[0] == '\0' && h->name[0] == '\0') {
|
||||||
@ -482,13 +486,13 @@ xt(int argc, char *argv[], int mode)
|
|||||||
if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0')
|
if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0')
|
||||||
eprintf("strtol %s: invalid size\n", h->size);
|
eprintf("strtol %s: invalid size\n", h->size);
|
||||||
|
|
||||||
/* Long file path is read direcly into fname*/
|
/* Long file path is read directly into fname*/
|
||||||
if (h->type == 'L' || h->type == 'x' || h->type == 'g') {
|
if (h->type == 'L' || h->type == 'x' || h->type == 'g') {
|
||||||
|
|
||||||
/* Read header only up to size of fname buffer */
|
/* Read header only up to size of fname buffer */
|
||||||
for (q = fname; q < fname+size; q += BLKSIZ) {
|
for (q = fname; q < fname+size; q += BLKSIZ) {
|
||||||
if (q + BLKSIZ >= fname + l)
|
if (q + BLKSIZ >= fname + l)
|
||||||
eprintf("name exceeds buffer: %s\n", fname);
|
eprintf("name exceeds buffer: %.*s\n", q-fname, fname);
|
||||||
eread(tarfd, q, BLKSIZ);
|
eread(tarfd, q, BLKSIZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user