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