diff --git a/include/protocols/dumprestore.h b/include/protocols/dumprestore.h index 5fe6666b1c60..03fc93dcd545 100644 --- a/include/protocols/dumprestore.h +++ b/include/protocols/dumprestore.h @@ -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 diff --git a/sbin/dump/dump.h b/sbin/dump/dump.h index b0500d745ec3..b937e61308f1 100644 --- a/sbin/dump/dump.h +++ b/sbin/dump/dump.h @@ -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); diff --git a/sbin/dump/tape.c b/sbin/dump/tape.c index 34e48c85b96d..458435523af0 100644 --- a/sbin/dump/tape.c +++ b/sbin/dump/tape.c @@ -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 __unused) */ (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 __unused) 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 __unused) #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 __unused) } /* - * 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) diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c index 558a57587486..a92b86dac9eb 100644 --- a/sbin/dump/traverse.c +++ b/sbin/dump/traverse.c @@ -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/03/01 16:42:11 christos Exp $"); #include #include +#include #include #include #include @@ -58,8 +59,10 @@ __RCSID("$NetBSD: traverse.c,v 1.52 2019/03/01 16:42:11 christos Exp $"); #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, long size, off_t filesize, 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_level, off_t *size) 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_level, off_t *size) 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_t 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,9 +727,129 @@ blksout64(int64_t *blkp, int frags, ino_t 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. */ diff --git a/sbin/restore/dirs.c b/sbin/restore/dirs.c index fd02512b5811..2a471ed7a4eb 100644 --- a/sbin/restore/dirs.c +++ b/sbin/restore/dirs.c @@ -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, char *); 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 = ""; 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, long (*todo)(const char *, ino_t, int)) 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; } @@ -452,6 +453,17 @@ dcvt(struct odirect *odp, struct direct *ndp) ndp->d_reclen = UFS_DIRSIZ(0, ndp, 0); } +/* + * 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. @@ -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); - } - ep->e_flags &= ~NEW; + 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); + } + } + (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 ino) 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 ino) 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 *ctxp, long aseekpt) 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); } diff --git a/sbin/restore/extern.h b/sbin/restore/extern.h index 3a69394cb26a..9ac4c34d94a3 100644 --- a/sbin/restore/extern.h +++ b/sbin/restore/extern.h @@ -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_t, int); 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); diff --git a/sbin/restore/interactive.c b/sbin/restore/interactive.c index 388612d470c6..33ababbfb030 100644 --- a/sbin/restore/interactive.c +++ b/sbin/restore/interactive.c @@ -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 2019/02/03 03:19:26 mrg Exp $"); #include #include +#include #include #include #include @@ -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 *name, struct arglist *ap) (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 *name, struct arglist *ap) * 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 *canonname) (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, struct afile *fp) 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, struct afile *fp) 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 *stp) 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)); } diff --git a/sbin/restore/main.c b/sbin/restore/main.c index c124a6e6f40c..3832c070d713 100644 --- a/sbin/restore/main.c +++ b/sbin/restore/main.c @@ -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, 1993\ #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; diff --git a/sbin/restore/restore.c b/sbin/restore/restore.c index 359b39d48d8b..0fc776bde50d 100644 --- a/sbin/restore/restore.c +++ b/sbin/restore/restore.c @@ -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, int type) 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 type) 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, int type) } else { mktempname(np); } - /* fall through */ + /* FALLTHROUGH */ /* * A previously non-existent file. @@ -353,7 +353,7 @@ nodeupdates(const char *name, ino_t ino, int type) 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, int type) * 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, int type) 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); diff --git a/sbin/restore/restore.h b/sbin/restore/restore.h index 4b5f58b683d2..fba3b02d282b 100644 --- a/sbin/restore/restore.h +++ b/sbin/restore/restore.h @@ -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; diff --git a/sbin/restore/symtab.c b/sbin/restore/symtab.c index 3e42fb119963..e75d9dbf5abe 100644 --- a/sbin/restore/symtab.c +++ b/sbin/restore/symtab.c @@ -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); } /* diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c index fe869b0fbcf1..c03adb2a5b86 100644 --- a/sbin/restore/tape.c +++ b/sbin/restore/tape.c @@ -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/11 01:13:11 msaitoh Exp $"); #include #include #include +#include +#define _ACL_PRIVATE +#include +#include #include #include @@ -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; @@ -794,6 +825,127 @@ extractfile(char *name) /* NOTREACHED */ } +/* + * 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 */ @@ -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 size), 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++) @@ -935,11 +1133,55 @@ loop: gettingfile = 0; } +/* + * 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 __unused) */ /* 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); diff --git a/sbin/restore/utilities.c b/sbin/restore/utilities.c index 857761394b87..4bae752c864c 100644 --- a/sbin/restore/utilities.c +++ b/sbin/restore/utilities.c @@ -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); } diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h index 18b3d387d6be..527415dd8388 100644 --- a/sys/sys/extattr.h +++ b/sys/sys/extattr.h @@ -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 +#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);