Module Name:    src
Committed By:   christos
Date:           Sat Jun 19 13:56:35 UTC 2021

Modified Files:
        src/include/protocols: dumprestore.h
        src/sbin/dump: dump.h tape.c traverse.c
        src/sbin/restore: dirs.c extern.h interactive.c main.c restore.c
            restore.h symtab.c tape.c utilities.c
        src/sys/sys: extattr.h

Log Message:
Add external attribute dumping and restoring support from FreeBSD.
Does not fully work yet, attributes are being saved and restored correctly,
but don't appear in the restored files somehow.


To generate a diff of this commit:
cvs rdiff -u -r1.19 -r1.20 src/include/protocols/dumprestore.h
cvs rdiff -u -r1.59 -r1.60 src/sbin/dump/dump.h
cvs rdiff -u -r1.56 -r1.57 src/sbin/dump/tape.c
cvs rdiff -u -r1.52 -r1.53 src/sbin/dump/traverse.c
cvs rdiff -u -r1.51 -r1.52 src/sbin/restore/dirs.c
cvs rdiff -u -r1.15 -r1.16 src/sbin/restore/extern.h
cvs rdiff -u -r1.28 -r1.29 src/sbin/restore/interactive.c
cvs rdiff -u -r1.36 -r1.37 src/sbin/restore/main.c
cvs rdiff -u -r1.21 -r1.22 src/sbin/restore/restore.c
cvs rdiff -u -r1.22 -r1.23 src/sbin/restore/restore.h
cvs rdiff -u -r1.29 -r1.30 src/sbin/restore/symtab.c
cvs rdiff -u -r1.70 -r1.71 src/sbin/restore/tape.c
cvs rdiff -u -r1.23 -r1.24 src/sbin/restore/utilities.c
cvs rdiff -u -r1.10 -r1.11 src/sys/sys/extattr.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/include/protocols/dumprestore.h
diff -u src/include/protocols/dumprestore.h:1.19 src/include/protocols/dumprestore.h:1.20
--- src/include/protocols/dumprestore.h:1.19	Sun Apr  5 11:25:39 2020
+++ src/include/protocols/dumprestore.h	Sat Jun 19 09:56:34 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: dumprestore.h,v 1.19 2020/04/05 15:25:39 joerg Exp $	*/
+/*	$NetBSD: dumprestore.h,v 1.20 2021/06/19 13:56:34 christos Exp $	*/
 
 /*
  * Copyright (c) 1980, 1993
@@ -95,7 +95,8 @@ extern union u_spcl {
 				int64_t __uc_birthtime;
 				int64_t __uc_atime;
 				int64_t __uc_mtime;
-				int32_t __uc_spare4[7];
+				int32_t __uc_extsize;
+				int32_t __uc_spare4[6];
 				uint32_t __uc_file_flags;
 				int32_t __uc_spare5[2];
 				uint32_t __uc_uid;
@@ -125,6 +126,7 @@ extern union u_spcl {
 #define c_mode		__c_ino.__uc_ino.__uc_mode
 #define c_spare1	__c_ino.__uc_ino.__uc_spare1
 #define c_size		__c_ino.__uc_ino.__uc_size
+#define c_extsize	__c_ino.__uc_ino.__uc_extsize
 #define c_old_atime	__c_ino.__uc_ino.__uc_old_atime
 #define c_atime		__c_ino.__uc_ino.__uc_atime
 #define c_atimensec	__c_ino.__uc_ino.__uc_atimensec

Index: src/sbin/dump/dump.h
diff -u src/sbin/dump/dump.h:1.59 src/sbin/dump/dump.h:1.60
--- src/sbin/dump/dump.h:1.59	Thu Dec  3 03:25:57 2020
+++ src/sbin/dump/dump.h	Sat Jun 19 09:56:34 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: dump.h,v 1.59 2020/12/03 08:25:57 kre Exp $	*/
+/*	$NetBSD: dump.h,v 1.60 2021/06/19 13:56:34 christos Exp $	*/
 
 /*-
  * Copyright (c) 1980, 1993
@@ -205,7 +205,7 @@ int	mapdirs(ino_t, u_int64_t *);
 
 /* file dumping routines */
 void	blksout32(int32_t *, int, ino_t);
-void	blksout64(int64_t *, int, ino_t);
+void	blksout64(union dinode *, int64_t *, int, ino_t, int);
 void	dumpino(union dinode *, ino_t);
 #ifndef RRESTORE
 void	dumpmap(char *, int, ino_t);

