]> git.wh0rd.org - dump.git/blob - restore/dirs.c
Version 0.4b5.
[dump.git] / restore / dirs.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <pop@cybercable.fr>, 1999
6 *
7 */
8
9 /*
10 * Copyright (c) 1983, 1993
11 * The Regents of the University of California. All rights reserved.
12 * (c) UNIX System Laboratories, Inc.
13 * All or some portions of this file are derived from material licensed
14 * to the University of California by American Telephone and Telegraph
15 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
16 * the permission of UNIX System Laboratories, Inc.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the University of
29 * California, Berkeley and its contributors.
30 * 4. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47 #ifndef lint
48 #if 0
49 static char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95";
50 #endif
51 static const char rcsid[] =
52 "$Id: dirs.c,v 1.2 1999/10/11 12:53:23 stelian Exp $";
53 #endif /* not lint */
54
55 #include <sys/param.h>
56 #include <sys/file.h>
57 #include <sys/stat.h>
58
59 #ifdef __linux__
60 #include <linux/ext2_fs.h>
61 #include <bsdcompat.h>
62 #else /* __linux__ */
63 #include <ufs/ufs/dinode.h>
64 #include <ufs/ufs/dir.h>
65 #endif /* __linux__ */
66 #include <protocols/dumprestore.h>
67
68 #include <err.h>
69 #include <errno.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74
75 #ifdef __linux__
76 #include <endian.h>
77 #else
78 #include <machine/endian.h>
79 #endif
80
81 #include "pathnames.h"
82 #include "restore.h"
83 #include "extern.h"
84
85 /*
86 * Symbol table of directories read from tape.
87 */
88 #define HASHSIZE 1000
89 #define INOHASH(val) (val % HASHSIZE)
90 struct inotab {
91 struct inotab *t_next;
92 ino_t t_ino;
93 int32_t t_seekpt;
94 int32_t t_size;
95 };
96 static struct inotab *inotab[HASHSIZE];
97
98 /*
99 * Information retained about directories.
100 */
101 struct modeinfo {
102 ino_t ino;
103 struct timeval timep[2];
104 mode_t mode;
105 uid_t uid;
106 gid_t gid;
107 int flags;
108 };
109
110 /*
111 * Definitions for library routines operating on directories.
112 */
113 #undef DIRBLKSIZ
114 #define DIRBLKSIZ 1024
115 struct rstdirdesc {
116 int dd_fd;
117 int32_t dd_loc;
118 int32_t dd_size;
119 char dd_buf[DIRBLKSIZ];
120 };
121
122 /*
123 * Global variables for this file.
124 */
125 static long seekpt;
126 static FILE *df, *mf;
127 static RST_DIR *dirp;
128 static char dirfile[MAXPATHLEN] = "#"; /* No file */
129 static char modefile[MAXPATHLEN] = "#"; /* No file */
130 static char dot[2] = "."; /* So it can be modified */
131
132 /*
133 * Format of old style directories.
134 */
135 #define ODIRSIZ 14
136 struct odirect {
137 u_short d_ino;
138 char d_name[ODIRSIZ];
139 };
140
141 #ifdef __linux__
142 static struct inotab *allocinotab __P((ino_t, struct new_bsd_inode *, long));
143 #else
144 static struct inotab *allocinotab __P((ino_t, struct dinode *, long));
145 #endif
146 static void dcvt __P((struct odirect *, struct direct *));
147 static void flushent __P((void));
148 static struct inotab *inotablookup __P((ino_t));
149 static RST_DIR *opendirfile __P((const char *));
150 static void putdir __P((char *, long));
151 static void putent __P((struct direct *));
152 static void rst_seekdir __P((RST_DIR *, long, long));
153 static long rst_telldir __P((RST_DIR *));
154 static struct direct *searchdir __P((ino_t, char *));
155
156 /*
157 * Extract directory contents, building up a directory structure
158 * on disk for extraction by name.
159 * If genmode is requested, save mode, owner, and times for all
160 * directories on the tape.
161 */
162 void
163 extractdirs(genmode)
164 int genmode;
165 {
166 register int i;
167 #ifdef __linux__
168 register struct new_bsd_inode *ip;
169 #else
170 register struct dinode *ip;
171 #endif
172 struct inotab *itp;
173 struct direct nulldir;
174 int fd;
175
176 vprintf(stdout, "Extract directories from tape\n");
177 (void) sprintf(dirfile, "%s/rstdir%ld", tmpdir, dumpdate);
178 if (command != 'r' && command != 'R') {
179 (void *) strcat(dirfile, "-XXXXXX");
180 fd = mkstemp(dirfile);
181 } else
182 fd = open(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666);
183 if (fd == -1 || (df = fdopen(fd, "w")) == NULL) {
184 if (fd != -1)
185 close(fd);
186 warn("%s - cannot create directory temporary\nfopen", dirfile);
187 done(1);
188 }
189 if (genmode != 0) {
190 (void) sprintf(modefile, "%s/rstmode%ld", tmpdir, dumpdate);
191 if (command != 'r' && command != 'R') {
192 (void *) strcat(modefile, "-XXXXXX");
193 fd = mkstemp(modefile);
194 } else
195 fd = open(modefile, O_RDWR|O_CREAT|O_EXCL, 0666);
196 if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) {
197 if (fd != -1)
198 close(fd);
199 warn("%s - cannot create modefile\nfopen", modefile);
200 done(1);
201 }
202 }
203 nulldir.d_ino = 0;
204 nulldir.d_type = DT_DIR;
205 nulldir.d_namlen = 1;
206 (void) strcpy(nulldir.d_name, "/");
207 nulldir.d_reclen = DIRSIZ(0, &nulldir);
208 for (;;) {
209 curfile.name = "<directory file - name unknown>";
210 curfile.action = USING;
211 ip = curfile.dip;
212 if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
213 (void) fclose(df);
214 dirp = opendirfile(dirfile);
215 if (dirp == NULL)
216 fprintf(stderr, "opendirfile: %s\n",
217 strerror(errno));
218 if (mf != NULL)
219 (void) fclose(mf);
220 i = dirlookup(dot);
221 if (i == 0)
222 panic("Root directory is not on tape\n");
223 return;
224 }
225 itp = allocinotab(curfile.ino, ip, seekpt);
226 getfile(putdir, xtrnull);
227 putent(&nulldir);
228 flushent();
229 itp->t_size = seekpt - itp->t_seekpt;
230 }
231 }
232
233 /*
234 * skip over all the directories on the tape
235 */
236 void
237 skipdirs()
238 {
239
240 while (curfile.dip && (curfile.dip->di_mode & IFMT) == IFDIR) {
241 skipfile();
242 }
243 }
244
245 /*
246 * Recursively find names and inumbers of all files in subtree
247 * pname and pass them off to be processed.
248 */
249 void
250 treescan(pname, ino, todo)
251 char *pname;
252 ino_t ino;
253 long (*todo) __P((char *, ino_t, int));
254 {
255 register struct inotab *itp;
256 register struct direct *dp;
257 int namelen;
258 long bpt;
259 char locname[MAXPATHLEN + 1];
260
261 itp = inotablookup(ino);
262 if (itp == NULL) {
263 /*
264 * Pname is name of a simple file or an unchanged directory.
265 */
266 (void) (*todo)(pname, ino, LEAF);
267 return;
268 }
269 /*
270 * Pname is a dumped directory name.
271 */
272 if ((*todo)(pname, ino, NODE) == FAIL)
273 return;
274 /*
275 * begin search through the directory
276 * skipping over "." and ".."
277 */
278 (void) strncpy(locname, pname, sizeof(locname) - 1);
279 locname[sizeof(locname) - 1] = '\0';
280 (void) strncat(locname, "/", sizeof(locname) - strlen(locname));
281 namelen = strlen(locname);
282 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
283 dp = rst_readdir(dirp); /* "." */
284 if (dp != NULL && strcmp(dp->d_name, ".") == 0)
285 dp = rst_readdir(dirp); /* ".." */
286 else
287 fprintf(stderr, "Warning: `.' missing from directory %s\n",
288 pname);
289 if (dp != NULL && strcmp(dp->d_name, "..") == 0)
290 dp = rst_readdir(dirp); /* first real entry */
291 else
292 fprintf(stderr, "Warning: `..' missing from directory %s\n",
293 pname);
294 bpt = rst_telldir(dirp);
295 /*
296 * a zero inode signals end of directory
297 */
298 while (dp != NULL) {
299 locname[namelen] = '\0';
300 if (namelen + dp->d_namlen >= sizeof(locname)) {
301 fprintf(stderr, "%s%s: name exceeds %d char\n",
302 locname, dp->d_name, sizeof(locname) - 1);
303 } else {
304 (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
305 treescan(locname, dp->d_ino, todo);
306 rst_seekdir(dirp, bpt, itp->t_seekpt);
307 }
308 dp = rst_readdir(dirp);
309 bpt = rst_telldir(dirp);
310 }
311 }
312
313 /*
314 * Lookup a pathname which is always assumed to start from the ROOTINO.
315 */
316 struct direct *
317 pathsearch(pathname)
318 const char *pathname;
319 {
320 ino_t ino;
321 struct direct *dp;
322 char *path, *name, buffer[MAXPATHLEN];
323
324 strcpy(buffer, pathname);
325 path = buffer;
326 ino = ROOTINO;
327 while (*path == '/')
328 path++;
329 dp = NULL;
330 while ((name = strsep(&path, "/")) != NULL && *name != '\0') {
331 if ((dp = searchdir(ino, name)) == NULL)
332 return (NULL);
333 ino = dp->d_ino;
334 }
335 return (dp);
336 }
337
338 /*
339 * Lookup the requested name in directory inum.
340 * Return its inode number if found, zero if it does not exist.
341 */
342 static struct direct *
343 searchdir(inum, name)
344 ino_t inum;
345 char *name;
346 {
347 register struct direct *dp;
348 register struct inotab *itp;
349 int len;
350
351 itp = inotablookup(inum);
352 if (itp == NULL)
353 return (NULL);
354 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
355 len = strlen(name);
356 do {
357 dp = rst_readdir(dirp);
358 if (dp == NULL)
359 return (NULL);
360 } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
361 return (dp);
362 }
363
364 /*
365 * Put the directory entries in the directory file
366 */
367 static void
368 putdir(buf, size)
369 char *buf;
370 long size;
371 {
372 struct direct cvtbuf;
373 register struct odirect *odp;
374 struct odirect *eodp;
375 register struct direct *dp;
376 long loc, i;
377
378 if (cvtflag) {
379 eodp = (struct odirect *)&buf[size];
380 for (odp = (struct odirect *)buf; odp < eodp; odp++)
381 if (odp->d_ino != 0) {
382 dcvt(odp, &cvtbuf);
383 putent(&cvtbuf);
384 }
385 } else {
386 for (loc = 0; loc < size; ) {
387 dp = (struct direct *)(buf + loc);
388 #ifdef DIRDEBUG
389 printf ("reclen = %d, namlen = %d, type = %d\n",
390 dp->d_reclen, dp->d_namlen, dp->d_type);
391 #endif
392 if (Bcvt)
393 swabst((u_char *)"ls", (u_char *) dp);
394 if (oldinofmt && dp->d_ino != 0) {
395 #ifdef __linux__
396 if (Bcvt)
397 swabst((u_char *)"s", (u_char *)&dp->d_namlen);
398 #else
399 # if BYTE_ORDER == BIG_ENDIAN
400 if (Bcvt)
401 dp->d_namlen = dp->d_type;
402 # else
403 if (!Bcvt)
404 dp->d_namlen = dp->d_type;
405 # endif
406 #endif /* __linux__ */
407 dp->d_type = DT_UNKNOWN;
408 }
409 #ifdef __linux__
410 /*
411 * Horrible hack to read FreeBSD 2.0 dumps
412 */
413 if (!oldinofmt)
414 swabst((u_char *)"6bs", (u_char *) dp);
415 #endif /* __linux__ */
416 #ifdef DIRDEBUG
417 printf ("reclen = %d, namlen = %d, type = %d\n",
418 dp->d_reclen, dp->d_namlen, dp->d_type);
419 #endif
420 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
421 if ((dp->d_reclen & 0x3) != 0 ||
422 dp->d_reclen > i ||
423 dp->d_reclen < DIRSIZ(0, dp) ||
424 dp->d_namlen > NAME_MAX) {
425 vprintf(stdout, "Mangled directory: ");
426 if ((dp->d_reclen & 0x3) != 0)
427 vprintf(stdout,
428 "reclen not multiple of 4 ");
429 if (dp->d_reclen < DIRSIZ(0, dp))
430 vprintf(stdout,
431 "reclen less than DIRSIZ (%d < %d) ",
432 dp->d_reclen, DIRSIZ(0, dp));
433 if (dp->d_namlen > NAME_MAX)
434 vprintf(stdout,
435 "reclen name too big (%d > %d) ",
436 dp->d_namlen, NAME_MAX);
437 vprintf(stdout, "\n");
438 loc += i;
439 continue;
440 }
441 loc += dp->d_reclen;
442 if (dp->d_ino != 0) {
443 putent(dp);
444 }
445 }
446 }
447 }
448
449 /*
450 * These variables are "local" to the following two functions.
451 */
452 char dirbuf[DIRBLKSIZ];
453 long dirloc = 0;
454 long prev = 0;
455
456 /*
457 * add a new directory entry to a file.
458 */
459 static void
460 putent(dp)
461 struct direct *dp;
462 {
463 dp->d_reclen = DIRSIZ(0, dp);
464 if (dirloc + dp->d_reclen > DIRBLKSIZ) {
465 ((struct direct *)(dirbuf + prev))->d_reclen =
466 DIRBLKSIZ - prev;
467 (void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
468 dirloc = 0;
469 }
470 memmove(dirbuf + dirloc, dp, (long)dp->d_reclen);
471 prev = dirloc;
472 dirloc += dp->d_reclen;
473 }
474
475 /*
476 * flush out a directory that is finished.
477 */
478 static void
479 flushent()
480 {
481 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
482 (void) fwrite(dirbuf, (int)dirloc, 1, df);
483 seekpt = ftell(df);
484 dirloc = 0;
485 }
486
487 static void
488 dcvt(odp, ndp)
489 register struct odirect *odp;
490 register struct direct *ndp;
491 {
492
493 memset(ndp, 0, (long)(sizeof *ndp));
494 ndp->d_ino = odp->d_ino;
495 ndp->d_type = DT_UNKNOWN;
496 (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
497 ndp->d_namlen = strlen(ndp->d_name);
498 ndp->d_reclen = DIRSIZ(0, ndp);
499 }
500
501 /*
502 * Seek to an entry in a directory.
503 * Only values returned by rst_telldir should be passed to rst_seekdir.
504 * This routine handles many directories in a single file.
505 * It takes the base of the directory in the file, plus
506 * the desired seek offset into it.
507 */
508 static void
509 rst_seekdir(dirp, loc, base)
510 register RST_DIR *dirp;
511 long loc, base;
512 {
513
514 if (loc == rst_telldir(dirp))
515 return;
516 loc -= base;
517 if (loc < 0)
518 fprintf(stderr, "bad seek pointer to rst_seekdir %ld\n", loc);
519 (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
520 dirp->dd_loc = loc & (DIRBLKSIZ - 1);
521 if (dirp->dd_loc != 0)
522 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
523 }
524
525 /*
526 * get next entry in a directory.
527 */
528 struct direct *
529 rst_readdir(dirp)
530 register RST_DIR *dirp;
531 {
532 register struct direct *dp;
533
534 for (;;) {
535 if (dirp->dd_loc == 0) {
536 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
537 DIRBLKSIZ);
538 if (dirp->dd_size <= 0) {
539 dprintf(stderr, "error reading directory\n");
540 return (NULL);
541 }
542 }
543 if (dirp->dd_loc >= dirp->dd_size) {
544 dirp->dd_loc = 0;
545 continue;
546 }
547 dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
548 if (dp->d_reclen == 0 ||
549 dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
550 dprintf(stderr, "corrupted directory: bad reclen %d\n",
551 dp->d_reclen);
552 return (NULL);
553 }
554 dirp->dd_loc += dp->d_reclen;
555 if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
556 return (NULL);
557 if (dp->d_ino >= maxino) {
558 dprintf(stderr, "corrupted directory: bad inum %d\n",
559 dp->d_ino);
560 continue;
561 }
562 return (dp);
563 }
564 }
565
566 /*
567 * Simulate the opening of a directory
568 */
569 RST_DIR *
570 rst_opendir(name)
571 const char *name;
572 {
573 struct inotab *itp;
574 RST_DIR *dirp;
575 ino_t ino;
576
577 if ((ino = dirlookup(name)) > 0 &&
578 (itp = inotablookup(ino)) != NULL) {
579 dirp = opendirfile(dirfile);
580 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
581 return (dirp);
582 }
583 return (NULL);
584 }
585
586 /*
587 * In our case, there is nothing to do when closing a directory.
588 */
589 void
590 rst_closedir(dirp)
591 RST_DIR *dirp;
592 {
593
594 (void)close(dirp->dd_fd);
595 free(dirp);
596 return;
597 }
598
599 /*
600 * Simulate finding the current offset in the directory.
601 */
602 static long
603 rst_telldir(dirp)
604 RST_DIR *dirp;
605 {
606 return ((long)lseek(dirp->dd_fd,
607 (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
608 }
609
610 /*
611 * Open a directory file.
612 */
613 static RST_DIR *
614 opendirfile(name)
615 const char *name;
616 {
617 register RST_DIR *dirp;
618 register int fd;
619
620 if ((fd = open(name, O_RDONLY)) == -1)
621 return (NULL);
622 if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
623 (void)close(fd);
624 return (NULL);
625 }
626 dirp->dd_fd = fd;
627 dirp->dd_loc = 0;
628 return (dirp);
629 }
630
631 /*
632 * Set the mode, owner, and times for all new or changed directories
633 */
634 void
635 setdirmodes(flags)
636 int flags;
637 {
638 FILE *mf;
639 struct modeinfo node;
640 struct entry *ep;
641 char *cp;
642
643 vprintf(stdout, "Set directory mode, owner, and times.\n");
644 if (command == 'r' || command == 'R')
645 (void) sprintf(modefile, "%s/rstmode%ld", tmpdir, dumpdate);
646 if (modefile[0] == '#') {
647 panic("modefile not defined\n");
648 fprintf(stderr, "directory mode, owner, and times not set\n");
649 return;
650 }
651 mf = fopen(modefile, "r");
652 if (mf == NULL) {
653 fprintf(stderr, "fopen: %s\n", strerror(errno));
654 fprintf(stderr, "cannot open mode file %s\n", modefile);
655 fprintf(stderr, "directory mode, owner, and times not set\n");
656 return;
657 }
658 clearerr(mf);
659 for (;;) {
660 (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
661 if (feof(mf))
662 break;
663 ep = lookupino(node.ino);
664 if (command == 'i' || command == 'x') {
665 if (ep == NULL)
666 continue;
667 if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
668 ep->e_flags &= ~NEW;
669 continue;
670 }
671 if (node.ino == ROOTINO &&
672 reply("set owner/mode for '.'") == FAIL)
673 continue;
674 }
675 if (ep == NULL) {
676 panic("cannot find directory inode %d\n", node.ino);
677 } else {
678 cp = myname(ep);
679 (void) chown(cp, node.uid, node.gid);
680 (void) chmod(cp, node.mode);
681 #ifdef __linux__
682 (void) setflags(cp, node.flags);
683 #else
684 (void) chflags(cp, node.flags);
685 #endif
686 utimes(cp, node.timep);
687 ep->e_flags &= ~NEW;
688 }
689 }
690 if (ferror(mf))
691 panic("error setting directory modes\n");
692 (void) fclose(mf);
693 }
694
695 /*
696 * Generate a literal copy of a directory.
697 */
698 int
699 genliteraldir(name, ino)
700 char *name;
701 ino_t ino;
702 {
703 register struct inotab *itp;
704 int ofile, dp, i, size;
705 char buf[BUFSIZ];
706
707 itp = inotablookup(ino);
708 if (itp == NULL)
709 panic("Cannot find directory inode %d named %s\n", ino, name);
710 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
711 fprintf(stderr, "%s: ", name);
712 (void) fflush(stderr);
713 fprintf(stderr, "cannot create file: %s\n", strerror(errno));
714 return (FAIL);
715 }
716 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
717 dp = dup(dirp->dd_fd);
718 for (i = itp->t_size; i > 0; i -= BUFSIZ) {
719 size = i < BUFSIZ ? i : BUFSIZ;
720 if (read(dp, buf, (int) size) == -1) {
721 fprintf(stderr,
722 "write error extracting inode %ld, name %s\n",
723 curfile.ino, curfile.name);
724 fprintf(stderr, "read: %s\n", strerror(errno));
725 done(1);
726 }
727 if (!Nflag && write(ofile, buf, (int) size) == -1) {
728 fprintf(stderr,
729 "write error extracting inode %ld, name %s\n",
730 curfile.ino, curfile.name);
731 fprintf(stderr, "write: %s\n", strerror(errno));
732 done(1);
733 }
734 }
735 (void) close(dp);
736 (void) close(ofile);
737 return (GOOD);
738 }
739
740 /*
741 * Determine the type of an inode
742 */
743 int
744 inodetype(ino)
745 ino_t ino;
746 {
747 struct inotab *itp;
748
749 itp = inotablookup(ino);
750 if (itp == NULL)
751 return (LEAF);
752 return (NODE);
753 }
754
755 /*
756 * Allocate and initialize a directory inode entry.
757 * If requested, save its pertinent mode, owner, and time info.
758 */
759 static struct inotab *
760 allocinotab(ino, dip, seekpt)
761 ino_t ino;
762 #ifdef __linux__
763 struct new_bsd_inode *dip;
764 #else
765 struct dinode *dip;
766 #endif
767 long seekpt;
768 {
769 register struct inotab *itp;
770 struct modeinfo node;
771
772 itp = calloc(1, sizeof(struct inotab));
773 if (itp == NULL)
774 panic("no memory directory table\n");
775 itp->t_next = inotab[INOHASH(ino)];
776 inotab[INOHASH(ino)] = itp;
777 itp->t_ino = ino;
778 itp->t_seekpt = seekpt;
779 if (mf == NULL)
780 return (itp);
781 node.ino = ino;
782 #ifdef __linux__
783 node.timep[0].tv_sec = dip->di_atime.tv_sec;
784 node.timep[0].tv_usec = dip->di_atime.tv_usec;
785 node.timep[1].tv_sec = dip->di_mtime.tv_sec;
786 node.timep[1].tv_usec = dip->di_mtime.tv_usec;
787 #else /* __linux__ */
788 node.timep[0].tv_sec = dip->di_atime;
789 node.timep[0].tv_usec = dip->di_atimensec / 1000;
790 node.timep[1].tv_sec = dip->di_mtime;
791 node.timep[1].tv_usec = dip->di_mtimensec / 1000;
792 #endif /* __linux__ */
793 node.mode = dip->di_mode;
794 node.flags = dip->di_flags;
795 node.uid = dip->di_uid;
796 node.gid = dip->di_gid;
797 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
798 return (itp);
799 }
800
801 /*
802 * Look up an inode in the table of directories
803 */
804 static struct inotab *
805 inotablookup(ino)
806 ino_t ino;
807 {
808 register struct inotab *itp;
809
810 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
811 if (itp->t_ino == ino)
812 return (itp);
813 return (NULL);
814 }
815
816 /*
817 * Clean up and exit
818 */
819 void
820 done(exitcode)
821 int exitcode;
822 {
823
824 closemt();
825 if (modefile[0] != '#')
826 (void) unlink(modefile);
827 if (dirfile[0] != '#')
828 (void) unlink(dirfile);
829 exit(exitcode);
830 }