dirs.c revision 1.37 1 /* $NetBSD: dirs.c,v 1.37 2002/05/09 02:55:50 simonb 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.37 2002/05/09 02:55:50 simonb 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 0 /* dp->d_namlen is a uint8_t, always < NAME_MAX */
398 if (dp->d_namlen > NAME_MAX)
399 vprintf(stdout,
400 "reclen name too big (%d > %d) ",
401 dp->d_namlen, NAME_MAX);
402 #endif
403 vprintf(stdout, "\n");
404 loc += i;
405 continue;
406 }
407 loc += dp->d_reclen;
408 if (dp->d_ino != 0) {
409 putent(dp);
410 }
411 }
412 }
413 }
414
415 /*
416 * These variables are "local" to the following two functions.
417 */
418 char dirbuf[DIRBLKSIZ];
419 long dirloc = 0;
420 long prev = 0;
421
422 /*
423 * add a new directory entry to a file.
424 */
425 static void
426 putent(dp)
427 struct direct *dp;
428 {
429 dp->d_reclen = DIRSIZ(0, dp, 0);
430 if (dirloc + dp->d_reclen > DIRBLKSIZ) {
431 ((struct direct *)(dirbuf + prev))->d_reclen =
432 DIRBLKSIZ - prev;
433 (void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
434 dirloc = 0;
435 }
436 memmove(dirbuf + dirloc, dp, (long)dp->d_reclen);
437 prev = dirloc;
438 dirloc += dp->d_reclen;
439 }
440
441 /*
442 * flush out a directory that is finished.
443 */
444 static void
445 flushent()
446 {
447 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
448 (void) fwrite(dirbuf, (int)dirloc, 1, df);
449 seekpt = ftell(df);
450 dirloc = 0;
451 }
452
453 static void
454 dcvt(odp, ndp)
455 struct odirect *odp;
456 struct direct *ndp;
457 {
458
459 memset(ndp, 0, (size_t)(sizeof *ndp));
460 ndp->d_ino = odp->d_ino;
461 ndp->d_type = DT_UNKNOWN;
462 (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
463 ndp->d_namlen = strlen(ndp->d_name);
464 ndp->d_reclen = DIRSIZ(0, ndp, 0);
465 }
466
467 /*
468 * Seek to an entry in a directory.
469 * Only values returned by rst_telldir should be passed to rst_seekdir.
470 * This routine handles many directories in a single file.
471 * It takes the base of the directory in the file, plus
472 * the desired seek offset into it.
473 */
474 static void
475 rst_seekdir(rdirp, loc, base)
476 RST_DIR *rdirp;
477 long loc, base;
478 {
479
480 if (loc == rst_telldir(rdirp))
481 return;
482 loc -= base;
483 if (loc < 0)
484 fprintf(stderr, "bad seek pointer to rst_seekdir %d\n",
485 (int)loc);
486 (void) lseek(rdirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
487 rdirp->dd_loc = loc & (DIRBLKSIZ - 1);
488 if (rdirp->dd_loc != 0)
489 rdirp->dd_size = read(rdirp->dd_fd, rdirp->dd_buf, DIRBLKSIZ);
490 }
491
492 /*
493 * get next entry in a directory.
494 */
495 struct direct *
496 rst_readdir(rdirp)
497 RST_DIR *rdirp;
498 {
499 struct direct *dp;
500
501 for (;;) {
502 if (rdirp->dd_loc == 0) {
503 rdirp->dd_size = read(rdirp->dd_fd, rdirp->dd_buf,
504 DIRBLKSIZ);
505 if (rdirp->dd_size <= 0) {
506 dprintf(stderr, "error reading directory\n");
507 return (NULL);
508 }
509 }
510 if (rdirp->dd_loc >= rdirp->dd_size) {
511 rdirp->dd_loc = 0;
512 continue;
513 }
514 dp = (struct direct *)(rdirp->dd_buf + rdirp->dd_loc);
515 if (dp->d_reclen == 0 ||
516 dp->d_reclen > DIRBLKSIZ + 1 - rdirp->dd_loc) {
517 dprintf(stderr, "corrupted directory: bad reclen %d\n",
518 dp->d_reclen);
519 return (NULL);
520 }
521 rdirp->dd_loc += dp->d_reclen;
522 if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
523 return (NULL);
524 if (dp->d_ino >= maxino) {
525 dprintf(stderr, "corrupted directory: bad inum %d\n",
526 dp->d_ino);
527 continue;
528 }
529 return (dp);
530 }
531 }
532
533 /*
534 * Simulate the opening of a directory
535 */
536 RST_DIR *
537 rst_opendir(name)
538 const char *name;
539 {
540 struct inotab *itp;
541 RST_DIR *rdirp;
542 ino_t ino;
543
544 if ((ino = dirlookup(name)) > 0 &&
545 (itp = inotablookup(ino)) != NULL) {
546 rdirp = opendirfile(dirfile);
547 rst_seekdir(rdirp, itp->t_seekpt, itp->t_seekpt);
548 return (rdirp);
549 }
550 return (NULL);
551 }
552
553 /*
554 * In our case, there is nothing to do when closing a directory.
555 */
556 void
557 rst_closedir(rdirp)
558 RST_DIR *rdirp;
559 {
560
561 (void)close(rdirp->dd_fd);
562 free(rdirp);
563 return;
564 }
565
566 /*
567 * Simulate finding the current offset in the directory.
568 */
569 static long
570 rst_telldir(rdirp)
571 RST_DIR *rdirp;
572 {
573 return ((long)lseek(rdirp->dd_fd,
574 (off_t)0, SEEK_CUR) - rdirp->dd_size + rdirp->dd_loc);
575 }
576
577 /*
578 * Open a directory file.
579 */
580 static RST_DIR *
581 opendirfile(name)
582 const char *name;
583 {
584 RST_DIR *rdirp;
585 int fd;
586
587 if ((fd = open(name, O_RDONLY)) == -1)
588 return (NULL);
589 if ((rdirp = malloc(sizeof(RST_DIR))) == NULL) {
590 (void)close(fd);
591 return (NULL);
592 }
593 rdirp->dd_fd = fd;
594 rdirp->dd_loc = 0;
595 return (rdirp);
596 }
597
598 /*
599 * Set the mode, owner, and times for all new or changed directories
600 */
601 void
602 setdirmodes(flags)
603 int flags;
604 {
605 FILE *mf;
606 struct modeinfo node;
607 struct entry *ep;
608 char *cp;
609
610 vprintf(stdout, "Set directory mode, owner, and times.\n");
611 if (command == 'r' || command == 'R')
612 (void) snprintf(modefile, sizeof(modefile), "%s/rstmode%d",
613 tmpdir, (int)dumpdate);
614 if (modefile[0] == '#') {
615 panic("modefile not defined\n");
616 fprintf(stderr, "directory mode, owner, and times not set\n");
617 return;
618 }
619 mf = fopen(modefile, "r");
620 if (mf == NULL) {
621 fprintf(stderr, "fopen: %s\n", strerror(errno));
622 fprintf(stderr, "cannot open mode file %s\n", modefile);
623 fprintf(stderr, "directory mode, owner, and times not set\n");
624 return;
625 }
626 clearerr(mf);
627 for (;;) {
628 (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
629 if (feof(mf))
630 break;
631 ep = lookupino(node.ino);
632 if (command == 'i' || command == 'x') {
633 if (ep == NULL)
634 continue;
635 if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
636 ep->e_flags &= ~NEW;
637 continue;
638 }
639 if (node.ino == ROOTINO &&
640 reply("set owner/mode for '.'") == FAIL)
641 continue;
642 }
643 if (ep == NULL) {
644 panic("cannot find directory inode %d\n", node.ino);
645 } else {
646 if (!Nflag) {
647 cp = myname(ep);
648 (void) utimes(cp, node.timep);
649 (void) chown(cp, node.uid, node.gid);
650 (void) chmod(cp, node.mode);
651 (void) chflags(cp, node.flags);
652 }
653 ep->e_flags &= ~NEW;
654 }
655 }
656 if (ferror(mf))
657 panic("error setting directory modes\n");
658 (void) fclose(mf);
659 }
660
661 /*
662 * Generate a literal copy of a directory.
663 */
664 int
665 genliteraldir(name, ino)
666 char *name;
667 ino_t ino;
668 {
669 struct inotab *itp;
670 int ofile, dp, i, size;
671 char buf[BUFSIZ];
672
673 itp = inotablookup(ino);
674 if (itp == NULL)
675 panic("Cannot find directory inode %d named %s\n", ino, name);
676 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
677 fprintf(stderr, "%s: ", name);
678 (void) fflush(stderr);
679 fprintf(stderr, "cannot create file: %s\n", strerror(errno));
680 return (FAIL);
681 }
682 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
683 dp = dup(dirp->dd_fd);
684 for (i = itp->t_size; i > 0; i -= BUFSIZ) {
685 size = i < BUFSIZ ? i : BUFSIZ;
686 if (read(dp, buf, (int) size) == -1) {
687 fprintf(stderr,
688 "write error extracting inode %d, name %s\n",
689 curfile.ino, curfile.name);
690 fprintf(stderr, "read: %s\n", strerror(errno));
691 exit(1);
692 }
693 if (!Nflag && write(ofile, buf, (int) size) == -1) {
694 fprintf(stderr,
695 "write error extracting inode %d, name %s\n",
696 curfile.ino, curfile.name);
697 fprintf(stderr, "write: %s\n", strerror(errno));
698 exit(1);
699 }
700 }
701 (void) close(dp);
702 (void) close(ofile);
703 return (GOOD);
704 }
705
706 /*
707 * Determine the type of an inode
708 */
709 int
710 inodetype(ino)
711 ino_t ino;
712 {
713 struct inotab *itp;
714
715 itp = inotablookup(ino);
716 if (itp == NULL)
717 return (LEAF);
718 return (NODE);
719 }
720
721 /*
722 * Allocate and initialize a directory inode entry.
723 * If requested, save its pertinent mode, owner, and time info.
724 */
725 static struct inotab *
726 allocinotab(mf, ino, dip, aseekpt)
727 FILE *mf;
728 ino_t ino;
729 struct dinode *dip;
730 long aseekpt;
731 {
732 struct inotab *itp;
733 struct modeinfo node;
734
735 itp = calloc(1, sizeof(struct inotab));
736 if (itp == NULL)
737 panic("no memory directory table\n");
738 itp->t_next = inotab[INOHASH(ino)];
739 inotab[INOHASH(ino)] = itp;
740 itp->t_ino = ino;
741 itp->t_seekpt = aseekpt;
742 if (mf == NULL)
743 return (itp);
744 node.ino = ino;
745 node.timep[0].tv_sec = dip->di_atime;
746 node.timep[0].tv_usec = dip->di_atimensec / 1000;
747 node.timep[1].tv_sec = dip->di_mtime;
748 node.timep[1].tv_usec = dip->di_mtimensec / 1000;
749 node.mode = dip->di_mode;
750 node.flags = dip->di_flags;
751 node.uid = dip->di_uid;
752 node.gid = dip->di_gid;
753 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
754 return (itp);
755 }
756
757 /*
758 * Look up an inode in the table of directories
759 */
760 static struct inotab *
761 inotablookup(ino)
762 ino_t ino;
763 {
764 struct inotab *itp;
765
766 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
767 if (itp->t_ino == ino)
768 return (itp);
769 return (NULL);
770 }
771
772 /*
773 * Clean up and exit
774 */
775 void
776 cleanup()
777 {
778
779 closemt();
780 if (modefile[0] != '#')
781 (void) unlink(modefile);
782 if (dirfile[0] != '#')
783 (void) unlink(dirfile);
784 }
785