Commit | Line | Data |
---|---|---|
f743fc86 KM |
1 | /* Copyright (c) 1983 Regents of the University of California */ |
2 | ||
3 | #ifndef lint | |
c03606b5 | 4 | static char sccsid[] = "@(#)dirs.c 3.9 (Berkeley) 83/05/03"; |
f743fc86 KM |
5 | #endif |
6 | ||
7 | #include "restore.h" | |
8 | #include <dumprestor.h> | |
9f13f26d | 9 | #include <sys/file.h> |
f743fc86 KM |
10 | #include <dir.h> |
11 | ||
7432ff81 KM |
12 | /* |
13 | * Symbol table of directories read from tape. | |
14 | */ | |
f743fc86 | 15 | #define HASHSIZE 1000 |
f743fc86 KM |
16 | #define INOHASH(val) (val % HASHSIZE) |
17 | struct inotab { | |
18 | struct inotab *t_next; | |
19 | ino_t t_ino; | |
20 | daddr_t t_seekpt; | |
21 | long t_size; | |
9f13f26d KM |
22 | }; |
23 | static struct inotab *inotab[HASHSIZE]; | |
24 | extern struct inotab *inotablookup(); | |
9730f69a | 25 | extern struct inotab *allocinotab(); |
f743fc86 | 26 | |
7432ff81 KM |
27 | /* |
28 | * Information retained about directories. | |
29 | */ | |
f743fc86 KM |
30 | struct modeinfo { |
31 | ino_t ino; | |
32 | time_t timep[2]; | |
33 | short mode; | |
34 | short uid; | |
35 | short gid; | |
36 | }; | |
37 | ||
7432ff81 KM |
38 | /* |
39 | * Global variables for this file. | |
40 | */ | |
9f13f26d KM |
41 | static daddr_t seekpt; |
42 | static FILE *df, *mf; | |
43 | static DIR *dirp; | |
7432ff81 KM |
44 | static char dirfile[32] = "#"; /* No file */ |
45 | static char modefile[32] = "#"; /* No file */ | |
9f13f26d | 46 | extern ino_t search(); |
f743fc86 | 47 | |
7432ff81 KM |
48 | /* |
49 | * Format of old style directories. | |
50 | */ | |
f743fc86 KM |
51 | #define ODIRSIZ 14 |
52 | struct odirect { | |
53 | u_short d_ino; | |
54 | char d_name[ODIRSIZ]; | |
55 | }; | |
56 | ||
7432ff81 KM |
57 | /* |
58 | * Structure and routines associated with listing directories. | |
59 | */ | |
60 | struct afile { | |
61 | ino_t fnum; /* inode number of file */ | |
62 | char *fname; /* file name */ | |
63 | short fflags; /* extraction flags, if any */ | |
64 | char ftype; /* file type, e.g. LEAF or NODE */ | |
65 | }; | |
66 | extern int fcmp(); | |
67 | extern char *fmtentry(); | |
68 | ||
f743fc86 KM |
69 | /* |
70 | * Extract directory contents, building up a directory structure | |
71 | * on disk for extraction by name. | |
7432ff81 | 72 | * If genmode is requested, save mode, owner, and times for all |
f743fc86 KM |
73 | * directories on the tape. |
74 | */ | |
7432ff81 KM |
75 | extractdirs(genmode) |
76 | int genmode; | |
f743fc86 KM |
77 | { |
78 | register int i; | |
79 | register struct dinode *ip; | |
9730f69a | 80 | struct inotab *itp; |
f743fc86 KM |
81 | struct direct nulldir; |
82 | int putdir(), null(); | |
83 | ||
84 | vprintf(stdout, "Extract directories from tape\n"); | |
7432ff81 | 85 | (void) sprintf(dirfile, "/tmp/rstdir%d", dumpdate); |
f743fc86 KM |
86 | df = fopen(dirfile, "w"); |
87 | if (df == 0) { | |
88 | fprintf(stderr, | |
89 | "restor: %s - cannot create directory temporary\n", | |
90 | dirfile); | |
91 | perror("fopen"); | |
92 | done(1); | |
93 | } | |
7432ff81 KM |
94 | if (genmode != 0) { |
95 | (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate); | |
f743fc86 | 96 | mf = fopen(modefile, "w"); |
9f13f26d | 97 | if (mf == 0) { |
f743fc86 KM |
98 | fprintf(stderr, |
99 | "restor: %s - cannot create modefile \n", | |
100 | modefile); | |
101 | perror("fopen"); | |
102 | done(1); | |
103 | } | |
104 | } | |
9730f69a | 105 | nulldir.d_ino = 0; |
f743fc86 | 106 | nulldir.d_namlen = 1; |
7432ff81 | 107 | (void) strncpy(nulldir.d_name, "/", (int)nulldir.d_namlen); |
f743fc86 KM |
108 | nulldir.d_reclen = DIRSIZ(&nulldir); |
109 | for (;;) { | |
110 | curfile.name = "<directory file - name unknown>"; | |
111 | curfile.action = USING; | |
112 | ip = curfile.dip; | |
113 | i = ip->di_mode & IFMT; | |
114 | if (i != IFDIR) { | |
82d46726 | 115 | (void) fclose(df); |
f743fc86 KM |
116 | dirp = opendir(dirfile); |
117 | if (dirp == NULL) | |
118 | perror("opendir"); | |
119 | if (mf != NULL) | |
82d46726 | 120 | (void) fclose(mf); |
7432ff81 KM |
121 | i = dirlookup("."); |
122 | if (i == 0) | |
7851e15d | 123 | panic("Root directory is not on tape\n"); |
f743fc86 KM |
124 | return; |
125 | } | |
9730f69a | 126 | itp = allocinotab(curfile.ino, ip, seekpt); |
f743fc86 KM |
127 | getfile(putdir, null); |
128 | putent(&nulldir); | |
129 | flushent(); | |
9730f69a KM |
130 | itp->t_size = seekpt - itp->t_seekpt; |
131 | } | |
132 | } | |
133 | ||
134 | /* | |
135 | * skip over all the directories on the tape | |
136 | */ | |
137 | skipdirs() | |
138 | { | |
139 | ||
140 | while ((curfile.dip->di_mode & IFMT) == IFDIR) { | |
141 | skipfile(); | |
f743fc86 KM |
142 | } |
143 | } | |
144 | ||
145 | /* | |
146 | * Recursively find names and inumbers of all files in subtree | |
147 | * pname and pass them off to be processed. | |
148 | */ | |
149 | treescan(pname, ino, todo) | |
150 | char *pname; | |
151 | ino_t ino; | |
314ac756 | 152 | long (*todo)(); |
f743fc86 KM |
153 | { |
154 | register struct inotab *itp; | |
155 | int namelen; | |
156 | daddr_t bpt; | |
157 | register struct direct *dp; | |
4796d2a4 | 158 | char locname[MAXPATHLEN + 1]; |
f743fc86 KM |
159 | |
160 | itp = inotablookup(ino); | |
161 | if (itp == NULL) { | |
162 | /* | |
163 | * Pname is name of a simple file or an unchanged directory. | |
164 | */ | |
314ac756 | 165 | (void) (*todo)(pname, ino, LEAF); |
f743fc86 KM |
166 | return; |
167 | } | |
168 | /* | |
169 | * Pname is a dumped directory name. | |
170 | */ | |
314ac756 KM |
171 | if ((*todo)(pname, ino, NODE) == FAIL) |
172 | return; | |
f743fc86 KM |
173 | /* |
174 | * begin search through the directory | |
175 | * skipping over "." and ".." | |
176 | */ | |
7432ff81 KM |
177 | (void) strncpy(locname, pname, MAXPATHLEN); |
178 | (void) strncat(locname, "/", MAXPATHLEN); | |
f743fc86 KM |
179 | namelen = strlen(locname); |
180 | seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |
181 | dp = readdir(dirp); /* "." */ | |
182 | dp = readdir(dirp); /* ".." */ | |
183 | dp = readdir(dirp); /* first real entry */ | |
184 | bpt = telldir(dirp); | |
185 | /* | |
186 | * "/" signals end of directory | |
187 | */ | |
188 | while (dp != NULL && !(dp->d_namlen == 1 && dp->d_name[0] == '/')) { | |
189 | locname[namelen] = '\0'; | |
4796d2a4 | 190 | if (namelen + dp->d_namlen >= MAXPATHLEN) { |
f743fc86 | 191 | fprintf(stderr, "%s%s: name exceeds %d char\n", |
4796d2a4 | 192 | locname, dp->d_name, MAXPATHLEN); |
f743fc86 | 193 | } else { |
7432ff81 | 194 | (void) strncat(locname, dp->d_name, (int)dp->d_namlen); |
f743fc86 KM |
195 | treescan(locname, dp->d_ino, todo); |
196 | seekdir(dirp, bpt, itp->t_seekpt); | |
197 | } | |
198 | dp = readdir(dirp); | |
199 | bpt = telldir(dirp); | |
200 | } | |
201 | if (dp == NULL) | |
202 | fprintf(stderr, "corrupted directory: %s.\n", locname); | |
203 | } | |
204 | ||
205 | /* | |
206 | * Search the directory tree rooted at inode ROOTINO | |
207 | * for the path pointed at by n | |
208 | */ | |
209 | ino_t | |
210 | psearch(n) | |
211 | char *n; | |
212 | { | |
213 | register char *cp, *cp1; | |
214 | ino_t ino; | |
215 | char c; | |
216 | ||
217 | ino = ROOTINO; | |
218 | if (*(cp = n) == '/') | |
219 | cp++; | |
220 | next: | |
221 | cp1 = cp + 1; | |
222 | while (*cp1 != '/' && *cp1) | |
223 | cp1++; | |
224 | c = *cp1; | |
225 | *cp1 = 0; | |
226 | ino = search(ino, cp); | |
227 | if (ino == 0) { | |
228 | *cp1 = c; | |
229 | return(0); | |
230 | } | |
231 | *cp1 = c; | |
232 | if (c == '/') { | |
233 | cp = cp1+1; | |
234 | goto next; | |
235 | } | |
236 | return(ino); | |
237 | } | |
238 | ||
239 | /* | |
240 | * search the directory inode ino | |
241 | * looking for entry cp | |
242 | */ | |
243 | ino_t | |
244 | search(inum, cp) | |
245 | ino_t inum; | |
246 | char *cp; | |
247 | { | |
248 | register struct direct *dp; | |
249 | register struct inotab *itp; | |
250 | int len; | |
251 | ||
252 | itp = inotablookup(inum); | |
253 | if (itp == NULL) | |
254 | return(0); | |
255 | seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |
256 | len = strlen(cp); | |
257 | do { | |
258 | dp = readdir(dirp); | |
259 | if (dp->d_namlen == 1 && dp->d_name[0] == '/') | |
260 | return(0); | |
7432ff81 | 261 | } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); |
f743fc86 KM |
262 | return(dp->d_ino); |
263 | } | |
264 | ||
265 | /* | |
266 | * Put the directory entries in the directory file | |
267 | */ | |
268 | putdir(buf, size) | |
269 | char *buf; | |
270 | int size; | |
271 | { | |
272 | struct direct cvtbuf; | |
273 | register struct odirect *odp; | |
274 | struct odirect *eodp; | |
275 | register struct direct *dp; | |
276 | long loc, i; | |
277 | ||
278 | if (cvtflag) { | |
279 | eodp = (struct odirect *)&buf[size]; | |
280 | for (odp = (struct odirect *)buf; odp < eodp; odp++) | |
281 | if (odp->d_ino != 0) { | |
282 | dcvt(odp, &cvtbuf); | |
283 | putent(&cvtbuf); | |
284 | } | |
285 | } else { | |
286 | for (loc = 0; loc < size; ) { | |
287 | dp = (struct direct *)(buf + loc); | |
288 | i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); | |
289 | if (dp->d_reclen == 0 || dp->d_reclen > i) { | |
290 | loc += i; | |
291 | continue; | |
292 | } | |
293 | loc += dp->d_reclen; | |
294 | if (dp->d_ino != 0) { | |
295 | putent(dp); | |
296 | } | |
297 | } | |
298 | } | |
299 | } | |
300 | ||
301 | /* | |
302 | * These variables are "local" to the following two functions. | |
303 | */ | |
304 | char dirbuf[DIRBLKSIZ]; | |
305 | long dirloc = 0; | |
306 | long prev = 0; | |
307 | ||
308 | /* | |
309 | * add a new directory entry to a file. | |
310 | */ | |
311 | putent(dp) | |
312 | struct direct *dp; | |
313 | { | |
9730f69a | 314 | dp->d_reclen = DIRSIZ(dp); |
f743fc86 KM |
315 | if (dirloc + dp->d_reclen > DIRBLKSIZ) { |
316 | ((struct direct *)(dirbuf + prev))->d_reclen = | |
317 | DIRBLKSIZ - prev; | |
82d46726 | 318 | (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); |
f743fc86 KM |
319 | dirloc = 0; |
320 | } | |
321 | bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); | |
322 | prev = dirloc; | |
323 | dirloc += dp->d_reclen; | |
324 | } | |
325 | ||
326 | /* | |
327 | * flush out a directory that is finished. | |
328 | */ | |
329 | flushent() | |
330 | { | |
331 | ||
332 | ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; | |
82d46726 | 333 | (void) fwrite(dirbuf, (int)dirloc, 1, df); |
f743fc86 KM |
334 | seekpt = ftell(df); |
335 | dirloc = 0; | |
336 | } | |
337 | ||
338 | dcvt(odp, ndp) | |
339 | register struct odirect *odp; | |
340 | register struct direct *ndp; | |
341 | { | |
342 | ||
343 | bzero((char *)ndp, (long)(sizeof *ndp)); | |
344 | ndp->d_ino = odp->d_ino; | |
7432ff81 | 345 | (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); |
f743fc86 KM |
346 | ndp->d_namlen = strlen(ndp->d_name); |
347 | ndp->d_reclen = DIRSIZ(ndp); | |
f743fc86 KM |
348 | } |
349 | ||
350 | /* | |
351 | * Seek to an entry in a directory. | |
352 | * Only values returned by ``telldir'' should be passed to seekdir. | |
82d46726 KM |
353 | * This routine handles many directories in a single file. |
354 | * It takes the base of the directory in the file, plus | |
355 | * the desired seek offset into it. | |
f743fc86 KM |
356 | */ |
357 | void | |
358 | seekdir(dirp, loc, base) | |
359 | register DIR *dirp; | |
360 | daddr_t loc, base; | |
361 | { | |
362 | ||
363 | if (loc == telldir(dirp)) | |
364 | return; | |
365 | loc -= base; | |
366 | if (loc < 0) | |
367 | fprintf(stderr, "bad seek pointer to seekdir %d\n", loc); | |
368 | (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); | |
369 | dirp->dd_loc = loc & (DIRBLKSIZ - 1); | |
370 | if (dirp->dd_loc != 0) | |
371 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); | |
372 | } | |
373 | ||
374 | /* | |
375 | * get next entry in a directory. | |
376 | */ | |
377 | struct direct * | |
378 | readdir(dirp) | |
379 | register DIR *dirp; | |
380 | { | |
381 | register struct direct *dp; | |
382 | ||
383 | for (;;) { | |
384 | if (dirp->dd_loc == 0) { | |
385 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, | |
386 | DIRBLKSIZ); | |
387 | if (dirp->dd_size <= 0) | |
388 | return NULL; | |
389 | } | |
390 | if (dirp->dd_loc >= dirp->dd_size) { | |
391 | dirp->dd_loc = 0; | |
392 | continue; | |
393 | } | |
394 | dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); | |
395 | if (dp->d_reclen == 0 || | |
396 | dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) | |
397 | return NULL; | |
398 | dirp->dd_loc += dp->d_reclen; | |
f743fc86 KM |
399 | return (dp); |
400 | } | |
401 | } | |
402 | ||
403 | /* | |
404 | * Set the mode, owner, and times for all new or changed directories | |
405 | */ | |
7432ff81 | 406 | setdirmodes() |
f743fc86 KM |
407 | { |
408 | FILE *mf; | |
409 | struct modeinfo node; | |
410 | struct entry *ep; | |
411 | char *cp; | |
412 | ||
413 | vprintf(stdout, "Set directory mode, owner, and times.\n"); | |
414 | mf = fopen(modefile, "r"); | |
415 | if (mf == NULL) { | |
416 | perror("fopen"); | |
417 | panic("cannot open mode file %s\n", modefile); | |
418 | } | |
419 | clearerr(mf); | |
9f13f26d | 420 | for (;;) { |
82d46726 | 421 | (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); |
9f13f26d KM |
422 | if (feof(mf)) |
423 | break; | |
f743fc86 | 424 | ep = lookupino(node.ino); |
c03606b5 | 425 | if (ep == NIL) { |
7432ff81 | 426 | if (command != 'r' && command != 'R') |
9f13f26d | 427 | continue; |
f743fc86 | 428 | panic("cannot find directory inode %d\n", node.ino); |
9f13f26d | 429 | } |
f743fc86 | 430 | cp = myname(ep); |
82d46726 KM |
431 | (void) chown(cp, node.uid, node.gid); |
432 | (void) chmod(cp, node.mode); | |
f743fc86 | 433 | utime(cp, node.timep); |
7432ff81 | 434 | ep->e_flags &= ~NEW; |
f743fc86 KM |
435 | } |
436 | if (ferror(mf)) | |
437 | panic("error setting directory modes\n"); | |
82d46726 | 438 | (void) fclose(mf); |
f743fc86 KM |
439 | } |
440 | ||
441 | /* | |
442 | * Generate a literal copy of a directory. | |
443 | */ | |
444 | genliteraldir(name, ino) | |
445 | char *name; | |
446 | ino_t ino; | |
447 | { | |
448 | register struct inotab *itp; | |
449 | int ofile, dp, i, size; | |
450 | char buf[BUFSIZ]; | |
451 | ||
452 | itp = inotablookup(ino); | |
453 | if (itp == NULL) | |
9730f69a | 454 | panic("Cannot find directory inode %d named %s\n", ino, name); |
f743fc86 KM |
455 | if ((ofile = open(name, FWRONLY|FCREATE, 0666)) < 0) { |
456 | fprintf(stderr, "%s: cannot create file\n", name); | |
457 | return (FAIL); | |
458 | } | |
459 | seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |
460 | dp = dup(dirp->dd_fd); | |
461 | for (i = itp->t_size; i > 0; i -= BUFSIZ) { | |
462 | size = i < BUFSIZ ? i : BUFSIZ; | |
463 | if (read(dp, buf, (int) size) == -1) { | |
464 | fprintf(stderr, | |
465 | "write error extracting inode %d, name %s\n", | |
466 | curfile.ino, curfile.name); | |
467 | perror("read"); | |
468 | done(1); | |
469 | } | |
470 | if (write(ofile, buf, (int) size) == -1) { | |
471 | fprintf(stderr, | |
472 | "write error extracting inode %d, name %s\n", | |
473 | curfile.ino, curfile.name); | |
474 | perror("write"); | |
475 | done(1); | |
476 | } | |
477 | } | |
82d46726 KM |
478 | (void) close(dp); |
479 | (void) close(ofile); | |
f743fc86 KM |
480 | return (GOOD); |
481 | } | |
482 | ||
7432ff81 KM |
483 | /* |
484 | * Do an "ls" style listing of a directory | |
485 | */ | |
486 | printlist(name, ino) | |
487 | char *name; | |
488 | ino_t ino; | |
489 | { | |
490 | register struct afile *fp; | |
491 | register struct inotab *itp; | |
492 | struct afile *dfp0, *dfplast; | |
493 | struct afile single; | |
494 | ||
495 | itp = inotablookup(ino); | |
496 | if (itp == NULL) { | |
497 | single.fnum = ino; | |
498 | single.fname = savename(rindex(name, '/') + 1); | |
499 | dfp0 = &single; | |
500 | dfplast = dfp0 + 1; | |
501 | } else { | |
502 | seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |
503 | if (getdir(dirp, &dfp0, &dfplast) == FAIL) | |
504 | return; | |
505 | } | |
506 | qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp); | |
507 | formatf(dfp0, dfplast); | |
508 | for (fp = dfp0; fp < dfplast; fp++) | |
509 | freename(fp->fname); | |
510 | } | |
511 | ||
512 | /* | |
513 | * Read the contents of a directory. | |
514 | */ | |
515 | getdir(dirp, pfp0, pfplast) | |
516 | DIR *dirp; | |
517 | struct afile **pfp0, **pfplast; | |
518 | { | |
519 | register struct afile *fp; | |
520 | register struct direct *dp; | |
521 | static struct afile *basefp = NULL; | |
522 | static long nent = 20; | |
523 | ||
524 | if (basefp == NULL) | |
525 | basefp = (struct afile *)calloc((unsigned)nent, | |
526 | sizeof (struct afile)); | |
527 | fp = *pfp0 = basefp; | |
528 | *pfplast = *pfp0 + nent; | |
529 | while (dp = readdir(dirp)) { | |
530 | if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) | |
531 | break; | |
532 | if (BIT(dp->d_ino, dumpmap) == 0) | |
533 | continue; | |
534 | if (vflag == 0 && | |
535 | (strcmp(dp->d_name, ".") == 0 || | |
536 | strcmp(dp->d_name, "..") == 0)) | |
537 | continue; | |
538 | fp->fnum = dp->d_ino; | |
539 | fp->fname = savename(dp->d_name); | |
540 | fp++; | |
541 | if (fp == *pfplast) { | |
542 | basefp = (struct afile *)realloc((char *)basefp, | |
543 | (unsigned)(2 * nent * sizeof (struct afile))); | |
544 | if (basefp == 0) { | |
545 | fprintf(stderr, "ls: out of memory\n"); | |
546 | return (FAIL); | |
547 | } | |
548 | *pfp0 = basefp; | |
549 | fp = *pfp0 + nent; | |
550 | *pfplast = fp + nent; | |
551 | nent *= 2; | |
552 | } | |
553 | } | |
554 | *pfplast = fp; | |
555 | return (GOOD); | |
556 | } | |
557 | ||
558 | /* | |
559 | * Print out a pretty listing of a directory | |
560 | */ | |
561 | formatf(fp0, fplast) | |
562 | struct afile *fp0, *fplast; | |
563 | { | |
564 | register struct afile *fp; | |
565 | struct entry *np; | |
566 | int width = 0, w, nentry = fplast - fp0; | |
567 | int i, j, len, columns, lines; | |
568 | char *cp; | |
569 | ||
570 | if (fp0 == fplast) | |
571 | return; | |
572 | for (fp = fp0; fp < fplast; fp++) { | |
573 | fp->ftype = inodetype(fp->fnum); | |
574 | np = lookupino(fp->fnum); | |
575 | if (np != NIL) | |
576 | fp->fflags = np->e_flags; | |
577 | else | |
578 | fp->fflags = 0; | |
579 | len = strlen(fmtentry(fp)); | |
580 | if (len > width) | |
581 | width = len; | |
582 | } | |
583 | width += 2; | |
584 | columns = 80 / width; | |
585 | if (columns == 0) | |
586 | columns = 1; | |
587 | lines = (nentry + columns - 1) / columns; | |
588 | for (i = 0; i < lines; i++) { | |
589 | for (j = 0; j < columns; j++) { | |
590 | fp = fp0 + j * lines + i; | |
591 | cp = fmtentry(fp); | |
592 | fprintf(stderr, "%s", cp); | |
593 | if (fp + lines >= fplast) { | |
594 | fprintf(stderr, "\n"); | |
595 | break; | |
596 | } | |
597 | w = strlen(cp); | |
598 | while (w < width) { | |
599 | w++; | |
600 | fprintf(stderr, " "); | |
601 | } | |
602 | } | |
603 | } | |
604 | } | |
605 | ||
606 | /* | |
607 | * Comparison routine for qsort. | |
608 | */ | |
609 | fcmp(f1, f2) | |
610 | register struct afile *f1, *f2; | |
611 | { | |
612 | ||
613 | return (strcmp(f1->fname, f2->fname)); | |
614 | } | |
615 | ||
616 | /* | |
617 | * Format a directory entry. | |
618 | */ | |
619 | char * | |
620 | fmtentry(fp) | |
621 | register struct afile *fp; | |
622 | { | |
623 | static char fmtres[BUFSIZ]; | |
624 | register char *cp, *dp; | |
625 | ||
626 | if (vflag) | |
627 | (void) sprintf(fmtres, "%5d ", fp->fnum); | |
628 | else | |
629 | fmtres[0] = '\0'; | |
630 | dp = &fmtres[strlen(fmtres)]; | |
631 | if ((fp->fflags & NEW) != 0) | |
632 | *dp++ = '*'; | |
633 | else | |
634 | *dp++ = ' '; | |
635 | for (cp = fp->fname; *cp; cp++) | |
636 | if (!vflag && (*cp < ' ' || *cp >= 0177)) | |
637 | *dp++ = '?'; | |
638 | else | |
639 | *dp++ = *cp; | |
640 | if (fp->ftype == NODE) | |
641 | *dp++ = '/'; | |
642 | *dp++ = 0; | |
643 | return (fmtres); | |
644 | } | |
645 | ||
646 | /* | |
647 | * Determine the type of an inode | |
648 | */ | |
649 | inodetype(ino) | |
650 | ino_t ino; | |
651 | { | |
652 | struct inotab *itp; | |
653 | ||
654 | itp = inotablookup(ino); | |
655 | if (itp == NULL) | |
656 | return (LEAF); | |
657 | return (NODE); | |
658 | } | |
659 | ||
f743fc86 KM |
660 | /* |
661 | * Allocate and initialize a directory inode entry. | |
662 | * If requested, save its pertinent mode, owner, and time info. | |
663 | */ | |
9730f69a | 664 | struct inotab * |
f743fc86 KM |
665 | allocinotab(ino, dip, seekpt) |
666 | ino_t ino; | |
667 | struct dinode *dip; | |
668 | daddr_t seekpt; | |
669 | { | |
670 | register struct inotab *itp; | |
671 | struct modeinfo node; | |
f743fc86 KM |
672 | |
673 | itp = (struct inotab *)calloc(1, sizeof(struct inotab)); | |
674 | itp->t_next = inotab[INOHASH(ino)]; | |
675 | inotab[INOHASH(ino)] = itp; | |
676 | itp->t_ino = ino; | |
677 | itp->t_seekpt = seekpt; | |
f743fc86 | 678 | if (mf == NULL) |
9730f69a | 679 | return(itp); |
f743fc86 KM |
680 | node.ino = ino; |
681 | node.timep[0] = dip->di_atime; | |
682 | node.timep[1] = dip->di_mtime; | |
683 | node.mode = dip->di_mode; | |
684 | node.uid = dip->di_uid; | |
685 | node.gid = dip->di_gid; | |
82d46726 | 686 | (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); |
9730f69a | 687 | return(itp); |
f743fc86 KM |
688 | } |
689 | ||
690 | /* | |
691 | * Look up an inode in the table of directories | |
692 | */ | |
693 | struct inotab * | |
694 | inotablookup(ino) | |
695 | ino_t ino; | |
696 | { | |
697 | register struct inotab *itp; | |
698 | ||
699 | for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) | |
700 | if (itp->t_ino == ino) | |
701 | return(itp); | |
702 | return ((struct inotab *)0); | |
703 | } | |
704 | ||
705 | /* | |
706 | * Clean up and exit | |
707 | */ | |
708 | done(exitcode) | |
709 | int exitcode; | |
710 | { | |
711 | ||
712 | closemt(); | |
7432ff81 KM |
713 | if (modefile[0] != '#') |
714 | (void) unlink(modefile); | |
715 | if (dirfile[0] != '#') | |
716 | (void) unlink(dirfile); | |
f743fc86 KM |
717 | exit(exitcode); |
718 | } |