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