Index: src/sbin/dump/tape.c
diff -u src/sbin/dump/tape.c:1.56 src/sbin/dump/tape.c:1.57
--- src/sbin/dump/tape.c:1.56	Mon Jun  7 10:07:32 2021
+++ src/sbin/dump/tape.c	Sat Jun 19 09:56:34 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: tape.c,v 1.56 2021/06/07 14:07:32 hannken Exp $	*/
+/*	$NetBSD: tape.c,v 1.57 2021/06/19 13:56:34 christos Exp $	*/
 
 /*-
  * Copyright (c) 1980, 1991, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)tape.c	8.4 (Berkeley) 5/1/95";
 #else
-__RCSID("$NetBSD: tape.c,v 1.56 2021/06/07 14:07:32 hannken Exp $");
+__RCSID("$NetBSD: tape.c,v 1.57 2021/06/19 13:56:34 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -69,8 +69,8 @@ char	*nexttape;
 
 static	ssize_t atomic_read(int, void *, int);
 static	ssize_t atomic_write(int, const void *, int);
-static	void doslave(int, int);
-static	void enslave(void);
+static	void doworker(int, int);
+static	void create_workers(void);
 static	void flushtape(void);
 static	void killall(void);
 static	void proceed(int);
@@ -80,11 +80,11 @@ static	void tperror(int);
 
 /*
  * Concurrent dump mods (Caltech) - disk block reading and tape writing
- * are exported to several slave processes.  While one slave writes the
+ * are exported to several worker processes.  While one worker writes the
  * tape, the others read disk blocks; they pass control of the tape in
  * a ring via signals. The parent process traverses the file system and
- * sends writeheader()'s and lists of daddr's to the slaves via pipes.
- * The following structure defines the instruction packets sent to slaves.
+ * sends writeheader()'s and lists of daddr's to the workers via pipes.
+ * The following structure defines the instruction packets sent to workers.
  */
 struct req {
 	daddr_t dblk;
@@ -92,20 +92,20 @@ struct req {
 };
 int reqsiz;
 
-#define SLAVES 3		/* 1 slave writing, 1 reading, 1 for slack */
-struct slave {
+#define WORKERS 3		/* 1 worker writing, 1 reading, 1 for slack */
+struct worker {
 	int64_t tapea;		/* header number at start of this chunk */
 	int64_t firstrec;	/* record number of this block */
 	int count;		/* count to next header (used for TS_TAPE */
 				/* after EOT) */
 	int inode;		/* inode that we are currently dealing with */
-	int fd;			/* FD for this slave */
-	int pid;		/* PID for this slave */
-	int sent;		/* 1 == we've sent this slave requests */
+	int fd;			/* FD for this worker */
+	int pid;		/* PID for this worker */
+	int sent;		/* 1 == we've sent this worker requests */
 	char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
 	struct req *req;	/* buffer for requests */
-} slaves[SLAVES+1];
-struct slave *slp;
+} workers[WORKERS+1];
+struct worker *wp;
 
 char	(*nextblock)[TP_BSIZE];
 
@@ -138,18 +138,18 @@ alloctape(void)
 	 * packets, so flushtape() can write them together with one write().
 	 * Align tape buffer on page boundary to speed up tape write().
 	 */
-	for (i = 0; i <= SLAVES; i++) {
+	for (i = 0; i <= WORKERS; i++) {
 		buf = (char *)
 		    xmalloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
-		slaves[i].tblock = (char (*)[TP_BSIZE])
+		workers[i].tblock = (char (*)[TP_BSIZE])
 		    (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
-		slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
+		workers[i].req = (struct req *)workers[i].tblock - ntrec - 1;
 	}
-	slp = &slaves[0];
-	slp->count = 1;
-	slp->tapea = 0;
-	slp->firstrec = 0;
-	nextblock = slp->tblock;
+	wp = &workers[0];
+	wp->count = 1;
+	wp->tapea = 0;
+	wp->firstrec = 0;
+	nextblock = wp->tblock;
 	return(1);
 }
 
@@ -157,8 +157,8 @@ void
 writerec(const char *dp, int isspcl)
 {
 
-	slp->req[trecno].dblk = (daddr_t)0;
-	slp->req[trecno].count = 1;
+	wp->req[trecno].dblk = (daddr_t)0;
+	wp->req[trecno].count = 1;
 	*(union u_spcl *)(*(nextblock)++) = *(const union u_spcl *)dp;
 	if (isspcl)
 		lastspclrec = iswap64(spcl.c_tapea);
@@ -177,8 +177,8 @@ dumpblock(daddr_t blkno, int size)
 	dblkno = fsatoda(ufsib, blkno);
 	tpblks = size >> tp_bshift;
 	while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
-		slp->req[trecno].dblk = dblkno;
-		slp->req[trecno].count = avail;
+		wp->req[trecno].dblk = dblkno;
+		wp->req[trecno].count = avail;
 		trecno += avail;
 		spcl.c_tapea = iswap64(iswap64(spcl.c_tapea) + avail);
 		if (trecno >= ntrec)
@@ -279,27 +279,27 @@ flushtape(void)
 	int i, blks, got;
 	int64_t lastfirstrec;
 
-	int siz = (char *)nextblock - (char *)slp->req;
+	int siz = (char *)nextblock - (char *)wp->req;
 
-	slp->req[trecno].count = 0;			/* Sentinel */
+	wp->req[trecno].count = 0;			/* Sentinel */
 
-	if (atomic_write(slp->fd, slp->req, siz) != siz)
+	if (atomic_write(wp->fd, wp->req, siz) != siz)
 		quite(errno, "error writing command pipe");
-	slp->sent = 1; /* we sent a request, read the response later */
+	wp->sent = 1; /* we sent a request, read the response later */
 
-	lastfirstrec = slp->firstrec;
+	lastfirstrec = wp->firstrec;
 
-	if (++slp >= &slaves[SLAVES])
-		slp = &slaves[0];
+	if (++wp >= &workers[WORKERS])
+		wp = &workers[0];
 
-	/* Read results back from next slave */
-	if (slp->sent) {
-		if (atomic_read(slp->fd, &got, sizeof got)
+	/* Read results back from next worker */
+	if (wp->sent) {
+		if (atomic_read(wp->fd, &got, sizeof got)
 		    != sizeof got) {
 			perror("  DUMP: error reading command pipe in master");
 			dumpabort(0);
 		}
-		slp->sent = 0;
+		wp->sent = 0;
 
 		/* Check for end of tape */
 		if (got < writesize) {
@@ -309,15 +309,15 @@ flushtape(void)
 			 * Drain the results, don't care what the values were.
 			 * If we read them here then trewind won't...
 			 */
-			for (i = 0; i < SLAVES; i++) {
-				if (slaves[i].sent) {
-					if (atomic_read(slaves[i].fd,
+			for (i = 0; i < WORKERS; i++) {
+				if (workers[i].sent) {
+					if (atomic_read(workers[i].fd,
 					    &got, sizeof got)
 					    != sizeof got) {
 						perror("  DUMP: error reading command pipe in master");
 						dumpabort(0);
 					}
-					slaves[i].sent = 0;
+					workers[i].sent = 0;
 				}
 			}
 
@@ -334,11 +334,11 @@ flushtape(void)
 			if (spcl.c_addr[i] != 0)
 				blks++;
 	}
-	slp->count = lastspclrec + blks + 1 - iswap64(spcl.c_tapea);
-	slp->tapea = iswap64(spcl.c_tapea);
-	slp->firstrec = lastfirstrec + ntrec;
-	slp->inode = curino;
-	nextblock = slp->tblock;
+	wp->count = lastspclrec + blks + 1 - iswap64(spcl.c_tapea);
+	wp->tapea = iswap64(spcl.c_tapea);
+	wp->firstrec = lastfirstrec + ntrec;
+	wp->inode = curino;
+	nextblock = wp->tblock;
 	trecno = 0;
 	asize += tenths;
 	blockswritten += ntrec;
@@ -357,7 +357,7 @@ trewind(int eject)
 	int f;
 	int got;
 
-	for (f = 0; f < SLAVES; f++) {
+	for (f = 0; f < WORKERS; f++) {
 		/*
 		 * Drain the results, but unlike EOT we DO (or should) care
 		 * what the return values were, since if we detect EOT after
@@ -366,22 +366,22 @@ trewind(int eject)
 		 *
 		 * fixme: punt for now.
 		 */
-		if (slaves[f].sent) {
-			if (atomic_read(slaves[f].fd, &got, sizeof got)
+		if (workers[f].sent) {
+			if (atomic_read(workers[f].fd, &got, sizeof got)
 			    != sizeof got) {
 				perror("  DUMP: error reading command pipe in master");
 				dumpabort(0);
 			}
-			slaves[f].sent = 0;
+			workers[f].sent = 0;
 			if (got != writesize) {
 				msg("EOT detected in last 2 tape records!\n");
 				msg("Use a longer tape, decrease the size estimate\n");
 				quit("or use no size estimate at all");
 			}
 		}
-		(void) close(slaves[f].fd);
+		(void) close(workers[f].fd);
 	}
-	while (wait(NULL) >= 0)	/* wait for any signals from slaves */
+	while (wait(NULL) >= 0)	/* wait for any signals from workers */
 		/* void */;
 
 	if (pipeout)
@@ -457,29 +457,29 @@ void
 rollforward(void)
 {
 	struct req *p, *q, *prev;
-	struct slave *tslp;
+	struct worker *twp;
 	int i, size, got;
 	int64_t savedtapea;
 	union u_spcl *ntb, *otb;
-	tslp = &slaves[SLAVES];
-	ntb = (union u_spcl *)tslp->tblock[1];
+	twp = &workers[WORKERS];
+	ntb = (union u_spcl *)twp->tblock[1];
 
 	/*
-	 * Each of the N slaves should have requests that need to
-	 * be replayed on the next tape.  Use the extra slave buffers
-	 * (slaves[SLAVES]) to construct request lists to be sent to
-	 * each slave in turn.
+	 * Each of the N workers should have requests that need to
+	 * be replayed on the next tape.  Use the extra worker buffers
+	 * (workers[WORKERS]) to construct request lists to be sent to
+	 * each worker in turn.
 	 */
-	for (i = 0; i < SLAVES; i++) {
-		q = &tslp->req[1];
-		otb = (union u_spcl *)slp->tblock;
+	for (i = 0; i < WORKERS; i++) {
+		q = &twp->req[1];
+		otb = (union u_spcl *)wp->tblock;
 
 		/*
-		 * For each request in the current slave, copy it to tslp.
+		 * For each request in the current worker, copy it to twp.
 		 */
 
 		prev = NULL;
-		for (p = slp->req; p->count > 0; p += p->count) {
+		for (p = wp->req; p->count > 0; p += p->count) {
 			*q = *p;
 			if (p->dblk == 0)
 				*ntb++ = *otb++; /* copy the datablock also */
@@ -494,26 +494,26 @@ rollforward(void)
 			ntb--;
 		q -= 1;
 		q->count = 0;
-		q = &tslp->req[0];
+		q = &twp->req[0];
 		if (i == 0) {
 			q->dblk = 0;
 			q->count = 1;
 			trecno = 0;
-			nextblock = tslp->tblock;
+			nextblock = twp->tblock;
 			savedtapea = iswap64(spcl.c_tapea);
-			spcl.c_tapea = iswap64(slp->tapea);
+			spcl.c_tapea = iswap64(wp->tapea);
 			startnewtape(0);
 			spcl.c_tapea = iswap64(savedtapea);
 			lastspclrec = savedtapea - 1;
 		}
 		size = (char *)ntb - (char *)q;
-		if (atomic_write(slp->fd, q, size) != size) {
+		if (atomic_write(wp->fd, q, size) != size) {
 			perror("  DUMP: error writing command pipe");
 			dumpabort(0);
 		}
-		slp->sent = 1;
-		if (++slp >= &slaves[SLAVES])
-			slp = &slaves[0];
+		wp->sent = 1;
+		if (++wp >= &workers[WORKERS])
+			wp = &workers[0];
 
 		q->count = 1;
 
@@ -525,34 +525,34 @@ rollforward(void)
 			 */
 			q->dblk = prev->dblk +
 				prev->count * (TP_BSIZE / DEV_BSIZE);
-			ntb = (union u_spcl *)tslp->tblock;
+			ntb = (union u_spcl *)twp->tblock;
 		} else {
 			/*
 			 * It wasn't a disk block.  Copy the data to its
 			 * new location in the buffer.
 			 */
 			q->dblk = 0;
-			*((union u_spcl *)tslp->tblock) = *ntb;
-			ntb = (union u_spcl *)tslp->tblock[1];
+			*((union u_spcl *)twp->tblock) = *ntb;
+			ntb = (union u_spcl *)twp->tblock[1];
 		}
 	}
-	slp->req[0] = *q;
-	nextblock = slp->tblock;
+	wp->req[0] = *q;
+	nextblock = wp->tblock;
 	if (q->dblk == 0)
 		nextblock++;
 	trecno = 1;
 
 	/*
-	 * Clear the first slaves' response.  One hopes that it
+	 * Clear the first workers' response.  One hopes that it
 	 * worked ok, otherwise the tape is much too short!
 	 */
-	if (slp->sent) {
-		if (atomic_read(slp->fd, &got, sizeof got)
+	if (wp->sent) {
+		if (atomic_read(wp->fd, &got, sizeof got)
 		    != sizeof got) {
 			perror("  DUMP: error reading command pipe in master");
 			dumpabort(0);
 		}
-		slp->sent = 0;
+		wp->sent = 0;
 
 		if (got != writesize) {
 			quit("EOT detected at start of the tape");
@@ -680,31 +680,31 @@ restore_check_point:
 				dumpabort(0);
 		}
 
-		enslave();  /* Share open tape file descriptor with slaves */
+		create_workers();  /* Share open tape file descriptor with workers */
 
 		asize = 0;
 		blocksthisvol = 0;
 		if (top)
 			newtape++;		/* new tape signal */
-		spcl.c_count = iswap32(slp->count);
+		spcl.c_count = iswap32(wp->count);
 		/*
 		 * measure firstrec in TP_BSIZE units since restore doesn't
 		 * know the correct ntrec value...
 		 */
-		spcl.c_firstrec = iswap32(slp->firstrec);
+		spcl.c_firstrec = iswap32(wp->firstrec);
 		spcl.c_volume = iswap32(iswap32(spcl.c_volume) + 1);
 		spcl.c_type = iswap32(TS_TAPE);
 		if (!is_ufs2)
 			spcl.c_flags = iswap32(iswap32(spcl.c_flags)
 			    | DR_NEWHEADER);
-		writeheader((ino_t)slp->inode);
+		writeheader((ino_t)wp->inode);
 		if (!is_ufs2)
 			spcl.c_flags  = iswap32(iswap32(spcl.c_flags) &
 			    ~ DR_NEWHEADER);
 		msg("Volume %d started at: %s", tapeno, ctime(&tstart_volume));
 		if (tapeno > 1)
 			msg("Volume %d begins with blocks from inode %d\n",
-				tapeno, slp->inode);
+				tapeno, wp->inode);
 	}
 }
 
@@ -739,7 +739,7 @@ Exit(int status)
 }
 
 /*
- * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
+ * proceed - handler for SIGUSR2, used to synchronize IO between the workers.
  */
 static void
 proceed(int signo __unused)
@@ -748,7 +748,7 @@ proceed(int signo __unused)
 }
 
 void
-enslave(void)
+create_workers(void)
 {
 	int cmd[2];
 	int i, j;
@@ -758,36 +758,36 @@ enslave(void)
 	signal(SIGTERM, dumpabort);  /* Slave sends SIGTERM on dumpabort() */
 	signal(SIGPIPE, sigpipe);
 	signal(SIGUSR1, tperror);    /* Slave sends SIGUSR1 on tape errors */
-	signal(SIGUSR2, proceed);    /* Slave sends SIGUSR2 to next slave */
+	signal(SIGUSR2, proceed);    /* Slave sends SIGUSR2 to next worker */
 
-	for (i = 0; i < SLAVES; i++) {
-		if (i == slp - &slaves[0]) {
+	for (i = 0; i < WORKERS; i++) {
+		if (i == wp - &workers[0]) {
 			caught = 1;
 		} else {
 			caught = 0;
 		}
 
 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, cmd) < 0 ||
-		    (slaves[i].pid = fork()) < 0)
-			quite(errno, "too many slaves, %d (recompile smaller)",
+		    (workers[i].pid = fork()) < 0)
+			quite(errno, "too many workers, %d (recompile smaller)",
 			    i);
 
-		slaves[i].fd = cmd[1];
-		slaves[i].sent = 0;
-		if (slaves[i].pid == 0) { 	    /* Slave starts up here */
+		workers[i].fd = cmd[1];
+		workers[i].sent = 0;
+		if (workers[i].pid == 0) { 	    /* Slave starts up here */
 			for (j = 0; j <= i; j++)
-				(void) close(slaves[j].fd);
+				(void) close(workers[j].fd);
 			signal(SIGINT, SIG_IGN);    /* Master handles this */
 			signal(SIGINFO, SIG_IGN);
-			doslave(cmd[0], i);
+			doworker(cmd[0], i);
 			Exit(X_FINOK);
 		}
 	}
 
-	for (i = 0; i < SLAVES; i++)
-		(void) atomic_write(slaves[i].fd,
-				&slaves[(i + 1) % SLAVES].pid,
-				sizeof slaves[0].pid);
+	for (i = 0; i < WORKERS; i++)
+		(void) atomic_write(workers[i].fd,
+				&workers[(i + 1) % WORKERS].pid,
+				sizeof workers[0].pid);
 
 	master = 0;
 }
@@ -797,10 +797,10 @@ killall(void)
 {
 	int i;
 
-	for (i = 0; i < SLAVES; i++)
-		if (slaves[i].pid > 0) {
-			(void) kill(slaves[i].pid, SIGKILL);
-			slaves[i].sent = 0;
+	for (i = 0; i < WORKERS; i++)
+		if (workers[i].pid > 0) {
+			(void) kill(workers[i].pid, SIGKILL);
+			workers[i].sent = 0;
 		}
 }
 
@@ -812,9 +812,9 @@ killall(void)
  * get the lock back for the next cycle by swapping descriptors.
  */
 static void
-doslave(int cmd, int slave_number __unused)
+doworker(int cmd, int worker_number __unused)
 {
-	int nread, nextslave, size, wrote, eot_count, werror;
+	int nread, nextworker, size, wrote, eot_count, werror;
 	sigset_t nsigset, osigset;
 
 	wrote = 0;
@@ -823,33 +823,33 @@ doslave(int cmd, int slave_number __unus
 	 */
 	(void) close(diskfd);
 	if ((diskfd = open(disk_dev, O_RDONLY)) < 0)
-		quite(errno, "slave couldn't reopen disk");
+		quite(errno, "worker couldn't reopen disk");
 
 	/*
-	 * Need the pid of the next slave in the loop...
+	 * Need the pid of the next worker in the loop...
 	 */
-	if ((nread = atomic_read(cmd, &nextslave, sizeof nextslave))
-	    != sizeof nextslave) {
-		quit("master/slave protocol botched - didn't get pid"
-		    " of next slave");
+	if ((nread = atomic_read(cmd, &nextworker, sizeof nextworker))
+	    != sizeof nextworker) {
+		quit("master/worker protocol botched - didn't get pid"
+		    " of next worker");
 	}
 
 	/*
 	 * Get list of blocks to dump, read the blocks into tape buffer
 	 */
-	while ((nread = atomic_read(cmd, slp->req, reqsiz)) == reqsiz) {
-		struct req *p = slp->req;
+	while ((nread = atomic_read(cmd, wp->req, reqsiz)) == reqsiz) {
+		struct req *p = wp->req;
 
 		for (trecno = 0; trecno < ntrec;
 		     trecno += p->count, p += p->count) {
 			if (p->dblk) {
-				bread(p->dblk, slp->tblock[trecno],
+				bread(p->dblk, wp->tblock[trecno],
 					p->count * TP_BSIZE);
 			} else {
 				if (p->count != 1 || atomic_read(cmd,
-				    slp->tblock[trecno],
+				    wp->tblock[trecno],
 				    TP_BSIZE) != TP_BSIZE)
-				       quit("master/slave protocol botched");
+				       quit("master/worker protocol botched");
 			}
 		}
 
@@ -869,16 +869,16 @@ doslave(int cmd, int slave_number __unus
 		while (eot_count < 10 && size < writesize) {
 #ifdef RDUMP
 			if (host)
-				wrote = rmtwrite(slp->tblock[0]+size,
+				wrote = rmtwrite(wp->tblock[0]+size,
 				    writesize-size);
 			else
 #endif
-				wrote = write(tapefd, slp->tblock[0]+size,
+				wrote = write(tapefd, wp->tblock[0]+size,
 				    writesize-size);
 			werror = errno;
 #ifdef WRITEDEBUG
-			fprintf(stderr, "slave %d wrote %d werror %d\n",
-			    slave_number, wrote, werror);
+			fprintf(stderr, "worker %d wrote %d werror %d\n",
+			    worker_number, wrote, werror);
 #endif
 			if (wrote < 0)
 				break;
@@ -890,8 +890,8 @@ doslave(int cmd, int slave_number __unus
 #ifdef WRITEDEBUG
 		if (size != writesize)
 			fprintf(stderr,
-		    "slave %d only wrote %d out of %d bytes and gave up.\n",
-			    slave_number, size, writesize);
+		    "worker %d only wrote %d out of %d bytes and gave up.\n",
+			    worker_number, size, writesize);
 #endif
 
 		/*
@@ -919,10 +919,10 @@ doslave(int cmd, int slave_number __unus
 		}
 
 		/*
-		 * If partial write, don't want next slave to go.
+		 * If partial write, don't want next worker to go.
 		 * Also jolts him awake.
 		 */
-		(void) kill(nextslave, SIGUSR2);
+		(void) kill(nextworker, SIGUSR2);
 	}
 	printcachestats();
 	if (nread != 0)

Index: src/sbin/dump/traverse.c
diff -u src/sbin/dump/traverse.c:1.52 src/sbin/dump/traverse.c:1.53
--- src/sbin/dump/traverse.c:1.52	Fri Mar  1 11:42:11 2019
+++ src/sbin/dump/traverse.c	Sat Jun 19 09:56:34 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: traverse.c,v 1.52 2019/03/01 16:42:11 christos Exp $	*/
+/*	$NetBSD: traverse.c,v 1.53 2021/06/19 13:56:34 christos Exp $	*/
 
 /*-
  * Copyright (c) 1980, 1988, 1991, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)traverse.c	8.7 (Berkeley) 6/15/95";
 #else
-__RCSID("$NetBSD: traverse.c,v 1.52 2019/03/01 16:42:11 christos Exp $");
+__RCSID("$NetBSD: traverse.c,v 1.53 2021/06/19 13:56:34 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -45,6 +45,7 @@ __RCSID("$NetBSD: traverse.c,v 1.52 2019
 #include <ufs/ffs/fs.h>
 #include <ufs/ffs/ffs_extern.h>
 
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fts.h>
@@ -58,8 +59,10 @@ __RCSID("$NetBSD: traverse.c,v 1.52 2019
 #define	HASDUMPEDFILE	0x1
 #define	HASSUBDIRS	0x2
 
+static	int appendextdata(union dinode *dp);
+static	void writeextdata(union dinode *dp, ino_t ino, int added);
 static	int dirindir(ino_t, daddr_t, int, off_t *, u_int64_t *, int);
-static	void dmpindir(ino_t, daddr_t, int, off_t *);
+static	void dmpindir(union dinode *dp, ino_t, daddr_t, int, off_t *);
 static	int searchdir(ino_t, daddr_t, long, off_t, u_int64_t *, int);
 
 /*
@@ -475,7 +478,7 @@ searchdir(ino_t dino, daddr_t blkno, lon
 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];
 	daddr_t blk;
@@ -504,6 +507,7 @@ dumpino(union dinode *dp, ino_t ino)
 			ffs_dinode2_swap(&dp->dp2, &dp->dp2);
 		spcl.c_mode = dp->dp2.di_mode;
 		spcl.c_size = dp->dp2.di_size;
+		spcl.c_extsize = dp->dp2.di_extsize;
 		spcl.c_atime = dp->dp2.di_atime;
 		spcl.c_atimensec = dp->dp2.di_atimensec;
 		spcl.c_mtime = dp->dp2.di_mtime;
@@ -539,6 +543,7 @@ dumpino(union dinode *dp, ino_t ino)
 			) {
 			spcl.c_addr[0] = 1;
 			spcl.c_count = iswap32(1);
+			added = appendextdata(dp);
 			writeheader(ino);
 			if (is_ufs2)
 				shortlink = dp->dp2.di_db;
@@ -547,6 +552,7 @@ dumpino(union dinode *dp, ino_t ino)
 			memmove(buf, shortlink, DIP(dp, size));
 			buf[DIP(dp, size)] = '\0';
 			writerec(buf, 0);
+			writeextdata(dp, ino, added);
 			return;
 		}
 		/* fall through */
@@ -561,19 +567,24 @@ dumpino(union dinode *dp, ino_t ino)
 	case IFSOCK:
 	case IFCHR:
 	case IFBLK:
+		added = appendextdata(dp);
 		writeheader(ino);
+		writeextdata(dp, ino, added);
 		return;
 
 	default:
 		msg("Warning: undefined file type 0%o\n", DIP(dp, mode) & IFMT);
 		return;
 	}
-	if (DIP(dp, size) > UFS_NDADDR * ufsib->ufs_bsize)
+	if (DIP(dp, size) > UFS_NDADDR * ufsib->ufs_bsize) {
 		cnt = UFS_NDADDR * ufsib->ufs_frag;
-	else
+		last = 0;
+	} else {
 		cnt = howmany(DIP(dp, size), ufsib->ufs_fsize);
+		last = 1;
+	}
 	if (is_ufs2)
-		blksout64(&dp->dp2.di_db[0], cnt, ino);
+		blksout64(dp, &dp->dp2.di_db[0], cnt, ino, last);
 	else
 		blksout32(&dp->dp1.di_db[0], cnt, ino);
 
@@ -584,7 +595,7 @@ dumpino(union dinode *dp, ino_t ino)
 			blk = iswap64(dp->dp2.di_ib[ind_level]);
 		else
 			blk = iswap32(dp->dp1.di_ib[ind_level]);
-		dmpindir(ino, blk, ind_level, &size);
+		dmpindir(dp, ino, blk, ind_level, &size);
 		if (size <= 0)
 			return;
 	}
@@ -594,9 +605,9 @@ dumpino(union dinode *dp, ino_t ino)
  * Read indirect blocks, and pass the data blocks to be dumped.
  */
 static void
-dmpindir(ino_t ino, daddr_t blk, int ind_level, off_t *size)
+dmpindir(union dinode *dp, ino_t ino, daddr_t blk, int ind_level, off_t *size)
 {
-	int i, cnt;
+	int i, cnt, last;
 	union {
 		int32_t i32[MAXBSIZE / sizeof (int32_t)];
 		int64_t i64[MAXBSIZE / sizeof (int64_t)];
@@ -610,13 +621,16 @@ dmpindir(ino_t ino, daddr_t blk, int ind
 	else
 		memset(&idblk, 0, (int)ufsib->ufs_bsize);
 	if (ind_level <= 0) {
-		if (*size < ufsib->ufs_nindir * ufsib->ufs_bsize)
+		if (*size < ufsib->ufs_nindir * ufsib->ufs_bsize) {
 			cnt = howmany(*size, ufsib->ufs_fsize);
-		else
+			last = 0;
+		} else {
 			cnt = ufsib->ufs_nindir * ufsib->ufs_frag;
+			last = 1;
+		}
 		*size -= ufsib->ufs_nindir * ufsib->ufs_bsize;
 		if (is_ufs2)
-			blksout64(&idblk.i64[0], cnt, ino);
+			blksout64(dp, &idblk.i64[0], cnt, ino, last);
 		else
 			blksout32(&idblk.i32[0], cnt, ino);
 		return;
@@ -627,7 +641,7 @@ dmpindir(ino_t ino, daddr_t blk, int ind
 			iblk = iswap64(idblk.i64[i]);
 		else
 			iblk = iswap32(idblk.i32[i]);
-		dmpindir(ino, iblk, ind_level, size);
+		dmpindir(dp, ino, iblk, ind_level, size);
 		if (*size <= 0)
 			return;
 	}
@@ -669,24 +683,40 @@ blksout32(int32_t *blkp, int frags, ino_
 }
 
 void
-blksout64(int64_t *blkp, int frags, ino_t ino)
+blksout64(union dinode *dp, int64_t *blkp, int frags, ino_t ino, int last)
 {
 	int64_t *bp;
-	int i, j, count, blks, tbperdb;
+	int i, j, count, blks, tbperdb, added = 0;
+	static int writingextdata = 0;
 
 	blks = howmany(frags * ufsib->ufs_fsize, TP_BSIZE);
+	if (last) {
+		int resid;
+		int extsize = iswap32(spcl.c_extsize);
+		if (writingextdata)
+			resid = howmany(ufsib->ufs_qfmask & extsize,
+			    TP_BSIZE);
+		else
+			resid = howmany(ufsib->ufs_qfmask & dp->dp2.di_size,
+			    TP_BSIZE);
+		if (resid > 0)
+			blks -= howmany(ufsib->ufs_fsize, TP_BSIZE) - resid;
+	}
 	tbperdb = ufsib->ufs_bsize >> tp_bshift;
 	for (i = 0; i < blks; i += TP_NINDIR) {
 		if (i + TP_NINDIR > blks)
 			count = blks;
 		else
 			count = i + TP_NINDIR;
+		assert(count <= TP_NINDIR + i);
 		for (j = i; j < count; j++)
 			if (blkp[j / tbperdb] != 0)
 				spcl.c_addr[j - i] = 1;
 			else
 				spcl.c_addr[j - i] = 0;
 		spcl.c_count = iswap32(count - i);
+		if (last && count == blks && !writingextdata)
+			added = appendextdata(dp);
 		writeheader(ino);
 		bp = &blkp[i / tbperdb];
 		for (j = i; j < count; j += tbperdb, bp++)
@@ -697,10 +727,130 @@ blksout64(int64_t *blkp, int frags, ino_
 					dumpblock(iswap64(*bp), (count - j) * TP_BSIZE);
 			}
 		spcl.c_type = iswap32(TS_ADDR);
+		spcl.c_count = 0;
+		if (last && count == blks && !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, count, extsize;
+
+	count = iswap32(spcl.c_count);
+	extsize = iswap32(spcl.c_extsize);
+	/*
+	 * If no extended attributes, there is nothing to do.
+	 */
+	if (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 (extsize > UFS_NXADDR * ufsib->ufs_bsize)
+		blks = howmany(UFS_NXADDR * ufsib->ufs_bsize, TP_BSIZE);
+	else
+		blks = howmany(extsize, TP_BSIZE);
+	if (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 = ufsib->ufs_bsize >> tp_bshift;
+	assert(count + blks < TP_NINDIR);
+	for (i = 0; i < blks; i++)
+		if (&dp->dp2.di_extb[i / tbperdb] != 0)
+				spcl.c_addr[count + i] = 1;
+			else
+				spcl.c_addr[count + i] = 0;
+	spcl.c_count = iswap32(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, extsize;
+	int64_t *bp;
+	off_t size;
+
+	extsize = iswap32(spcl.c_extsize);
+
+	/*
+	 * If no extended attributes, there is nothing to do.
+	 */
+	if (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 (extsize > UFS_NXADDR * ufsib->ufs_bsize) {
+			frags = UFS_NXADDR * ufsib->ufs_frag;
+			last = 0;
+		} else {
+			frags = howmany(extsize, ufsib->ufs_fsize);
+			last = 1;
+		}
+		blksout64(dp, &dp->dp2.di_extb[0], frags, ino, last);
+	} else {
+		if (extsize > UFS_NXADDR * ufsib->ufs_bsize)
+			blks = howmany(UFS_NXADDR * ufsib->ufs_bsize, TP_BSIZE);
+		else
+			blks = howmany(extsize, TP_BSIZE);
+		tbperdb = ufsib->ufs_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(iswap64(*bp), (int)ufsib->ufs_bsize);
+				else
+					dumpblock(iswap64(*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 = extsize - UFS_NXADDR * ufsib->ufs_bsize) > 0)
+		dmpindir(dp, ino, dp->dp2.di_exti, 0, &size);
+}
+
+/*
  * Dump a map to the tape.
  */
 void

Index: src/sbin/restore/dirs.c
diff -u src/sbin/restore/dirs.c:1.51 src/sbin/restore/dirs.c:1.52
--- src/sbin/restore/dirs.c:1.51	Sun Mar  1 22:17:24 2015
+++ src/sbin/restore/dirs.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: dirs.c,v 1.51 2015/03/02 03:17:24 enami Exp $	*/
+/*	$NetBSD: dirs.c,v 1.52 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -39,7 +39,7 @@
 #if 0
 static char sccsid[] = "@(#)dirs.c	8.7 (Berkeley) 5/1/95";
 #else
-__RCSID("$NetBSD: dirs.c,v 1.51 2015/03/02 03:17:24 enami Exp $");
+__RCSID("$NetBSD: dirs.c,v 1.52 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -89,7 +89,8 @@ struct modeinfo {
 	mode_t mode;
 	uid_t uid;
 	gid_t gid;
-	int flags;
+	u_int flags;
+	int extsize;
 };
 
 /*
@@ -108,7 +109,7 @@ struct rstdirdesc {
  * Global variables for this file.
  */
 static long	seekpt;
-static FILE	*df;
+static FILE	*df, *mf;
 static RST_DIR	*dirp;
 static char	dirfile[MAXPATHLEN] = "#";	/* No file */
 static char	modefile[MAXPATHLEN] = "#";	/* No file */
@@ -123,16 +124,18 @@ struct odirect {
 	char	d_name[ODIRSIZ];
 };
 
-static struct inotab	*allocinotab(FILE *, struct context *, long);
+static struct inotab	*allocinotab(struct context *, long);
 static void		 dcvt(struct odirect *, struct direct *);
 static void		 flushent(void);
 static struct inotab	*inotablookup(ino_t);
 static RST_DIR		*opendirfile(const char *);
-static void		 putdir(char *, long);
+static void		 putdir(char *, size_t);
+static void		 putdirattrs(char *, size_t);
 static void		 putent(struct direct *);
 static void		 rst_seekdir(RST_DIR *, long, long);
 static long		 rst_telldir(RST_DIR *);
 static struct direct	*searchdir(ino_t, char *);
+static void		 fail_dirtmp(char *);
 
 /*
  *	Extract directory contents, building up a directory structure
@@ -143,18 +146,16 @@ static struct direct	*searchdir(ino_t, c
 void
 extractdirs(int genmode)
 {
-	FILE *mf;
 	int i, dfd, mfd;
 	struct inotab *itp;
 	struct direct nulldir;
 
-	mf = NULL;
 	vprintf(stdout, "Extract directories from tape\n");
-	(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d",
-	    tmpdir, (int)dumpdate);
+	(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%jd",
+	    tmpdir, (intmax_t)dumpdate);
 	if (command != 'r' && command != 'R') {
-		(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%d-XXXXXX",
-		    tmpdir, (int)dumpdate);
+		(void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%jd-XXXXXX",
+		    tmpdir, (intmax_t)dumpdate);
 		if ((dfd = mkstemp(dirfile)) == -1)
 			err(1, "cannot mkstemp temporary file %s", dirfile);
 		df = fdopen(dfd, "w");
@@ -165,11 +166,11 @@ extractdirs(int genmode)
 		err(1, "cannot open temporary file %s", dirfile);
 
 	if (genmode != 0) {
-		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
-		    tmpdir, (int)dumpdate);
+		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%jd",
+		    tmpdir, (intmax_t)dumpdate);
 		if (command != 'r' && command != 'R') {
 			(void) snprintf(modefile, sizeof(modefile),
-			    "%s/rstmode%d-XXXXXX", tmpdir, (int)dumpdate);
+			    "%s/rstmode%jd-XXXXXX", tmpdir, (intmax_t)dumpdate);
 			if ((mfd = mkstemp(modefile)) == -1)
 				err(1, "cannot mkstemp temporary file %s",
 				    modefile);
@@ -188,25 +189,24 @@ extractdirs(int genmode)
 	for (;;) {
 		curfile.name = "<directory file - name unknown>";
 		curfile.action = USING;
-		if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) {
-			(void) fclose(df);
-			dirp = opendirfile(dirfile);
-			if (dirp == NULL)
-				fprintf(stderr, "opendirfile: %s\n",
-				    strerror(errno));
-			if (mf != NULL)
-				(void) fclose(mf);
-			i = dirlookup(dot);
-			if (i == 0)
-				panic("Root directory is not on tape\n");
-			return;
-		}
-		itp = allocinotab(mf, &curfile, seekpt);
-		getfile(putdir, xtrnull);
+		if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR)
+			break;
+		itp = allocinotab(&curfile, seekpt);
+		getfile(putdir, putdirattrs, xtrnull);
 		putent(&nulldir);
 		flushent();
 		itp->t_size = seekpt - itp->t_seekpt;
 	}
+	if (fclose(df) != 0)
+		fail_dirtmp(dirfile);
+	dirp = opendirfile(dirfile);
+	if (dirp == NULL)
+		fprintf(stderr, "opendirfile: %s\n", strerror(errno));
+	if (mf != NULL && fclose(mf) != 0)
+		fail_dirtmp(modefile);
+	i = dirlookup(dot);
+	if (i == 0)
+		panic("Root directory is not on tape\n");
 }
 
 /*
@@ -272,11 +272,10 @@ treescan(const char *pname, ino_t ino, l
 	while (dp != NULL) {
 		locname[namelen] = '\0';
 		if (namelen + dp->d_namlen >= sizeof(locname)) {
-			fprintf(stderr, "%s%s: name exceeds %lu char\n",
-			    locname, dp->d_name, (u_long)(sizeof(locname) - 1));
+			fprintf(stderr, "%s%s: name exceeds %zu char\n",
+			    locname, dp->d_name, sizeof(locname) - 1);
 		} else {
-			(void) strncat(locname, dp->d_name, (int)dp->d_namlen);
-			locname[namelen + dp->d_namlen] = '\0';
+			(void)strlcat(locname, dp->d_name, sizeof(locname));
 			treescan(locname, dp->d_ino, todo);
 			rst_seekdir(dirp, bpt, itp->t_seekpt);
 		}
@@ -337,13 +336,13 @@ searchdir(ino_t inum, char *name)
  * Put the directory entries in the directory file
  */
 static void
-putdir(char *buf, long size)
+putdir(char *buf, size_t size)
 {
 	struct direct cvtbuf;
 	struct odirect *odp;
 	struct odirect *eodp;
 	struct direct *dp;
-	long loc, i;
+	size_t loc, i;
 
 	if (cvtflag) {
 		eodp = (struct odirect *)&buf[size];
@@ -417,7 +416,8 @@ putent(struct direct *dp)
 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
 		((struct direct *)(dirbuf + prev))->d_reclen =
 		    DIRBLKSIZ - prev;
-		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
+		if (fwrite(dirbuf, DIRBLKSIZ, 1, df) != 1)
+			fail_dirtmp(dirfile);
 		dirloc = 0;
 	}
 	memmove(dirbuf + dirloc, dp, (long)dp->d_reclen);
@@ -432,7 +432,8 @@ static void
 flushent(void)
 {
 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
-	(void) fwrite(dirbuf, (int)dirloc, 1, df);
+	if (fwrite(dirbuf, (int)dirloc, 1, df) != 1)
+		fail_dirtmp(dirfile);
 	seekpt = ftell(df);
 	dirloc = 0;
 }
@@ -453,6 +454,17 @@ dcvt(struct odirect *odp, struct direct 
 }
 
 /*
+ * Save extended attributes for a directory entry to a file.
+ */
+ static void
+putdirattrs(char *buf, size_t size)
+{
+
+	if (mf != NULL && fwrite(buf, size, 1, mf) != 1)
+		fail_dirtmp(modefile);
+}
+
+/*
  * 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.
@@ -582,15 +594,15 @@ opendirfile(const char *name)
 void
 setdirmodes(int flags)
 {
-	FILE *mf;
 	struct modeinfo node;
 	struct entry *ep;
-	char *cp;
+	char *cp, *buf;
+	int bufsize;
 
 	vprintf(stdout, "Set directory mode, owner, and times.\n");
 	if (command == 'r' || command == 'R')
-		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
-		    tmpdir, (int)dumpdate);
+		(void) snprintf(modefile, sizeof(modefile), "%s/rstmode%jd",
+		    tmpdir, (intmax_t)dumpdate);
 	if (modefile[0] == '#') {
 		panic("modefile not defined\n");
 		fprintf(stderr, "directory mode, owner, and times not set\n");
@@ -604,10 +616,47 @@ setdirmodes(int flags)
 		return;
 	}
 	clearerr(mf);
+	bufsize = 0;
+	buf = NULL;
 	for (;;) {
 		(void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
+		if (ferror(mf)) {
+			warn("%s: cannot read modefile.", modefile);
+			fprintf(stderr, "Mode, owner, and times not set.\n");
+			break;
+		}
 		if (feof(mf))
 			break;
+		if (node.extsize > 0) {
+			if (bufsize < node.extsize) {
+				if (bufsize > 0)
+					free(buf);
+				if ((buf = malloc(node.extsize)) != NULL) {
+					bufsize = node.extsize;
+				} else {
+					bufsize = 0;
+				}
+			}
+			if (bufsize >= node.extsize) {
+				(void) fread(buf, 1, node.extsize, mf);
+				if (ferror(mf)) {
+					warn("%s: cannot read modefile.",
+					    modefile);
+					fprintf(stderr, "Not all external ");
+					fprintf(stderr, "attributes set.\n");
+					break;
+				}
+			} else {
+				(void) fseek(mf, node.extsize, SEEK_CUR);
+				if (ferror(mf)) {
+					warn("%s: cannot seek in modefile.",
+					    modefile);
+					fprintf(stderr, "Not all directory ");
+					fprintf(stderr, "attributes set.\n");
+					break;
+				}
+			}
+		}
 		ep = lookupino(node.ino);
 		if (command == 'i' || command == 'x') {
 			if (ep == NULL)
@@ -620,27 +669,35 @@ setdirmodes(int flags)
 				continue;
 		}
 		if (ep == NULL) {
-			panic("cannot find directory inode %llu\n",
-			    (unsigned long long)node.ino);
-		} else {
-			if (!Nflag) {
-				cp = myname(ep);
-				(void) utimens(cp, node.ctimep);
-				(void) utimens(cp, node.mtimep);
-				(void) chown(cp, node.uid, node.gid);
-				(void) chmod(cp, node.mode);
-				if (Mtreefile) {
-					writemtree(cp, "dir",
-					    node.uid, node.gid, node.mode,
-					    node.flags);
-				} else 
-					(void) chflags(cp, node.flags);
+			panic("cannot find directory inode %ju\n",
+			    (uintmax_t)node.ino);
+			continue;
+		}
+		if (!Nflag) {
+			cp = myname(ep);
+			if (node.extsize > 0) {
+				if (bufsize >= node.extsize) {
+					set_extattr(-1, cp, buf, node.extsize, SXA_FILE);
+				} else {
+					fprintf(stderr, "Cannot restore %s%s\n",
+					    "extended attributes for ", cp);
+				}
 			}
-			ep->e_flags &= ~NEW;
+			(void) utimens(cp, node.ctimep);
+			(void) utimens(cp, node.mtimep);
+			(void) chown(cp, node.uid, node.gid);
+			(void) chmod(cp, node.mode);
+			if (Mtreefile) {
+				writemtree(cp, "dir",
+				    node.uid, node.gid, node.mode,
+				    node.flags);
+			} else 
+				(void) chflags(cp, node.flags);
 		}
+		ep->e_flags &= ~NEW;
 	}
-	if (ferror(mf))
-		panic("error setting directory modes\n");
+	if (bufsize > 0)
+		free(buf);
 	(void) fclose(mf);
 }
 
@@ -656,8 +713,8 @@ genliteraldir(const char *name, ino_t in
 
 	itp = inotablookup(ino);
 	if (itp == NULL)
-		panic("Cannot find directory inode %llu named %s\n",
-		    (unsigned long long)ino, name);
+		panic("Cannot find directory inode %ju named %s\n",
+		    (uintmax_t)ino, name);
 	if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
 		fprintf(stderr, "%s: ", name);
 		(void) fflush(stderr);
@@ -667,18 +724,18 @@ genliteraldir(const char *name, ino_t in
 	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
 	dp = dup(dirp->dd_fd);
 	for (i = itp->t_size; i > 0; i -= BUFSIZ) {
-		size = i < BUFSIZ ? i : BUFSIZ;
+		size = MIN(i, BUFSIZ);
 		if (read(dp, buf, (int) size) == -1) {
 			fprintf(stderr,
-			    "write error extracting inode %llu, name %s\n",
-			    (unsigned long long)curfile.ino, curfile.name);
+			    "write error extracting inode %ju, name %s\n",
+			    (uintmax_t)curfile.ino, curfile.name);
 			fprintf(stderr, "read: %s\n", strerror(errno));
 			exit(1);
 		}
 		if (!Nflag && write(ofile, buf, (int) size) == -1) {
 			fprintf(stderr,
-			    "write error extracting inode %llu, name %s\n",
-			    (unsigned long long)curfile.ino, curfile.name);
+			    "write error extracting inode %ju, name %s\n",
+			    (uintmax_t)curfile.ino, curfile.name);
 			fprintf(stderr, "write: %s\n", strerror(errno));
 			exit(1);
 		}
@@ -707,14 +764,14 @@ inodetype(ino_t ino)
  * If requested, save its pertinent mode, owner, and time info.
  */
 static struct inotab *
-allocinotab(FILE *mf, struct context *ctxp, long aseekpt)
+allocinotab(struct context *ctxp, long aseekpt)
 {
 	struct inotab	*itp;
 	struct modeinfo node;
 
 	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;
@@ -730,11 +787,13 @@ allocinotab(FILE *mf, struct context *ct
 	node.ctimep[0].tv_nsec = ctxp->atime_nsec;
 	node.ctimep[1].tv_sec = ctxp->birthtime_sec;
 	node.ctimep[1].tv_nsec = ctxp->birthtime_nsec;
+	node.extsize = ctxp->extsize;
 	node.mode = ctxp->mode;
 	node.flags = ctxp->file_flags;
 	node.uid = ctxp->uid;
 	node.gid = ctxp->gid;
-	(void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
+	if (fwrite((char *)&node, sizeof(struct modeinfo), 1, mf) != 1)
+		fail_dirtmp(modefile);
 	return (itp);
 }
 
@@ -760,8 +819,28 @@ cleanup(void)
 {
 
 	closemt();
-	if (modefile[0] != '#')
+	if (modefile[0] != '#') {
+		(void) truncate(modefile, 0);
 		(void) unlink(modefile);
-	if (dirfile[0] != '#')
+	}
+	if (dirfile[0] != '#') {
+		(void) truncate(dirfile, 0);
 		(void) unlink(dirfile);
+	}
+}
+
+/*
+ * Print out information about the failure to save directory,
+ * extended attribute, and mode information.
+ */
+static void
+fail_dirtmp(char *filename)
+{
+	warn("%s: cannot write directory database", filename);
+	if (errno == ENOSPC) {
+		fprintf(stderr, "Try making space in %s, %s\n%s\n", tmpdir,
+		    "or set environment variable TMPDIR",
+		    "to an alternate location with more disk space.");
+	}
+	exit(1);
 }

Index: src/sbin/restore/extern.h
diff -u src/sbin/restore/extern.h:1.15 src/sbin/restore/extern.h:1.16
--- src/sbin/restore/extern.h:1.15	Sat Feb 16 12:58:01 2008
+++ src/sbin/restore/extern.h	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: extern.h,v 1.15 2008/02/16 17:58:01 matt Exp $	*/
+/*	$NetBSD: extern.h,v 1.16 2021/06/19 13:56:35 christos Exp $	*/
 
 /*-
  * Copyright (c) 1992, 1993
@@ -35,7 +35,7 @@ struct entry	*addentry(const char *, ino
 long		 addfile(const char *, ino_t, int);
 int		 addwhiteout(char *);
 void		 badentry(struct entry *, const char *);
-void	 	 canon(const char *, char *);
+void	 	 canon(const char *, char *, size_t);
 void		 checkrestore(void);
 void 		 cleanup(void);
 void		 closemt(void);
@@ -57,7 +57,8 @@ void		 freeentry(struct entry *);
 void		 freename(char *);
 int	 	 genliteraldir(const char *, ino_t);
 char		*gentempname(struct entry *);
-void		 getfile(void (*)(char *, long), void (*)(char *, long));
+void		 getfile(void (*)(char *, size_t),
+    void (*)(char *, size_t), void (*)(char *, size_t));
 void		 getvol(int);
 void		 initsymtable(const char *);
 int	 	 inodetype(ino_t);
@@ -91,6 +92,12 @@ struct direct	*rst_readdir(RST_DIR *);
 void		 rst_closedir(RST_DIR *);
 void	 	 runcmdshell(void);
 char		*savename(const char *);
+enum set_extattr_mode {
+	SXA_FILE,
+	SXA_LINK,
+	SXA_FD,
+};
+void		 set_extattr(int, char *, void *, int, enum set_extattr_mode);
 void	 	 setdirmodes(int);
 void		 setinput(const char *);
 void		 setup(void);
@@ -104,7 +111,7 @@ ino_t		 upperbnd(ino_t);
 long		 verifyfile(const char *, ino_t, int);
 void		 writemtree(const char *, const char *, const uid_t,
 				const gid_t, const mode_t, const u_long);
-void		 xtrnull(char *, long);
+void		 xtrnull(char *, size_t);
 
 /* From ../dump/dumprmt.c */
 void		rmtclose(void);

Index: src/sbin/restore/interactive.c
diff -u src/sbin/restore/interactive.c:1.28 src/sbin/restore/interactive.c:1.29
--- src/sbin/restore/interactive.c:1.28	Sat Feb  2 22:19:26 2019
+++ src/sbin/restore/interactive.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: interactive.c,v 1.28 2019/02/03 03:19:26 mrg Exp $	*/
+/*	$NetBSD: interactive.c,v 1.29 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1985, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)interactive.c	8.5 (Berkeley) 5/1/95";
 #else
-__RCSID("$NetBSD: interactive.c,v 1.28 2019/02/03 03:19:26 mrg Exp $");
+__RCSID("$NetBSD: interactive.c,v 1.29 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -49,6 +49,7 @@ __RCSID("$NetBSD: interactive.c,v 1.28 2
 
 #include <setjmp.h>
 #include <glob.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -85,7 +86,7 @@ struct arglist {
 static char	*copynext(char *, char *);
 static int	 fcmp(const void *, const void *);
 static void	 formatf(struct afile *, int);
-static void	 getcmd(char *, char *, char *, struct arglist *);
+static void	 getcmd(char *, char *, char *, size_t, struct arglist *);
 struct dirent	*glob_readdir(RST_DIR *dirp);
 static int	 glob_stat(const char *, struct stat *);
 static void	 mkentry(char *, struct direct *, struct afile *);
@@ -112,7 +113,7 @@ runcmdshell(void)
 	arglist.glob.gl_closedir = (void *)rst_closedir;
 	arglist.glob.gl_lstat = glob_stat;
 	arglist.glob.gl_stat = glob_stat;
-	canon("/", curdir);
+	canon("/", curdir, sizeof(curdir));
 loop:
 	if (setjmp(reset) != 0) {
 		if (arglist.freeglob != 0) {
@@ -124,7 +125,7 @@ loop:
 		volno = 0;
 	}
 	runshell = 1;
-	getcmd(curdir, cmd, name, &arglist);
+	getcmd(curdir, cmd, name, sizeof(name), &arglist);
 	switch (cmd[0]) {
 	/*
 	 * Add elements to the extraction list.
@@ -307,11 +308,11 @@ loop:
  * eliminate any embedded ".." components.
  */
 static void
-getcmd(char *curdir, char *cmd, char *name, struct arglist *ap)
+getcmd(char *curdir, char *cmd, char *name, size_t size, struct arglist *ap)
 {
 	char *cp;
 	static char input[BUFSIZ];
-	char output[BUFSIZ];
+	char output[BUFSIZ * 2];
 	int globretval;
 #	define rawname input	/* save space by reusing input buffer */
 
@@ -331,7 +332,7 @@ getcmd(char *curdir, char *cmd, char *na
 		(void) fgets(input, BUFSIZ, terminal);
 	} while (!feof(terminal) && input[0] == '\n');
 	if (feof(terminal)) {
-		(void) strcpy(cmd, "quit");
+		(void) strlcpy(cmd, "quit", size);
 		return;
 	}
 	for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
@@ -346,7 +347,7 @@ getcmd(char *curdir, char *cmd, char *na
 	 * If no argument, use curdir as the default.
 	 */
 	if (*cp == '\0') {
-		(void) strcpy(name, curdir);
+		(void) strlcpy(name, curdir, size);
 		return;
 	}
 	nextarg = cp;
@@ -363,16 +364,14 @@ getnext:
 	 * If it is an absolute pathname, canonicalize it and return it.
 	 */
 	if (rawname[0] == '/') {
-		canon(rawname, name);
+		canon(rawname, name, size);
 	} else {
 		/*
 		 * For relative pathnames, prepend the current directory to
 		 * it then canonicalize and return it.
 		 */
-		(void) strcpy(output, curdir);
-		(void) strcat(output, "/");
-		(void) strcat(output, rawname);
-		canon(output, name);
+		snprintf(output, sizeof(output), "%s/%s", curdir, rawname);
+		canon(output, name, sizeof(name));
 	}
 	if ((globretval = glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob)) < 0) {
 		fprintf(stderr, "%s: %s: ", ap->cmd, name);
@@ -397,7 +396,7 @@ getnext:
 	ap->argcnt = ap->glob.gl_pathc;
 
 retnext:
-	strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]);
+	strlcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt], size);
 	if (--ap->argcnt == 0) {
 		ap->freeglob = 0;
 		globfree(&ap->glob);
@@ -458,7 +457,7 @@ copynext(char *input, char *output)
  * remove any imbedded "." and ".." components.
  */
 void
-canon(const char *rawname, char *canonname)
+canon(const char *rawname, char *canonname, size_t len)
 {
 	char *cp, *np;
 
@@ -468,6 +467,11 @@ canon(const char *rawname, char *canonna
 		(void) strcpy(canonname, ".");
 	else
 		(void) strcpy(canonname, "./");
+	if (strlen(canonname) + strlen(rawname) >= len) {
+		fprintf(stderr, "canonname: not enough buffer space\n");
+		exit(1);
+	}
+		
 	(void) strcat(canonname, rawname);
 	/*
 	 * Eliminate multiple and trailing '/'s
@@ -546,9 +550,7 @@ printlist(char *name, char *basename)
 		fprintf(stderr, "%s:\n", name);
 		entries = 0;
 		listp = list;
-		(void) strncpy(locname, name, MAXPATHLEN);
-		(void) strncat(locname, "/", MAXPATHLEN);
-		namelen = strlen(locname);
+		namelen = snprintf(locname, sizeof(locname), "%s/", name);
 		while ((dp = rst_readdir(dirp)) != NULL) {
 			if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
 				continue;
@@ -561,8 +563,7 @@ printlist(char *name, char *basename)
 				fprintf(stderr, "%s%s: name exceeds %d char\n",
 					locname, dp->d_name, MAXPATHLEN);
 			} else {
-				(void) strncat(locname, dp->d_name,
-				    (int)dp->d_namlen);
+				(void)strlcat(locname, dp->d_name, MAXPATHLEN);
 				mkentry(locname, dp, listp++);
 				entries++;
 			}
@@ -596,7 +597,7 @@ mkentry(char *name, struct direct *dp, s
 	fp->fnum = dp->d_ino;
 	fp->fname = savename(dp->d_name);
 	for (cp = fp->fname; *cp; cp++)
-		if (!vflag && (*cp < ' ' || *cp >= 0177))
+		if (!vflag && isprint((unsigned char)*cp))
 			*cp = '?';
 	fp->len = cp - fp->fname;
 	if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
@@ -610,7 +611,7 @@ mkentry(char *name, struct direct *dp, s
 	default:
 		fprintf(stderr, "Warning: undefined file type %d\n",
 		    dp->d_type);
-		/* fall through */
+		/* FALLTHROUGH */
 	case DT_REG:
 		fp->postfix = ' ';
 		break;
@@ -690,8 +691,8 @@ formatf(struct afile *list, int nentry)
 		for (j = 0; j < columns; j++) {
 			fp = &list[j * lines + i];
 			if (vflag) {
-				fprintf(stderr, "%*llu ", precision,
-				    (unsigned long long)fp->fnum);
+				fprintf(stderr, "%*ju ", precision,
+				    (uintmax_t)fp->fnum);
 				fp->len += precision + 1;
 			}
 			if (haveprefix) {
@@ -767,7 +768,7 @@ glob_stat(const char *name, struct stat 
 static int
 fcmp(const void *f1, const void *f2)
 {
-	return (strcmp(((const struct afile *)f1)->fname,
+	return (strcoll(((const struct afile *)f1)->fname,
 	    ((const struct afile *)f2)->fname));
 }
 

Index: src/sbin/restore/main.c
diff -u src/sbin/restore/main.c:1.36 src/sbin/restore/main.c:1.37
--- src/sbin/restore/main.c:1.36	Sun Apr  5 11:25:40 2020
+++ src/sbin/restore/main.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.36 2020/04/05 15:25:40 joerg Exp $	*/
+/*	$NetBSD: main.c,v 1.37 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19
 #if 0
 static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: main.c,v 1.36 2020/04/05 15:25:40 joerg Exp $");
+__RCSID("$NetBSD: main.c,v 1.37 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -268,7 +268,7 @@ main(int argc, char *argv[])
 		extractdirs(0);
 		initsymtable((char *)0);
 		while (argc--) {
-			canon(*argv++, name);
+			canon(*argv++, name, sizeof(name));
 			ino = dirlookup(name);
 			if (ino == 0)
 				continue;
@@ -283,7 +283,7 @@ main(int argc, char *argv[])
 		extractdirs(1);
 		initsymtable((char *)0);
 		while (argc--) {
-			canon(*argv++, name);
+			canon(*argv++, name, sizeof(name));
 			ino = dirlookup(name);
 			if (ino == 0)
 				continue;

Index: src/sbin/restore/restore.c
diff -u src/sbin/restore/restore.c:1.21 src/sbin/restore/restore.c:1.22
--- src/sbin/restore/restore.c:1.21	Tue Jan 22 04:39:13 2013
+++ src/sbin/restore/restore.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: restore.c,v 1.21 2013/01/22 09:39:13 dholland Exp $	*/
+/*	$NetBSD: restore.c,v 1.22 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)restore.c	8.3 (Berkeley) 9/13/94";
 #else
-__RCSID("$NetBSD: restore.c,v 1.21 2013/01/22 09:39:13 dholland Exp $");
+__RCSID("$NetBSD: restore.c,v 1.22 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -63,7 +63,7 @@ listfile(const char *name, ino_t ino, in
 	if (TSTINO(ino, dumpmap) == 0)
 		return (descend);
 	vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
-	fprintf(stdout, "%10llu\t%s\n", (unsigned long long)ino, name);
+	fprintf(stdout, "%10ju\t%s\n", (uintmax_t)ino, name);
 	return (descend);
 }
 
@@ -85,8 +85,8 @@ addfile(const char *name, ino_t ino, int
 	if (ino == UFS_WINO && command == 'i' && !vflag)
 		return (descend);
 	if (!mflag) {
-		(void) snprintf(buf, sizeof(buf), "./%llu",
-		    (unsigned long long)ino);
+		(void) snprintf(buf, sizeof(buf), "./%ju",
+		    (uintmax_t)ino);
 		name = buf;
 		if (type == NODE) {
 			(void) genliteraldir(name, ino);
@@ -322,7 +322,7 @@ nodeupdates(const char *name, ino_t ino,
 		} else {
 			mktempname(np);
 		}
-		/* fall through */
+		/* FALLTHROUGH */
 
 	/*
 	 * A previously non-existent file.
@@ -353,7 +353,7 @@ nodeupdates(const char *name, ino_t ino,
 	case ONTAPE|INOFND:
 		if (type == LEAF && (ip->e_flags & KEEP) == 0)
 			ip->e_flags |= EXTRACT;
-		/* fall through */
+		/* FALLTHROUGH */
 	case INOFND:
 		if ((ip->e_flags & KEEP) == 0) {
 			renameit(myname(ip), name);
@@ -461,8 +461,8 @@ nodeupdates(const char *name, ino_t ino,
 	 * next incremental tape.
 	 */
 	case 0:
-		fprintf(stderr, "%s: (inode %llu) not found on tape\n",
-			name, (unsigned long long)ino);
+		fprintf(stderr, "%s: (inode %ju) not found on tape\n",
+			name, (uintmax_t)ino);
 		break;
 
 	/*
@@ -616,8 +616,8 @@ createleaves(const char *symtabfile)
 		while (first < curfile.ino) {
 			ep = lookupino(first);
 			if (ep == NULL)
-				panic("%llu: bad first\n",
-				    (unsigned long long)first);
+				panic("%ju: bad first\n",
+				    (uintmax_t)first);
 			fprintf(stderr, "%s: not found on tape\n", myname(ep));
 			ep->e_flags &= ~(NEW|EXTRACT);
 			first = lowerbnd(first);
@@ -630,9 +630,9 @@ createleaves(const char *symtabfile)
 		 * on the next incremental tape.
 		 */
 		if (first != curfile.ino) {
-			fprintf(stderr, "expected next file %llu, got %llu\n",
-			    (unsigned long long)first,
-			    (unsigned long long)curfile.ino);
+			fprintf(stderr, "expected next file %ju, got %ju\n",
+			    (uintmax_t)first,
+			    (uintmax_t)curfile.ino);
 			skipfile();
 			goto next;
 		}
@@ -854,7 +854,7 @@ verifyfile(const char *name, ino_t ino, 
 		if (np == ep)
 			break;
 	if (np == NULL)
-		panic("missing inumber %llu\n", (unsigned long long)ino);
+		panic("missing inumber %ju\n", (uintmax_t)ino);
 	if (ep->e_type == LEAF && type != LEAF)
 		badentry(ep, "type should be LEAF");
 	return (descend);

Index: src/sbin/restore/restore.h
diff -u src/sbin/restore/restore.h:1.22 src/sbin/restore/restore.h:1.23
--- src/sbin/restore/restore.h:1.22	Sun Apr  5 11:25:40 2020
+++ src/sbin/restore/restore.h	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: restore.h,v 1.22 2020/04/05 15:25:40 joerg Exp $	*/
+/*	$NetBSD: restore.h,v 1.23 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -134,6 +134,7 @@ extern 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 */
 	const char *name;	/* name of file */
 } curfile;

Index: src/sbin/restore/symtab.c
diff -u src/sbin/restore/symtab.c:1.29 src/sbin/restore/symtab.c:1.30
--- src/sbin/restore/symtab.c:1.29	Tue Jan 22 04:39:13 2013
+++ src/sbin/restore/symtab.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: symtab.c,v 1.29 2013/01/22 09:39:13 dholland Exp $	*/
+/*	$NetBSD: symtab.c,v 1.30 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)symtab.c	8.3 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: symtab.c,v 1.29 2013/01/22 09:39:13 dholland Exp $");
+__RCSID("$NetBSD: symtab.c,v 1.30 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -102,7 +102,7 @@ addino(ino_t inum, struct entry *np)
 	struct entry **epp;
 
 	if (inum < UFS_WINO || inum >= maxino)
-		panic("addino: out of range %llu\n", (unsigned long long)inum);
+		panic("addino: out of range %ju\n", (uintmax_t)inum);
 	epp = &entry[inum % entrytblsize];
 	np->e_ino = inum;
 	np->e_next = *epp;
@@ -123,8 +123,8 @@ deleteino(ino_t inum)
 	struct entry **prev;
 
 	if (inum < UFS_WINO || inum >= maxino)
-		panic("deleteino: out of range %llu\n",
-		    (unsigned long long)inum);
+		panic("deleteino: out of range %ju\n",
+		    (uintmax_t)inum);
 	prev = &entry[inum % entrytblsize];
 	for (next = *prev; next != NULL; next = next->e_next) {
 		if (next->e_ino == inum) {
@@ -134,7 +134,7 @@ deleteino(ino_t inum)
 		}
 		prev = &next->e_next;
 	}
-	panic("deleteino: %llu not found\n", (unsigned long long)inum);
+	panic("deleteino: %ju not found\n", (uintmax_t)inum);
 }
 
 /*

Index: src/sbin/restore/tape.c
diff -u src/sbin/restore/tape.c:1.70 src/sbin/restore/tape.c:1.71
--- src/sbin/restore/tape.c:1.70	Wed Mar 10 20:13:11 2021
+++ src/sbin/restore/tape.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: tape.c,v 1.70 2021/03/11 01:13:11 msaitoh Exp $	*/
+/*	$NetBSD: tape.c,v 1.71 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -39,7 +39,7 @@
 #if 0
 static char sccsid[] = "@(#)tape.c	8.9 (Berkeley) 5/1/95";
 #else
-__RCSID("$NetBSD: tape.c,v 1.70 2021/03/11 01:13:11 msaitoh Exp $");
+__RCSID("$NetBSD: tape.c,v 1.71 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -48,7 +48,11 @@ __RCSID("$NetBSD: tape.c,v 1.70 2021/03/
 #include <sys/ioctl.h>
 #include <sys/mtio.h>
 #include <sys/stat.h>
+#include <sys/extattr.h>
+#define _ACL_PRIVATE
+#include <sys/acl.h>
 
+#include <ufs/ufs/extattr.h>
 #include <ufs/ufs/dinode.h>
 #include <protocols/dumprestore.h>
 
@@ -109,6 +113,9 @@ static union digest_context {
 
 #define	FLUSHTAPEBUF()	blkcnt = ntrec + 1
 
+const char *namespace_names[] = EXTATTR_NAMESPACE_NAMES;
+
+
 union u_ospcl {
 	char dummy[TP_BSIZE];
 	struct	s_ospcl {
@@ -141,15 +148,18 @@ static void	 accthdr(struct s_spcl *);
 static int	 checksum(int *);
 static void	 findinode(struct s_spcl *);
 static void	 findtapeblksize(void);
+static char	*setupextattr(size_t);
+static void	 xtrattr(char *, size_t);
+static void	 skiphole(void (*)(char *, size_t), volatile size_t *);
 static void	 getbitmap(char **);
 static int	 gethead(struct s_spcl *);
 static void	 readtape(char *);
 static void	 setdumpnum(void);
 static void	 terminateinput(void);
-static void	 xtrfile(char *, long);
-static void	 xtrlnkfile(char *, long);
-__dead static void	 xtrlnkskip(char *, long);
-static void	 xtrskip(char *, long);
+static void	 xtrfile(char *, size_t);
+static void	 xtrlnkfile(char *, size_t);
+__dead static void	 xtrlnkskip(char *, size_t);
+static void	 xtrskip(char *, size_t);
 static void	 swap_header(struct s_spcl *);
 static void	 swap_old_header(struct s_ospcl *);
 
@@ -620,13 +630,15 @@ int
 extractfile(char *name)
 {
 	char dbuffer[DIGEST_BUFFER_SIZE];
-	int flags;
+	u_int flags;
 	uid_t uid;
 	gid_t gid;
 	mode_t mode;
+	int extsize;
 	struct timespec mtimep[2], ctimep[2];
 	struct entry *ep;
 	int setbirth;
+	char *buf;
 
 	curfile.name = name;
 	curfile.action = USING;
@@ -643,6 +655,7 @@ extractfile(char *name)
 		ctimep[1].tv_sec = curfile.birthtime_sec;
 		ctimep[1].tv_nsec = curfile.birthtime_nsec;
 	}
+	extsize = curfile.extsize;
 	uid = curfile.uid;
 	gid = curfile.gid;
 	mode = curfile.mode;
@@ -673,7 +686,8 @@ 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);
@@ -682,6 +696,8 @@ extractfile(char *name)
 		if (uflag)
 			(void) unlink(name);
 		if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
+			if (extsize > 0)
+				set_extattr(-1, name, buf, extsize, SXA_LINK);
 			if (setbirth)
 				(void) lutimens(name, ctimep);
 			(void) lutimens(name, mtimep);
@@ -712,7 +728,13 @@ extractfile(char *name)
 			skipfile();
 			return (FAIL);
 		}
-		skipfile();
+		if (extsize == 0) {
+			skipfile();
+		} else {
+			buf = setupextattr(extsize);
+			getfile(xtrnull, xtrattr, xtrnull);
+			set_extattr(-1, name, buf, extsize, SXA_FILE);
+		}
 		if (setbirth)
 			(void) utimens(name, ctimep);
 		(void) utimens(name, mtimep);
@@ -741,7 +763,13 @@ extractfile(char *name)
 			skipfile();
 			return (FAIL);
 		}
-		skipfile();
+		if (extsize == 0) {
+			skipfile();
+		} else {
+			buf = setupextattr(extsize);
+			getfile(xtrnull, xtrattr, xtrnull);
+			set_extattr(-1, name, buf, extsize, SXA_FILE);
+		}
 		if (setbirth)
 			(void) utimens(name, ctimep);
 		(void) utimens(name, mtimep);
@@ -767,7 +795,10 @@ extractfile(char *name)
 		}
 		if (Dflag)
 			(*ddesc->dd_init)(&dcontext);
-		getfile(xtrfile, xtrskip);
+		buf = setupextattr(extsize);
+		getfile(xtrfile, xtrattr, xtrskip);
+		if (extsize > 0)
+			set_extattr(ofile, name, buf, extsize, SXA_FD);
 		if (Dflag) {
 			(*ddesc->dd_end)(&dcontext, dbuffer);
 			for (ep = lookupname(name); ep != NULL;
@@ -795,6 +826,127 @@ extractfile(char *name)
 }
 
 /*
+ * Set attributes on a file descriptor, link, or file.
+ */
+void
+set_extattr(int fd, char *name, void *buf, int size, enum set_extattr_mode mode)
+{
+	struct extattr *eap, *eaend;
+	const char *method;
+	ssize_t res;
+	int error;
+	char eaname[EXTATTR_MAXNAMELEN + 1];
+
+	vprintf(stdout, "Set attributes for %s:", name);
+	eaend = (void *)((char *)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;
+		snprintf(eaname, sizeof(eaname), "%.*s",
+		    (int)eap->ea_namelength, eap->ea_name);
+		vprintf(stdout, "\n\t%s, (%d bytes), %s",
+			namespace_names[eap->ea_namespace], eap->ea_length,
+			eaname);
+		/*
+		 * 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).
+		 */
+		switch (mode) {
+		case SXA_FD:
+			res = extattr_set_fd(fd, eap->ea_namespace,
+			    eaname, EXTATTR_CONTENT(eap),
+			    EXTATTR_CONTENT_SIZE(eap));
+			method = "extattr_set_fd";
+			break;
+		case SXA_LINK:
+			res = extattr_set_link(name, eap->ea_namespace,
+			    eaname, EXTATTR_CONTENT(eap),
+			    EXTATTR_CONTENT_SIZE(eap));
+			method = "extattr_set_link";
+			break;
+		case SXA_FILE:
+			res = extattr_set_file(name, eap->ea_namespace,
+			    eaname, EXTATTR_CONTENT(eap),
+			    EXTATTR_CONTENT_SIZE(eap));
+			method = "extattr_set_file";
+			break;
+		default:
+			abort();
+		}
+		if (res != -1) {
+			dprintf(stdout, " (set using %s)", method);
+			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(eaname, POSIX1E_ACL_ACCESS_EXTATTR_NAME) == 0) {
+			switch (mode) {
+			case SXA_FD:
+				error = acl_set_fd(fd, EXTATTR_CONTENT(eap));
+				method = "acl_set_fd";
+				break;
+			case SXA_LINK:
+				error = acl_set_link_np(name, ACL_TYPE_ACCESS,
+				    EXTATTR_CONTENT(eap));
+				method = "acl_set_link_np";
+				break;
+			case SXA_FILE:
+				error = acl_set_file(name, ACL_TYPE_ACCESS,
+				    EXTATTR_CONTENT(eap));
+				method = "acl_set_file";
+				break;
+			default:
+				abort();
+			}
+			if (error != -1) {
+				dprintf(stdout, " (set using %s)", method);
+				continue;
+			}
+		}
+		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
+		    strcmp(eaname, POSIX1E_ACL_DEFAULT_EXTATTR_NAME) == 0) {
+			switch (mode) {
+			case SXA_FD:
+				error = acl_set_fd(fd, EXTATTR_CONTENT(eap));
+				method = "acl_set_fd";
+				break;
+			case SXA_LINK:
+				error = acl_set_link_np(name, ACL_TYPE_DEFAULT,
+				    EXTATTR_CONTENT(eap));
+				method = "acl_set_link_np";
+				break;
+			case SXA_FILE:
+				error = acl_set_file(name, ACL_TYPE_DEFAULT,
+				    EXTATTR_CONTENT(eap));
+				method = "acl_set_file";
+				break;
+			default:
+				abort();
+			}
+			if (error != -1) {
+				dprintf(stdout, " (set using %s)", method);
+				continue;
+			}
+		}
+		vprintf(stdout, " (unable to set)");
+	}
+	vprintf(stdout, "\n");
+}
+
+/*
  * skip over bit maps on the tape
  */
 void
@@ -813,7 +965,22 @@ skipfile(void)
 {
 
 	curfile.action = SKIP;
-	getfile(xtrnull, xtrnull);
+	getfile(xtrnull, xtrnull, xtrnull);
+}
+
+/*
+ * Skip a hole in an output file
+ */
+static void
+skiphole(void (*skip)(char *, size_t), volatile size_t *seekpos)
+{
+	char buf[MAXBSIZE];
+	size_t s = *seekpos;
+
+	if (s > 0) {
+		(*skip)(buf, s);
+		*seekpos = 0;
+	}
 }
 
 /*
@@ -870,18 +1037,21 @@ loop:
  * to the skip function.
  */
 void
-getfile(void (*fill)(char *buf, long size),
-	void (*skip)(char *buf, long size))
+getfile(void (*datafill)(char *, size_t), void (*attrfill)(char *, size_t),
+    void (*skip)(char *, size_t))
 {
 	int i;
-	int volatile curblk;
-	quad_t volatile size;
-	static char clearedbuf[MAXBSIZE];
+	volatile off_t size;
+	volatile size_t seekpos;
+	volatile int curblk, attrsize;
+	void (*fillit)(char *, size_t);
 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
 	char junk[TP_BSIZE];
 
 	curblk = 0;
 	size = spcl.c_size;
+	seekpos = 0;
+	attrsize = spcl.c_extsize;
 
 	if (spcl.c_type == TS_END)
 		panic("ran off end of tape\n");
@@ -890,26 +1060,54 @@ getfile(void (*fill)(char *buf, long siz
 	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 (spcl.c_addr[i]) {
 			readtape(&buf[curblk++][0]);
 			if ((uint32_t)curblk == fssize / TP_BSIZE) {
-				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
+				skiphole(skip, &seekpos);
+				(*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 ?
+				skiphole(skip, &seekpos);
+				(*fillit)((char *)buf, (long)(size > TP_BSIZE ?
 				     curblk * TP_BSIZE :
 				     (curblk - 1) * TP_BSIZE + size));
 				curblk = 0;
 			}
-			(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
-				TP_BSIZE : size));
+			/*
+			 * We have a block of a hole. Don't skip it
+			 * now, because there may be next adjacent
+			 * block of the hole in the file. Postpone the
+			 * seek until next file write.
+			 */
+			seekpos += (long)MIN(TP_BSIZE, size);
 		}
 		if ((size -= TP_BSIZE) <= 0) {
+			if (size > -TP_BSIZE && curblk > 0) {
+				skiphole(skip, &seekpos);
+				(*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 (spcl.c_addr[i])
 					readtape(junk);
@@ -924,7 +1122,7 @@ loop:
 			curfile.name, blksread);
 	}
 	if (curblk > 0)
-		(*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
+		panic("getfile: lost data\n");
 	/* Skip over Linux extended attributes. */
 	if (spcl.c_type == TS_INODE && (spcl.c_flags & DR_EXTATTRIBUTES)) {
 		for (i = 0; i < spcl.c_count; i++)
@@ -936,10 +1134,54 @@ loop:
 }
 
 /*
+ * These variables are shared between the next two functions.
+ */
+static size_t extbufsize = 0;
+static char *extbuf;
+static size_t extloc;
+
+/*
+ * Allocate a buffer into which to extract extended attributes.
+ */
+static char *
+setupextattr(size_t 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 %zu bytes %s for inode %ju, name %s\n",
+	    extsize, "of extended attributes", (uintmax_t)curfile.ino,
+	    curfile.name);
+	return (NULL);
+}
+
+/*
+ * Extract the next block of extended attributes.
+ */
+static void
+xtrattr(char *buf, size_t 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
-xtrfile(char *buf, long size)
+xtrfile(char *buf, size_t size)
 {
 
 	if (Dflag)
@@ -948,8 +1190,8 @@ xtrfile(char *buf, long size)
 		return;
 	if (write(ofile, buf, (int) size) == -1) {
 		fprintf(stderr,
-		    "write error extracting inode %llu, name %s\nwrite: %s\n",
-			(unsigned long long)curfile.ino, curfile.name,
+		    "write error extracting inode %ju, name %s\nwrite: %s\n",
+			(uintmax_t)curfile.ino, curfile.name,
 			strerror(errno));
 		exit(1);
 	}
@@ -960,7 +1202,7 @@ xtrfile(char *buf, long size)
  */
 /* ARGSUSED */
 static void
-xtrskip(char *buf, long size)
+xtrskip(char *buf, size_t size)
 {
 
 	if (Dflag)
@@ -969,8 +1211,8 @@ xtrskip(char *buf, long size)
 		return;
 	if (lseek(ofile, size, SEEK_CUR) == -1) {
 		fprintf(stderr,
-		    "seek error extracting inode %llu, name %s\nlseek: %s\n",
-			(unsigned long long)curfile.ino, curfile.name,
+		    "seek error extracting inode %ju, name %s\nlseek: %s\n",
+			(uintmax_t)curfile.ino, curfile.name,
 			strerror(errno));
 		exit(1);
 	}
@@ -980,7 +1222,7 @@ xtrskip(char *buf, long size)
  * Collect the next block of a symbolic link.
  */
 static void
-xtrlnkfile(char *buf, long size)
+xtrlnkfile(char *buf, size_t size)
 {
 
 	pathlen += size;
@@ -997,7 +1239,7 @@ xtrlnkfile(char *buf, long size)
  */
 /* ARGSUSED */
 static void
-xtrlnkskip(char *buf __unused, long size __unused)
+xtrlnkskip(char *buf __unused, size_t size __unused)
 {
 
 	fprintf(stderr, "unallocated block in symbolic link %s\n",
@@ -1010,7 +1252,7 @@ xtrlnkskip(char *buf __unused, long size
  */
 /* ARGSUSED */
 void
-xtrnull(char *buf __unused, long size __unused)
+xtrnull(char *buf __unused, size_t size __unused)
 {
 
 	return;
@@ -1092,8 +1334,8 @@ getmore:
 			fprintf(stderr, "restoring %s\n", curfile.name);
 			break;
 		case SKIP:
-			fprintf(stderr, "skipping over inode %llu\n",
-			    (unsigned long long)curfile.ino);
+			fprintf(stderr, "skipping over inode %ju\n",
+			    (uintmax_t)curfile.ino);
 			break;
 		}
 		if (!yflag && !reply("continue"))
@@ -1274,6 +1516,7 @@ good:
 			buf->c_birthtime = 0;
 			buf->c_birthtimensec = 0;
 			buf->c_atimensec = buf->c_mtimensec = 0;
+			buf->c_extsize = 0;
 		}
 			
 	case TS_ADDR:
@@ -1330,12 +1573,12 @@ accthdr(struct s_spcl *header)
 		fprintf(stderr, "Used inodes map header");
 		break;
 	case TS_INODE:
-		fprintf(stderr, "File header, ino %llu",
-		    (unsigned long long)previno);
+		fprintf(stderr, "File header, ino %ju",
+		    (uintmax_t)previno);
 		break;
 	case TS_ADDR:
-		fprintf(stderr, "File continuation header, ino %llu",
-		    (unsigned long long)previno);
+		fprintf(stderr, "File continuation header, ino %ju",
+		    (uintmax_t)previno);
 		break;
 	case TS_END:
 		fprintf(stderr, "End of tape header");
@@ -1417,6 +1660,7 @@ skip:
 			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;
@@ -1468,8 +1712,8 @@ checksum(int *buf)
 	}
 			
 	if (i != CHECKSUM) {
-		fprintf(stderr, "Checksum error %o, inode %llu file %s\n", i,
-		    (unsigned long long)curfile.ino, curfile.name);
+		fprintf(stderr, "Checksum error %o, inode %ju file %s\n", i,
+		    (uintmax_t)curfile.ino, curfile.name);
 		return(FAIL);
 	}
 	return(GOOD);
@@ -1502,6 +1746,7 @@ swap_header(struct s_spcl *s)
 	s->c_checksum = bswap32(s->c_checksum);
 
 	s->c_mode = bswap16(s->c_mode);
+	s->c_extsize = bswap64(s->c_extsize);
 	s->c_size = bswap64(s->c_size);
 	s->c_old_atime = bswap32(s->c_old_atime);
 	s->c_atimensec = bswap32(s->c_atimensec);

Index: src/sbin/restore/utilities.c
diff -u src/sbin/restore/utilities.c:1.23 src/sbin/restore/utilities.c:1.24
--- src/sbin/restore/utilities.c:1.23	Tue Jan 22 04:39:13 2013
+++ src/sbin/restore/utilities.c	Sat Jun 19 09:56:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: utilities.c,v 1.23 2013/01/22 09:39:13 dholland Exp $	*/
+/*	$NetBSD: utilities.c,v 1.24 2021/06/19 13:56:35 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)utilities.c	8.5 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: utilities.c,v 1.23 2013/01/22 09:39:13 dholland Exp $");
+__RCSID("$NetBSD: utilities.c,v 1.24 2021/06/19 13:56:35 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -115,8 +115,8 @@ gentempname(struct entry *ep)
 		i++;
 	if (np == NULL)
 		badentry(ep, "not on ino list");
-	(void)snprintf(name, sizeof(name), "%s%ld%llu", TMPHDR, (long) i,
-	    (unsigned long long)ep->e_ino);
+	(void)snprintf(name, sizeof(name), "%s%ld%ju", TMPHDR, (long) i,
+	    (uintmax_t)ep->e_ino);
 	return (name);
 }
 

Index: src/sys/sys/extattr.h
diff -u src/sys/sys/extattr.h:1.10 src/sys/sys/extattr.h:1.11
--- src/sys/sys/extattr.h:1.10	Sat May 16 14:31:53 2020
+++ src/sys/sys/extattr.h	Sat Jun 19 09:56:34 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: extattr.h,v 1.10 2020/05/16 18:31:53 christos Exp $	*/
+/*	$NetBSD: extattr.h,v 1.11 2021/06/19 13:56:34 christos Exp $	*/
 
 /*-
  * Copyright (c) 1999-2001 Robert N. M. Watson
@@ -41,11 +41,27 @@
 
 #include <sys/types.h>
 
+#define	EXTATTR_NAMESPACE_EMPTY		0x00000000
+#define	EXTATTR_NAMESPACE_EMPTY_STRING	"empty"
 #define	EXTATTR_NAMESPACE_USER		0x00000001
 #define	EXTATTR_NAMESPACE_USER_STRING	"user"
 #define	EXTATTR_NAMESPACE_SYSTEM	0x00000002
 #define	EXTATTR_NAMESPACE_SYSTEM_STRING	"system"
 
+/*    
+ * The following macro is designed to initialize an array that maps
+ * extended-attribute namespace values to their names, e.g.:
+ * 
+ * char *extattr_namespace_names[] = EXTATTR_NAMESPACE_NAMES;
+ */
+#define	EXTATTR_NAMESPACE_NAMES { \
+    EXTATTR_NAMESPACE_EMPTY_STRING, \
+    EXTATTR_NAMESPACE_USER_STRING, \
+    EXTATTR_NAMESPACE_SYSTEM_STRING, \
+}
+
+#define	EXTATTR_MAXNAMELEN	KERNEL_NAME_MAX
+
 /* for sys_extattrctl */
 #define EXTATTR_CMD_START		0x00000001
 #define EXTATTR_CMD_STOP		0x00000002
@@ -57,7 +73,6 @@
 /* VOP_LISTEXTATTR flags */
 #define EXTATTR_LIST_LENPREFIX	1	/* names with length prefix */
 
-#define	EXTATTR_MAXNAMELEN	KERNEL_NAME_MAX
 struct lwp;
 struct vnode;
 int	extattr_check_cred(struct vnode *, int, kauth_cred_t, int);

Reply via email to