sync with OpenBSD -current

This commit is contained in:
purplerain 2023-12-10 13:25:40 +00:00
parent 4c73aa256c
commit 086d8cf2c2
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
118 changed files with 975 additions and 393 deletions

View file

@ -1,4 +1,4 @@
/* $OpenBSD: tar.c,v 1.73 2023/09/04 17:05:34 jca Exp $ */
/* $OpenBSD: tar.c,v 1.74 2023/12/09 23:00:11 jca Exp $ */
/* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */
/*-
@ -35,10 +35,12 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <libgen.h>
#include <limits.h>
#include <pwd.h>
#include <stdio.h>
@ -50,6 +52,19 @@
#include "extern.h"
#include "tar.h"
SLIST_HEAD(xheader, xheader_record);
struct xheader_record {
SLIST_ENTRY(xheader_record) entry;
size_t reclen;
char *record;
};
/* shortest possible extended record: "5 a=\n" */
#define MINXHDRSZ 5
/* longest record we'll accept */
#define MAXXHDRSZ BLKMULT
/*
* Routines for reading, writing and header identify of various versions of tar
*/
@ -60,6 +75,9 @@ static char *name_split(char *, int);
static int ul_oct(u_long, char *, int, int);
static int ull_oct(unsigned long long, char *, int, int);
static int rd_xheader(ARCHD *arcn, int, off_t);
#ifndef SMALL
static int wr_xheader(ARCHD *, struct xheader *);
#endif
static uid_t uid_nobody;
static uid_t uid_warn;
@ -891,24 +909,121 @@ reset:
return(0);
}
/*
* ustar_wr()
* write a ustar header for the file specified in the ARCHD to the archive
* Have to check for file types that cannot be stored and file names that
* are too long. Be careful of the term (last arg) to ul_oct, we only use
* '\0' for the termination character (this is different than picky tar)
* ASSUMED: space after header in header block is zero filled
* Return:
* 0 if file has data to be written after the header, 1 if file has NO
* data to write after the header, -1 if archive write failed
*/
#ifndef SMALL
static int
xheader_add(struct xheader *xhdr, const char *keyword,
const char *value)
{
struct xheader_record *rec;
int reclen, tmplen;
char *s;
int
ustar_wr(ARCHD *arcn)
tmplen = MINXHDRSZ;
do {
reclen = tmplen;
tmplen = snprintf(NULL, 0, "%d %s=%s\n", reclen, keyword,
value);
} while (tmplen >= 0 && tmplen != reclen);
if (tmplen < 0)
return -1;
rec = calloc(1, sizeof(*rec));
if (rec == NULL)
return -1;
rec->reclen = reclen;
if (asprintf(&s, "%d %s=%s\n", reclen, keyword, value) < 0) {
free(rec);
return -1;
}
rec->record = s;
SLIST_INSERT_HEAD(xhdr, rec, entry);
return 0;
}
static void
xheader_free(struct xheader *xhdr)
{
struct xheader_record *rec;
while (!SLIST_EMPTY(xhdr)) {
rec = SLIST_FIRST(xhdr);
SLIST_REMOVE_HEAD(xhdr, entry);
free(rec->record);
free(rec);
}
}
static int
wr_xheader(ARCHD *arcn, struct xheader *xhdr)
{
char hdblk[sizeof(HD_USTAR)];
HD_USTAR *hd;
char buf[sizeof(hd->name) + 1];
struct xheader_record *rec;
size_t size;
size = 0;
SLIST_FOREACH(rec, xhdr, entry)
size += rec->reclen;
memset(hdblk, 0, sizeof(hdblk));
hd = (HD_USTAR *)hdblk;
hd->typeflag = XHDRTYPE;
strncpy(hd->magic, TMAGIC, TMAGLEN);
strncpy(hd->version, TVERSION, TVERSLEN);
if (ul_oct(size, hd->size, sizeof(hd->size), 3))
return -1;
/*
* Best effort attempt at providing a useful file name for
* implementations that don't support pax format. Don't bother
* with truncation if the resulting file name doesn't fit.
* XXX dirname/basename portability (check return value?)
*/
(void)snprintf(buf, sizeof(buf), "%s/PaxHeaders.%ld/%s",
dirname(arcn->name), (long)getpid(), basename(arcn->name));
fieldcpy(hd->name, sizeof(hd->name), buf, sizeof(buf));
if (ul_oct(arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
ull_oct(arcn->sb.st_mtime < 0 ? 0 : arcn->sb.st_mtime, hd->mtime,
sizeof(hd->mtime), 1) ||
ul_oct(arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
ul_oct(arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0))
return -1;
if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
sizeof(hd->chksum), 3))
return -1;
/* write out extended header */
if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
return -1;
if (wr_skip(BLKMULT - sizeof(HD_USTAR)) < 0)
return -1;
/* write out extended header records */
SLIST_FOREACH(rec, xhdr, entry)
if (wr_rdbuf(rec->record, rec->reclen) < 0)
return -1;
if (wr_skip(TAR_PAD(size)) < 0)
return -1;
return 0;
}
#endif
static int
wr_ustar_or_pax(ARCHD *arcn, int ustar)
{
HD_USTAR *hd;
const char *name;
char *pt, hdblk[sizeof(HD_USTAR)];
#ifndef SMALL
struct xheader xhdr = SLIST_HEAD_INITIALIZER(xhdr);
#endif
/*
* check for those file system types ustar cannot store
@ -929,8 +1044,19 @@ ustar_wr(ARCHD *arcn)
*/
if (PAX_IS_LINK(arcn->type) &&
((size_t)arcn->ln_nlen > sizeof(hd->linkname))) {
paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
return(1);
if (ustar) {
paxwarn(1, "Link name too long for ustar %s",
arcn->ln_name);
return(1);
}
#ifndef SMALL
else if (xheader_add(&xhdr, "linkpath", arcn->name) == -1) {
paxwarn(1, "Link name too long for pax %s",
arcn->ln_name);
xheader_free(&xhdr);
return(1);
}
#endif
}
/*
@ -938,8 +1064,21 @@ ustar_wr(ARCHD *arcn)
* pt != arcn->name, the name has to be split
*/
if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
paxwarn(1, "File name too long for ustar %s", arcn->name);
return(1);
if (ustar) {
paxwarn(1, "File name too long for ustar %s",
arcn->name);
return(1);
}
#ifndef SMALL
else if (xheader_add(&xhdr, "path", arcn->name) == -1) {
paxwarn(1, "File name too long for pax %s",
arcn->ln_name);
xheader_free(&xhdr);
return(1);
}
/* PAX format, we don't need to split the path */
pt = arcn->name;
#endif
}
/*
@ -1074,6 +1213,18 @@ ustar_wr(ARCHD *arcn)
strncpy(hd->gname, name, sizeof(hd->gname));
}
#ifndef SMALL
/* write out a pax extended header if needed */
if (!SLIST_EMPTY(&xhdr)) {
int ret;
ret = wr_xheader(arcn, &xhdr);
xheader_free(&xhdr);
if (ret == -1)
return(-1);
}
#endif
/*
* calculate and store the checksum write the header to the archive
* return 0 tells the caller to now write the file data, 1 says no data
@ -1091,6 +1242,9 @@ ustar_wr(ARCHD *arcn)
return(1);
out:
#ifndef SMALL
xheader_free(&xhdr);
#endif
/*
* header field is out of range
*/
@ -1098,6 +1252,42 @@ ustar_wr(ARCHD *arcn)
return(1);
}
/*
* ustar_wr()
* Write out a ustar format archive.
* Have to check for file types that cannot be stored and file names that
* are too long. Be careful of the term (last arg) to ul_oct, we only use
* '\0' for the termination character (this is different than picky tar).
* ASSUMED: space after header in header block is zero filled
* Return:
* 0 if file has data to be written after the header, 1 if file has NO
* data to write after the header, -1 if archive write failed
*/
int
ustar_wr(ARCHD *arcn)
{
return wr_ustar_or_pax(arcn, 1);
}
/*
* pax_wr()
* Write out a pax format archive.
* Have to check for file types that cannot be stored. Be careful of the
* term (last arg) to ul_oct, we only use '\0' for the termination
* character (this is different than picky tar).
* ASSUMED: space after header in header block is zero filled
* Return:
* 0 if file has data to be written after the header, 1 if file has NO
* data to write after the header, -1 if archive write failed
*/
#ifndef SMALL
int
pax_wr(ARCHD *arcn)
{
return wr_ustar_or_pax(arcn, 0);
}
#endif
/*
* name_split()
* see if the name has to be split for storage in a ustar header. We try
@ -1184,12 +1374,6 @@ expandname(char *buf, size_t len, char **gnu_name, const char *name,
return(nlen);
}
/* shortest possible extended record: "5 a=\n" */
#define MINXHDRSZ 5
/* longest record we'll accept */
#define MAXXHDRSZ BLKMULT
static int
rd_time(struct timespec *ts, const char *keyword, char *p)
{