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