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