1*da5362d5Sguenther /* $OpenBSD: dirs.c,v 1.43 2024/01/09 03:16:00 guenther Exp $ */
2a916033eSmillert /* $NetBSD: dirs.c,v 1.26 1997/07/01 05:37:49 lukem Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1983, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt * (c) UNIX System Laboratories, Inc.
8df930be7Sderaadt * All or some portions of this file are derived from material licensed
9df930be7Sderaadt * to the University of California by American Telephone and Telegraph
10df930be7Sderaadt * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11df930be7Sderaadt * the permission of UNIX System Laboratories, Inc.
12df930be7Sderaadt *
13df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
14df930be7Sderaadt * modification, are permitted provided that the following conditions
15df930be7Sderaadt * are met:
16df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
17df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
18df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
19df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
20df930be7Sderaadt * documentation and/or other materials provided with the distribution.
211ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
22df930be7Sderaadt * may be used to endorse or promote products derived from this software
23df930be7Sderaadt * without specific prior written permission.
24df930be7Sderaadt *
25df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35df930be7Sderaadt * SUCH DAMAGE.
36df930be7Sderaadt */
37df930be7Sderaadt
38df930be7Sderaadt #include <sys/stat.h>
39df930be7Sderaadt #include <sys/time.h>
40df930be7Sderaadt
41df930be7Sderaadt #include <ufs/ffs/fs.h>
42df930be7Sderaadt #include <ufs/ufs/dinode.h>
43df930be7Sderaadt #include <ufs/ufs/dir.h>
44df930be7Sderaadt #include <protocols/dumprestore.h>
45df930be7Sderaadt
46be9b7050Sguenther #include <endian.h>
47a916033eSmillert #include <err.h>
48ffb4dd05Sguenther #include <errno.h>
4901a83688Smillert #include <fcntl.h>
50ad417092Smillert #include <paths.h>
51df930be7Sderaadt #include <stdio.h>
52df930be7Sderaadt #include <stdlib.h>
53df930be7Sderaadt #include <string.h>
54df930be7Sderaadt #include <unistd.h>
55b9fc9a72Sderaadt #include <limits.h>
56df930be7Sderaadt
57df930be7Sderaadt #include "restore.h"
58df930be7Sderaadt #include "extern.h"
59df930be7Sderaadt
60df930be7Sderaadt /*
61df930be7Sderaadt * Symbol table of directories read from tape.
62df930be7Sderaadt */
63df930be7Sderaadt #define HASHSIZE 1000
64df930be7Sderaadt #define INOHASH(val) (val % HASHSIZE)
65df930be7Sderaadt struct inotab {
66df930be7Sderaadt struct inotab *t_next;
67df930be7Sderaadt ino_t t_ino;
68d739c122Sderaadt int32_t t_seekpt;
69d739c122Sderaadt int32_t t_size;
70df930be7Sderaadt };
71df930be7Sderaadt static struct inotab *inotab[HASHSIZE];
72df930be7Sderaadt
73df930be7Sderaadt /*
74df930be7Sderaadt * Information retained about directories.
75df930be7Sderaadt */
76df930be7Sderaadt struct modeinfo {
77df930be7Sderaadt ino_t ino;
78a740969bSguenther struct timespec ctimep[2];
79a740969bSguenther struct timespec mtimep[2];
80df930be7Sderaadt mode_t mode;
81df930be7Sderaadt uid_t uid;
82df930be7Sderaadt gid_t gid;
83230b6680Smillert u_int flags;
84df930be7Sderaadt };
85df930be7Sderaadt
86df930be7Sderaadt /*
87df930be7Sderaadt * Definitions for library routines operating on directories.
88df930be7Sderaadt */
89df930be7Sderaadt #undef DIRBLKSIZ
90df930be7Sderaadt #define DIRBLKSIZ 1024
91df930be7Sderaadt struct rstdirdesc {
92df930be7Sderaadt int dd_fd;
93d739c122Sderaadt int32_t dd_loc;
94d739c122Sderaadt int32_t dd_size;
95df930be7Sderaadt char dd_buf[DIRBLKSIZ];
96df930be7Sderaadt };
97df930be7Sderaadt
98df930be7Sderaadt /*
99df930be7Sderaadt * Global variables for this file.
100df930be7Sderaadt */
101df930be7Sderaadt static long seekpt;
102df930be7Sderaadt static FILE *df, *mf;
103df930be7Sderaadt static RST_DIR *dirp;
104b9fc9a72Sderaadt static char dirfile[PATH_MAX] = "#"; /* No file */
105b9fc9a72Sderaadt static char modefile[PATH_MAX] = "#"; /* No file */
106df930be7Sderaadt static char dot[2] = "."; /* So it can be modified */
107df930be7Sderaadt
108df930be7Sderaadt /*
109df930be7Sderaadt * Format of old style directories.
110df930be7Sderaadt */
111df930be7Sderaadt #define ODIRSIZ 14
112df930be7Sderaadt struct odirect {
113df930be7Sderaadt u_short d_ino;
114df930be7Sderaadt char d_name[ODIRSIZ];
115df930be7Sderaadt };
116df930be7Sderaadt
1170155e653Smillert static struct inotab *allocinotab(FILE *, struct context *, long);
118c72b5b24Smillert static void dcvt(struct odirect *, struct direct *);
119c72b5b24Smillert static void flushent(void);
120c72b5b24Smillert static struct inotab *inotablookup(ino_t);
121c72b5b24Smillert static RST_DIR *opendirfile(const char *);
1222d2a7b95Shenning static void putdir(char *, size_t);
123c72b5b24Smillert static void putent(struct direct *);
124c72b5b24Smillert static void rst_seekdir(RST_DIR *, long, long);
125c72b5b24Smillert static long rst_telldir(RST_DIR *);
126c72b5b24Smillert static struct direct *searchdir(ino_t, char *);
127df930be7Sderaadt
128df930be7Sderaadt /*
129df930be7Sderaadt * Extract directory contents, building up a directory structure
130df930be7Sderaadt * on disk for extraction by name.
131df930be7Sderaadt * If genmode is requested, save mode, owner, and times for all
132df930be7Sderaadt * directories on the tape.
133df930be7Sderaadt */
134df930be7Sderaadt void
extractdirs(int genmode)1354e95fccfSderaadt extractdirs(int genmode)
136df930be7Sderaadt {
137e073c79dSmpech int i;
138df930be7Sderaadt struct inotab *itp;
139df930be7Sderaadt struct direct nulldir;
1405d92347aSderaadt int fd;
141df930be7Sderaadt
142a916033eSmillert Vprintf(stdout, "Extract directories from tape\n");
143520eb379Sotto (void)snprintf(dirfile, sizeof(dirfile), "%s/rstdir%lld", tmpdir,
144520eb379Sotto (long long)dumpdate);
145f79cb2fdSderaadt if (command != 'r' && command != 'R') {
146f4dedfb2Savsm strlcat(dirfile, "-XXXXXXXXXX", sizeof(dirfile));
1479f6f356fSderaadt fd = mkstemp(dirfile);
1489f6f356fSderaadt } else
1499f6f356fSderaadt fd = open(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666);
1509f6f356fSderaadt if (fd == -1 || (df = fdopen(fd, "w")) == NULL) {
151ffb4dd05Sguenther int saved_errno = errno;
1525d92347aSderaadt if (fd != -1)
1535d92347aSderaadt close(fd);
154ffb4dd05Sguenther errc(1, saved_errno,
155ffb4dd05Sguenther "cannot create directory temporary %s", dirfile);
156df930be7Sderaadt }
157df930be7Sderaadt if (genmode != 0) {
158520eb379Sotto (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld",
159520eb379Sotto tmpdir, (long long)dumpdate);
160f79cb2fdSderaadt if (command != 'r' && command != 'R') {
161f4dedfb2Savsm strlcat(modefile, "-XXXXXXXXXX", sizeof(modefile));
1629f6f356fSderaadt fd = mkstemp(modefile);
1639f6f356fSderaadt } else
1649f6f356fSderaadt fd = open(modefile, O_RDWR|O_CREAT|O_EXCL, 0666);
1659f6f356fSderaadt if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) {
166ffb4dd05Sguenther int saved_errno = errno;
1675d92347aSderaadt if (fd != -1)
1685d92347aSderaadt close(fd);
169ffb4dd05Sguenther errc(1, saved_errno,
170ffb4dd05Sguenther "cannot create modefile %s", modefile);
171df930be7Sderaadt }
172df930be7Sderaadt }
173df930be7Sderaadt nulldir.d_ino = 0;
174df930be7Sderaadt nulldir.d_type = DT_DIR;
175df930be7Sderaadt nulldir.d_namlen = 1;
176a916033eSmillert nulldir.d_name[0] = '/';
177a916033eSmillert nulldir.d_name[1] = '\0';
178*da5362d5Sguenther nulldir.d_reclen = DIRSIZ(&nulldir);
179df930be7Sderaadt for (;;) {
180df930be7Sderaadt curfile.name = "<directory file - name unknown>";
181df930be7Sderaadt curfile.action = USING;
1820155e653Smillert if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) {
183df930be7Sderaadt (void)fclose(df);
184df930be7Sderaadt dirp = opendirfile(dirfile);
185df930be7Sderaadt if (dirp == NULL)
186a916033eSmillert warn("opendirfile");
187df930be7Sderaadt if (mf != NULL)
188df930be7Sderaadt (void)fclose(mf);
189df930be7Sderaadt i = dirlookup(dot);
190df930be7Sderaadt if (i == 0)
191df930be7Sderaadt panic("Root directory is not on tape\n");
192df930be7Sderaadt return;
193df930be7Sderaadt }
1940155e653Smillert itp = allocinotab(mf, &curfile, seekpt);
195df930be7Sderaadt getfile(putdir, xtrnull);
196df930be7Sderaadt putent(&nulldir);
197df930be7Sderaadt flushent();
198df930be7Sderaadt itp->t_size = seekpt - itp->t_seekpt;
199df930be7Sderaadt }
200df930be7Sderaadt }
201df930be7Sderaadt
202df930be7Sderaadt /*
203df930be7Sderaadt * skip over all the directories on the tape
204df930be7Sderaadt */
205df930be7Sderaadt void
skipdirs(void)2064e95fccfSderaadt skipdirs(void)
207df930be7Sderaadt {
208df930be7Sderaadt
2090155e653Smillert while (curfile.ino && (curfile.mode & IFMT) == IFDIR) {
210df930be7Sderaadt skipfile();
211df930be7Sderaadt }
212df930be7Sderaadt }
213df930be7Sderaadt
214df930be7Sderaadt /*
215df930be7Sderaadt * Recursively find names and inumbers of all files in subtree
216df930be7Sderaadt * pname and pass them off to be processed.
217df930be7Sderaadt */
218df930be7Sderaadt void
treescan(char * pname,ino_t ino,long (* todo)(char *,ino_t,int))2194e95fccfSderaadt treescan(char *pname, ino_t ino, long (*todo)(char *, ino_t, int))
220df930be7Sderaadt {
221e073c79dSmpech struct inotab *itp;
222e073c79dSmpech struct direct *dp;
223e88add51Smillert size_t namelen;
224df930be7Sderaadt long bpt;
225b9fc9a72Sderaadt char locname[PATH_MAX + 1];
226df930be7Sderaadt
227df930be7Sderaadt itp = inotablookup(ino);
228df930be7Sderaadt if (itp == NULL) {
229df930be7Sderaadt /*
230df930be7Sderaadt * Pname is name of a simple file or an unchanged directory.
231df930be7Sderaadt */
232df930be7Sderaadt (void)(*todo)(pname, ino, LEAF);
233df930be7Sderaadt return;
234df930be7Sderaadt }
235df930be7Sderaadt /*
236df930be7Sderaadt * Pname is a dumped directory name.
237df930be7Sderaadt */
238df930be7Sderaadt if ((*todo)(pname, ino, NODE) == FAIL)
239df930be7Sderaadt return;
240df930be7Sderaadt /*
241df930be7Sderaadt * begin search through the directory
242df930be7Sderaadt * skipping over "." and ".."
243df930be7Sderaadt */
244e88add51Smillert namelen = strlcpy(locname, pname, sizeof(locname));
245e88add51Smillert if (namelen >= sizeof(locname) - 1)
246e88add51Smillert namelen = sizeof(locname) - 2;
247e88add51Smillert locname[namelen++] = '/';
248e88add51Smillert locname[namelen] = '\0';
249df930be7Sderaadt rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
250df930be7Sderaadt dp = rst_readdir(dirp); /* "." */
251df930be7Sderaadt if (dp != NULL && strcmp(dp->d_name, ".") == 0)
252df930be7Sderaadt dp = rst_readdir(dirp); /* ".." */
253df930be7Sderaadt else
254df930be7Sderaadt fprintf(stderr, "Warning: `.' missing from directory %s\n",
255df930be7Sderaadt pname);
256df930be7Sderaadt if (dp != NULL && strcmp(dp->d_name, "..") == 0)
257df930be7Sderaadt dp = rst_readdir(dirp); /* first real entry */
258df930be7Sderaadt else
259df930be7Sderaadt fprintf(stderr, "Warning: `..' missing from directory %s\n",
260df930be7Sderaadt pname);
261df930be7Sderaadt bpt = rst_telldir(dirp);
262df930be7Sderaadt /*
263df930be7Sderaadt * a zero inode signals end of directory
264df930be7Sderaadt */
265df930be7Sderaadt while (dp != NULL) {
26628b0d5b1Smillert locname[namelen] = '\0';
26728b0d5b1Smillert if (namelen + dp->d_namlen >= sizeof(locname)) {
2680155e653Smillert fprintf(stderr, "%s%s: name exceeds %zd char\n",
26979f5c397Smillert locname, dp->d_name, sizeof(locname) - 1);
270df930be7Sderaadt } else {
271f4dedfb2Savsm (void)strlcat(locname, dp->d_name, sizeof(locname));
272df930be7Sderaadt treescan(locname, dp->d_ino, todo);
273df930be7Sderaadt rst_seekdir(dirp, bpt, itp->t_seekpt);
274df930be7Sderaadt }
275df930be7Sderaadt dp = rst_readdir(dirp);
276df930be7Sderaadt bpt = rst_telldir(dirp);
277df930be7Sderaadt }
278df930be7Sderaadt }
279df930be7Sderaadt
280df930be7Sderaadt /*
281df930be7Sderaadt * Lookup a pathname which is always assumed to start from the ROOTINO.
282df930be7Sderaadt */
283df930be7Sderaadt struct direct *
pathsearch(const char * pathname)2844e95fccfSderaadt pathsearch(const char *pathname)
285df930be7Sderaadt {
286df930be7Sderaadt ino_t ino;
287df930be7Sderaadt struct direct *dp;
288b9fc9a72Sderaadt char *path, *name, buffer[PATH_MAX];
289df930be7Sderaadt
29015f407e7Sderaadt strlcpy(buffer, pathname, sizeof buffer);
291df930be7Sderaadt path = buffer;
292df930be7Sderaadt ino = ROOTINO;
293df930be7Sderaadt while (*path == '/')
294df930be7Sderaadt path++;
295df930be7Sderaadt dp = NULL;
296a916033eSmillert while ((name = strsep(&path, "/")) != NULL && *name != '\0') {
297df930be7Sderaadt if ((dp = searchdir(ino, name)) == NULL)
298df930be7Sderaadt return (NULL);
299df930be7Sderaadt ino = dp->d_ino;
300df930be7Sderaadt }
301df930be7Sderaadt return (dp);
302df930be7Sderaadt }
303df930be7Sderaadt
304df930be7Sderaadt /*
305df930be7Sderaadt * Lookup the requested name in directory inum.
306df930be7Sderaadt * Return its inode number if found, zero if it does not exist.
307df930be7Sderaadt */
308df930be7Sderaadt static struct direct *
searchdir(ino_t inum,char * name)3094e95fccfSderaadt searchdir(ino_t inum, char *name)
310df930be7Sderaadt {
311e073c79dSmpech struct direct *dp;
312e073c79dSmpech struct inotab *itp;
313df930be7Sderaadt int len;
314df930be7Sderaadt
315df930be7Sderaadt itp = inotablookup(inum);
316df930be7Sderaadt if (itp == NULL)
317df930be7Sderaadt return (NULL);
318df930be7Sderaadt rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
319df930be7Sderaadt len = strlen(name);
320df930be7Sderaadt do {
321df930be7Sderaadt dp = rst_readdir(dirp);
322df930be7Sderaadt if (dp == NULL)
323df930be7Sderaadt return (NULL);
324df930be7Sderaadt } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
325df930be7Sderaadt return (dp);
326df930be7Sderaadt }
327df930be7Sderaadt
328df930be7Sderaadt /*
329df930be7Sderaadt * Put the directory entries in the directory file
330df930be7Sderaadt */
331df930be7Sderaadt static void
putdir(char * buf,size_t size)3324e95fccfSderaadt putdir(char *buf, size_t size)
333df930be7Sderaadt {
334df930be7Sderaadt struct direct cvtbuf;
335e073c79dSmpech struct odirect *odp;
336df930be7Sderaadt struct odirect *eodp;
337e073c79dSmpech struct direct *dp;
3382d2a7b95Shenning size_t loc, i;
339df930be7Sderaadt
340df930be7Sderaadt if (cvtflag) {
341df930be7Sderaadt eodp = (struct odirect *)&buf[size];
342df930be7Sderaadt for (odp = (struct odirect *)buf; odp < eodp; odp++)
343df930be7Sderaadt if (odp->d_ino != 0) {
344df930be7Sderaadt dcvt(odp, &cvtbuf);
345df930be7Sderaadt putent(&cvtbuf);
346df930be7Sderaadt }
347df930be7Sderaadt } else {
348df930be7Sderaadt for (loc = 0; loc < size; ) {
349df930be7Sderaadt dp = (struct direct *)(buf + loc);
350de5f1e61Smillert if (Bcvt) {
351de5f1e61Smillert dp->d_ino = swap32(dp->d_ino);
352de5f1e61Smillert dp->d_reclen = swap16(dp->d_reclen);
353de5f1e61Smillert }
354df930be7Sderaadt if (oldinofmt && dp->d_ino != 0) {
355df930be7Sderaadt # if BYTE_ORDER == BIG_ENDIAN
356df930be7Sderaadt if (Bcvt)
357df930be7Sderaadt dp->d_namlen = dp->d_type;
358df930be7Sderaadt # else
359df930be7Sderaadt if (!Bcvt)
360df930be7Sderaadt dp->d_namlen = dp->d_type;
361df930be7Sderaadt # endif
362df930be7Sderaadt dp->d_type = DT_UNKNOWN;
363df930be7Sderaadt }
364df930be7Sderaadt i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
365df930be7Sderaadt if ((dp->d_reclen & 0x3) != 0 ||
366df930be7Sderaadt dp->d_reclen > i ||
367*da5362d5Sguenther dp->d_reclen < DIRSIZ(dp) ||
368df930be7Sderaadt dp->d_namlen > NAME_MAX) {
369a916033eSmillert Vprintf(stdout, "Mangled directory: ");
370df930be7Sderaadt if ((dp->d_reclen & 0x3) != 0)
371a916033eSmillert Vprintf(stdout,
372df930be7Sderaadt "reclen not multiple of 4 ");
373*da5362d5Sguenther if (dp->d_reclen < DIRSIZ(dp))
374a916033eSmillert Vprintf(stdout,
3752d2a7b95Shenning "reclen less than DIRSIZ (%u < %u) ",
3762d2a7b95Shenning (unsigned)dp->d_reclen,
377*da5362d5Sguenther (unsigned)DIRSIZ(dp));
378df930be7Sderaadt if (dp->d_namlen > NAME_MAX)
379a916033eSmillert Vprintf(stdout,
3802d2a7b95Shenning "reclen name too big (%u > %u) ",
3812d2a7b95Shenning (unsigned)dp->d_namlen, NAME_MAX);
382a916033eSmillert Vprintf(stdout, "\n");
383df930be7Sderaadt loc += i;
384df930be7Sderaadt continue;
385df930be7Sderaadt }
386df930be7Sderaadt loc += dp->d_reclen;
387df930be7Sderaadt if (dp->d_ino != 0) {
388df930be7Sderaadt putent(dp);
389df930be7Sderaadt }
390df930be7Sderaadt }
391df930be7Sderaadt }
392df930be7Sderaadt }
393df930be7Sderaadt
394df930be7Sderaadt /*
395df930be7Sderaadt * These variables are "local" to the following two functions.
396df930be7Sderaadt */
397df930be7Sderaadt char dirbuf[DIRBLKSIZ];
398df930be7Sderaadt long dirloc = 0;
399df930be7Sderaadt long prev = 0;
400df930be7Sderaadt
401df930be7Sderaadt /*
402df930be7Sderaadt * add a new directory entry to a file.
403df930be7Sderaadt */
404df930be7Sderaadt static void
putent(struct direct * dp)4054e95fccfSderaadt putent(struct direct *dp)
406df930be7Sderaadt {
407*da5362d5Sguenther dp->d_reclen = DIRSIZ(dp);
408df930be7Sderaadt if (dirloc + dp->d_reclen > DIRBLKSIZ) {
409df930be7Sderaadt ((struct direct *)(dirbuf + prev))->d_reclen =
410df930be7Sderaadt DIRBLKSIZ - prev;
411df930be7Sderaadt (void)fwrite(dirbuf, 1, DIRBLKSIZ, df);
412df930be7Sderaadt dirloc = 0;
413df930be7Sderaadt }
41434278641Stedu memcpy(dirbuf + dirloc, dp, dp->d_reclen);
415df930be7Sderaadt prev = dirloc;
416df930be7Sderaadt dirloc += dp->d_reclen;
417df930be7Sderaadt }
418df930be7Sderaadt
419df930be7Sderaadt /*
420df930be7Sderaadt * flush out a directory that is finished.
421df930be7Sderaadt */
422df930be7Sderaadt static void
flushent(void)4234e95fccfSderaadt flushent(void)
424df930be7Sderaadt {
425df930be7Sderaadt ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
4263085c8d2Sguenther (void)fwrite(dirbuf, dirloc, 1, df);
427df930be7Sderaadt seekpt = ftell(df);
428df930be7Sderaadt dirloc = 0;
429df930be7Sderaadt }
430df930be7Sderaadt
431df930be7Sderaadt static void
dcvt(struct odirect * odp,struct direct * ndp)4324e95fccfSderaadt dcvt(struct odirect *odp, struct direct *ndp)
433df930be7Sderaadt {
434df930be7Sderaadt
43534278641Stedu memset(ndp, 0, sizeof *ndp);
436de5f1e61Smillert if (Bcvt)
437de5f1e61Smillert ndp->d_ino = swap16(odp->d_ino);
438de5f1e61Smillert else
439df930be7Sderaadt ndp->d_ino = odp->d_ino;
440df930be7Sderaadt ndp->d_type = DT_UNKNOWN;
441df930be7Sderaadt (void)strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
442df930be7Sderaadt ndp->d_namlen = strlen(ndp->d_name);
443*da5362d5Sguenther ndp->d_reclen = DIRSIZ(ndp);
444df930be7Sderaadt }
445df930be7Sderaadt
446df930be7Sderaadt /*
447df930be7Sderaadt * Seek to an entry in a directory.
448df930be7Sderaadt * Only values returned by rst_telldir should be passed to rst_seekdir.
449df930be7Sderaadt * This routine handles many directories in a single file.
450df930be7Sderaadt * It takes the base of the directory in the file, plus
451df930be7Sderaadt * the desired seek offset into it.
452df930be7Sderaadt */
453df930be7Sderaadt static void
rst_seekdir(RST_DIR * dirp,long loc,long base)4544e95fccfSderaadt rst_seekdir(RST_DIR *dirp, long loc, long base)
455df930be7Sderaadt {
456df930be7Sderaadt
457df930be7Sderaadt if (loc == rst_telldir(dirp))
458df930be7Sderaadt return;
459df930be7Sderaadt loc -= base;
460df930be7Sderaadt if (loc < 0)
461a916033eSmillert fprintf(stderr, "bad seek pointer to rst_seekdir %ld\n", loc);
462df930be7Sderaadt (void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
463df930be7Sderaadt dirp->dd_loc = loc & (DIRBLKSIZ - 1);
464df930be7Sderaadt if (dirp->dd_loc != 0)
465df930be7Sderaadt dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
466df930be7Sderaadt }
467df930be7Sderaadt
468df930be7Sderaadt /*
469df930be7Sderaadt * get next entry in a directory.
470df930be7Sderaadt */
471df930be7Sderaadt struct direct *
rst_readdir(RST_DIR * dirp)4724e95fccfSderaadt rst_readdir(RST_DIR *dirp)
473df930be7Sderaadt {
474e073c79dSmpech struct direct *dp;
475df930be7Sderaadt
476df930be7Sderaadt for (;;) {
477df930be7Sderaadt if (dirp->dd_loc == 0) {
478df930be7Sderaadt dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
479df930be7Sderaadt DIRBLKSIZ);
480df930be7Sderaadt if (dirp->dd_size <= 0) {
481a916033eSmillert Dprintf(stderr, "error reading directory\n");
482df930be7Sderaadt return (NULL);
483df930be7Sderaadt }
484df930be7Sderaadt }
485df930be7Sderaadt if (dirp->dd_loc >= dirp->dd_size) {
486df930be7Sderaadt dirp->dd_loc = 0;
487df930be7Sderaadt continue;
488df930be7Sderaadt }
489df930be7Sderaadt dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
490df930be7Sderaadt if (dp->d_reclen == 0 ||
491df930be7Sderaadt dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
492a916033eSmillert Dprintf(stderr, "corrupted directory: bad reclen %d\n",
493df930be7Sderaadt dp->d_reclen);
494df930be7Sderaadt return (NULL);
495df930be7Sderaadt }
496df930be7Sderaadt dirp->dd_loc += dp->d_reclen;
497df930be7Sderaadt if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
498df930be7Sderaadt return (NULL);
499df930be7Sderaadt if (dp->d_ino >= maxino) {
5003b92bd08Sderaadt Dprintf(stderr, "corrupted directory: bad inum %llu\n",
5013b92bd08Sderaadt (unsigned long long)dp->d_ino);
502df930be7Sderaadt continue;
503df930be7Sderaadt }
504df930be7Sderaadt return (dp);
505df930be7Sderaadt }
506df930be7Sderaadt }
507df930be7Sderaadt
508df930be7Sderaadt /*
509df930be7Sderaadt * Simulate the opening of a directory
510df930be7Sderaadt */
511df930be7Sderaadt RST_DIR *
rst_opendir(const char * name)5124e95fccfSderaadt rst_opendir(const char *name)
513df930be7Sderaadt {
514df930be7Sderaadt struct inotab *itp;
515df930be7Sderaadt RST_DIR *dirp;
516df930be7Sderaadt ino_t ino;
517df930be7Sderaadt
518df930be7Sderaadt if ((ino = dirlookup(name)) > 0 &&
519df930be7Sderaadt (itp = inotablookup(ino)) != NULL) {
520df930be7Sderaadt dirp = opendirfile(dirfile);
521df930be7Sderaadt rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
522df930be7Sderaadt return (dirp);
523df930be7Sderaadt }
524df930be7Sderaadt return (NULL);
525df930be7Sderaadt }
526df930be7Sderaadt
527df930be7Sderaadt /*
528df930be7Sderaadt * In our case, there is nothing to do when closing a directory.
529df930be7Sderaadt */
530df930be7Sderaadt void
rst_closedir(RST_DIR * dirp)5314e95fccfSderaadt rst_closedir(RST_DIR *dirp)
532df930be7Sderaadt {
533df930be7Sderaadt (void)close(dirp->dd_fd);
534df930be7Sderaadt free(dirp);
535df930be7Sderaadt return;
536df930be7Sderaadt }
537df930be7Sderaadt
538df930be7Sderaadt /*
539df930be7Sderaadt * Simulate finding the current offset in the directory.
540df930be7Sderaadt */
541df930be7Sderaadt static long
rst_telldir(RST_DIR * dirp)5424e95fccfSderaadt rst_telldir(RST_DIR *dirp)
543df930be7Sderaadt {
544df930be7Sderaadt return ((long)lseek(dirp->dd_fd,
545df930be7Sderaadt (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
546df930be7Sderaadt }
547df930be7Sderaadt
548df930be7Sderaadt /*
549df930be7Sderaadt * Open a directory file.
550df930be7Sderaadt */
551df930be7Sderaadt static RST_DIR *
opendirfile(const char * name)5524e95fccfSderaadt opendirfile(const char *name)
553df930be7Sderaadt {
554e073c79dSmpech RST_DIR *dirp;
555e073c79dSmpech int fd;
556df930be7Sderaadt
557df930be7Sderaadt if ((fd = open(name, O_RDONLY)) == -1)
558df930be7Sderaadt return (NULL);
559df930be7Sderaadt if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
560df930be7Sderaadt (void)close(fd);
561df930be7Sderaadt return (NULL);
562df930be7Sderaadt }
563df930be7Sderaadt dirp->dd_fd = fd;
564df930be7Sderaadt dirp->dd_loc = 0;
565df930be7Sderaadt return (dirp);
566df930be7Sderaadt }
567df930be7Sderaadt
568df930be7Sderaadt /*
569df930be7Sderaadt * Set the mode, owner, and times for all new or changed directories
570df930be7Sderaadt */
571df930be7Sderaadt void
setdirmodes(int flags)5724e95fccfSderaadt setdirmodes(int flags)
573df930be7Sderaadt {
574df930be7Sderaadt FILE *mf;
575df930be7Sderaadt struct modeinfo node;
576df930be7Sderaadt struct entry *ep;
577df930be7Sderaadt char *cp;
578df930be7Sderaadt
579a916033eSmillert Vprintf(stdout, "Set directory mode, owner, and times.\n");
580f79cb2fdSderaadt if (command == 'r' || command == 'R')
581520eb379Sotto (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld",
582520eb379Sotto tmpdir, (long long)dumpdate);
583f79cb2fdSderaadt if (modefile[0] == '#') {
584f79cb2fdSderaadt panic("modefile not defined\n");
585a916033eSmillert fputs("directory mode, owner, and times not set\n", stderr);
586f79cb2fdSderaadt return;
587f79cb2fdSderaadt }
588df930be7Sderaadt mf = fopen(modefile, "r");
589df930be7Sderaadt if (mf == NULL) {
590a916033eSmillert warn("fopen");
591df930be7Sderaadt fprintf(stderr, "cannot open mode file %s\n", modefile);
592df930be7Sderaadt fprintf(stderr, "directory mode, owner, and times not set\n");
593df930be7Sderaadt return;
594df930be7Sderaadt }
595df930be7Sderaadt clearerr(mf);
596df930be7Sderaadt for (;;) {
597df930be7Sderaadt (void)fread((char *)&node, 1, sizeof(struct modeinfo), mf);
598df930be7Sderaadt if (feof(mf))
599df930be7Sderaadt break;
600df930be7Sderaadt ep = lookupino(node.ino);
601df930be7Sderaadt if (command == 'i' || command == 'x') {
602df930be7Sderaadt if (ep == NULL)
603df930be7Sderaadt continue;
604df930be7Sderaadt if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
605df930be7Sderaadt ep->e_flags &= ~NEW;
606df930be7Sderaadt continue;
607df930be7Sderaadt }
608df930be7Sderaadt if (node.ino == ROOTINO &&
609df930be7Sderaadt reply("set owner/mode for '.'") == FAIL)
610df930be7Sderaadt continue;
611df930be7Sderaadt }
612df930be7Sderaadt if (ep == NULL) {
6133b92bd08Sderaadt panic("cannot find directory inode %llu\n",
6143b92bd08Sderaadt (unsigned long long)node.ino);
615df930be7Sderaadt } else {
6160155e653Smillert if (!Nflag) {
617df930be7Sderaadt cp = myname(ep);
618df930be7Sderaadt (void)chown(cp, node.uid, node.gid);
619df930be7Sderaadt (void)chmod(cp, node.mode);
620df930be7Sderaadt (void)chflags(cp, node.flags);
621a740969bSguenther (void)utimensat(AT_FDCWD, cp, node.ctimep, 0);
622a740969bSguenther (void)utimensat(AT_FDCWD, cp, node.mtimep, 0);
6230155e653Smillert }
624df930be7Sderaadt ep->e_flags &= ~NEW;
625df930be7Sderaadt }
626df930be7Sderaadt }
627df930be7Sderaadt if (ferror(mf))
628df930be7Sderaadt panic("error setting directory modes\n");
629df930be7Sderaadt (void)fclose(mf);
630df930be7Sderaadt }
631df930be7Sderaadt
632df930be7Sderaadt /*
633df930be7Sderaadt * Generate a literal copy of a directory.
634df930be7Sderaadt */
635df930be7Sderaadt int
genliteraldir(char * name,ino_t ino)6364e95fccfSderaadt genliteraldir(char *name, ino_t ino)
637df930be7Sderaadt {
638e073c79dSmpech struct inotab *itp;
639df930be7Sderaadt int ofile, dp, i, size;
640df930be7Sderaadt char buf[BUFSIZ];
641df930be7Sderaadt
642df930be7Sderaadt itp = inotablookup(ino);
643df930be7Sderaadt if (itp == NULL)
6443b92bd08Sderaadt panic("Cannot find directory inode %llu named %s\n",
6453b92bd08Sderaadt (unsigned long long)ino, name);
646df69c215Sderaadt if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
647a916033eSmillert warn("%s: cannot create file", name);
648df930be7Sderaadt return (FAIL);
649df930be7Sderaadt }
650df930be7Sderaadt rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
651df930be7Sderaadt dp = dup(dirp->dd_fd);
652df930be7Sderaadt for (i = itp->t_size; i > 0; i -= BUFSIZ) {
653df930be7Sderaadt size = i < BUFSIZ ? i : BUFSIZ;
6543085c8d2Sguenther if (read(dp, buf, size) == -1)
6553085c8d2Sguenther err(1, "read error extracting inode %llu, name %s",
6563b92bd08Sderaadt (unsigned long long)curfile.ino, curfile.name);
6573085c8d2Sguenther xtrfile(buf, size);
658df930be7Sderaadt }
659df930be7Sderaadt (void)close(dp);
660df930be7Sderaadt (void)close(ofile);
661df930be7Sderaadt return (GOOD);
662df930be7Sderaadt }
663df930be7Sderaadt
664df930be7Sderaadt /*
665df930be7Sderaadt * Determine the type of an inode
666df930be7Sderaadt */
667df930be7Sderaadt int
inodetype(ino_t ino)6684e95fccfSderaadt inodetype(ino_t ino)
669df930be7Sderaadt {
670df930be7Sderaadt struct inotab *itp;
671df930be7Sderaadt
672df930be7Sderaadt itp = inotablookup(ino);
673df930be7Sderaadt if (itp == NULL)
674df930be7Sderaadt return (LEAF);
675df930be7Sderaadt return (NODE);
676df930be7Sderaadt }
677df930be7Sderaadt
678df930be7Sderaadt /*
679df930be7Sderaadt * Allocate and initialize a directory inode entry.
680df930be7Sderaadt * If requested, save its pertinent mode, owner, and time info.
681df930be7Sderaadt */
682df930be7Sderaadt static struct inotab *
allocinotab(FILE * mf,struct context * ctxp,long seekpt)6830155e653Smillert allocinotab(FILE *mf, struct context *ctxp, long seekpt)
684df930be7Sderaadt {
685e073c79dSmpech struct inotab *itp;
686df930be7Sderaadt struct modeinfo node;
687df930be7Sderaadt
688df930be7Sderaadt itp = calloc(1, sizeof(struct inotab));
689df930be7Sderaadt if (itp == NULL)
690df930be7Sderaadt panic("no memory directory table\n");
6910155e653Smillert itp->t_next = inotab[INOHASH(ctxp->ino)];
6920155e653Smillert inotab[INOHASH(ctxp->ino)] = itp;
6930155e653Smillert itp->t_ino = ctxp->ino;
694df930be7Sderaadt itp->t_seekpt = seekpt;
695df930be7Sderaadt if (mf == NULL)
696df930be7Sderaadt return (itp);
6970155e653Smillert node.ino = ctxp->ino;
6980155e653Smillert node.mtimep[0].tv_sec = ctxp->atime_sec;
699a740969bSguenther node.mtimep[0].tv_nsec = ctxp->atime_nsec;
7000155e653Smillert node.mtimep[1].tv_sec = ctxp->mtime_sec;
701a740969bSguenther node.mtimep[1].tv_nsec = ctxp->mtime_nsec;
7020155e653Smillert node.ctimep[0].tv_sec = ctxp->atime_sec;
703a740969bSguenther node.ctimep[0].tv_nsec = ctxp->atime_nsec;
7040155e653Smillert node.ctimep[1].tv_sec = ctxp->birthtime_sec;
705a740969bSguenther node.ctimep[1].tv_nsec = ctxp->birthtime_nsec;
7060155e653Smillert node.mode = ctxp->mode;
7070155e653Smillert node.flags = ctxp->file_flags;
7080155e653Smillert node.uid = ctxp->uid;
7090155e653Smillert node.gid = ctxp->gid;
710df930be7Sderaadt (void)fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
711df930be7Sderaadt return (itp);
712df930be7Sderaadt }
713df930be7Sderaadt
714df930be7Sderaadt /*
715df930be7Sderaadt * Look up an inode in the table of directories
716df930be7Sderaadt */
717df930be7Sderaadt static struct inotab *
inotablookup(ino_t ino)7184e95fccfSderaadt inotablookup(ino_t ino)
719df930be7Sderaadt {
720e073c79dSmpech struct inotab *itp;
721df930be7Sderaadt
722df930be7Sderaadt for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
723df930be7Sderaadt if (itp->t_ino == ino)
724df930be7Sderaadt return (itp);
725df930be7Sderaadt return (NULL);
726df930be7Sderaadt }
727df930be7Sderaadt
728df930be7Sderaadt /*
729df930be7Sderaadt * Clean up and exit
730df930be7Sderaadt */
731df930be7Sderaadt void
cleanup(void)7324e95fccfSderaadt cleanup(void)
733df930be7Sderaadt {
734df930be7Sderaadt
735df930be7Sderaadt closemt();
736df930be7Sderaadt if (modefile[0] != '#')
737df930be7Sderaadt (void)unlink(modefile);
738df930be7Sderaadt if (dirfile[0] != '#')
739df930be7Sderaadt (void)unlink(dirfile);
740df930be7Sderaadt }
741