-/* $OpenBSD: tar.c,v 1.75 2023/12/21 01:20:54 jca Exp $ */
+/* $OpenBSD: tar.c,v 1.76 2023/12/22 20:29:27 jca Exp $ */
/* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */
/*-
memset(arcn, 0, sizeof(*arcn));
arcn->org_name = arcn->name;
arcn->sb.st_nlink = 1;
+ arcn->sb.st_size = (off_t)-1;
/* Process Extended headers. */
if (hd->typeflag == XHDRTYPE || hd->typeflag == GHDRTYPE) {
*/
arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
0xfff);
- arcn->sb.st_size = (off_t)asc_ull(hd->size, sizeof(hd->size), OCT);
+ if (arcn->sb.st_size == (off_t)-1) {
+ arcn->sb.st_size =
+ (off_t)asc_ull(hd->size, sizeof(hd->size), OCT);
+ }
if (arcn->sb.st_mtime == 0) {
val = asc_ull(hd->mtime, sizeof(hd->mtime), OCT);
if (val > MAX_TIME_T)
return 0;
}
+static int
+xheader_add_ull(struct xheader *xhdr, const char *keyword,
+ unsigned long long value)
+{
+ struct xheader_record *rec;
+ int reclen, tmplen;
+ char *s;
+
+ tmplen = MINXHDRSZ;
+ do {
+ reclen = tmplen;
+ tmplen = snprintf(NULL, 0, "%d %s=%llu\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=%llu\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)
{
hd->typeflag = REGTYPE;
arcn->pad = TAR_PAD(arcn->sb.st_size);
if (ull_oct(arcn->sb.st_size, hd->size, sizeof(hd->size), 3)) {
- paxwarn(1, "File is too long for ustar %s",
- arcn->org_name);
- return(1);
+ if (ustar) {
+ paxwarn(1, "File is too long for ustar %s",
+ arcn->org_name);
+ return(1);
+ }
+#ifndef SMALL
+ else if (xheader_add_ull(&xhdr, "size",
+ arcn->sb.st_size) == -1) {
+ paxwarn(1, "File is too long for pax %s",
+ arcn->org_name);
+ xheader_free(&xhdr);
+ return(1);
+ }
+#endif
}
break;
}
return 0;
}
+static int
+rd_size(off_t *size, const char *keyword, char *p)
+{
+ const char *errstr;
+
+ /* Assume off_t is a long long. */
+ *size = strtonum(p, 0, LLONG_MAX,
+ &errstr);
+ if (errstr != NULL) {
+ paxwarn(1, "%s is %s: %s", keyword, errstr, p);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
rd_xheader(ARCHD *arcn, int global, off_t size)
{
ret = rd_time(&arcn->sb.st_ctim, keyword, p);
if (ret < 0)
break;
+ } else if (!strcmp(keyword, "size")) {
+ ret = rd_size(&arcn->sb.st_size, keyword, p);
+ if (ret < 0)
+ break;
}
}
p = nextp;