|
|
1.1 root 1: /*
2: * Copyright (c) 1980, 1986 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)dir.c 5.18 (Berkeley) 7/20/90";
22: #endif /* not lint */
23:
24: #include <sys/param.h>
25: #include <ufs/dinode.h>
26: #include <ufs/fs.h>
27: #define KERNEL
28: #include <ufs/dir.h>
29: #undef KERNEL
30: #include <stdlib.h>
31: #include <string.h>
32: #include "fsck.h"
33:
34: char *lfname = "lost+found";
35: int lfmode = 01777;
36: struct dirtemplate emptydir = { 0, DIRBLKSIZ };
37: struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
38:
39: struct direct *fsck_readdir();
40: struct bufarea *getdirblk();
41:
42: /*
43: * Propagate connected state through the tree.
44: */
45: propagate()
46: {
47: register struct inoinfo **inpp, *inp;
48: struct inoinfo **inpend;
49: long change;
50:
51: inpend = &inpsort[inplast];
52: do {
53: change = 0;
54: for (inpp = inpsort; inpp < inpend; inpp++) {
55: inp = *inpp;
56: if (inp->i_parent == 0)
57: continue;
58: if (statemap[inp->i_parent] == DFOUND &&
59: statemap[inp->i_number] == DSTATE) {
60: statemap[inp->i_number] = DFOUND;
61: change++;
62: }
63: }
64: } while (change > 0);
65: }
66:
67: /*
68: * Scan each entry in a directory block.
69: */
70: dirscan(idesc)
71: register struct inodesc *idesc;
72: {
73: register struct direct *dp;
74: register struct bufarea *bp;
75: int dsize, n;
76: long blksiz;
77: char dbuf[DIRBLKSIZ];
78:
79: if (idesc->id_type != DATA)
80: errexit("wrong type to dirscan %d\n", idesc->id_type);
81: if (idesc->id_entryno == 0 &&
82: (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
83: idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
84: blksiz = idesc->id_numfrags * sblock.fs_fsize;
85: if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
86: idesc->id_filesize -= blksiz;
87: return (SKIP);
88: }
89: idesc->id_loc = 0;
90: for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
91: dsize = dp->d_reclen;
92: bcopy((char *)dp, dbuf, (size_t)dsize);
93: idesc->id_dirp = (struct direct *)dbuf;
94: if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
95: bp = getdirblk(idesc->id_blkno, blksiz);
96: bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize,
97: (size_t)dsize);
98: dirty(bp);
99: sbdirty();
100: }
101: if (n & STOP)
102: return (n);
103: }
104: return (idesc->id_filesize > 0 ? KEEPON : STOP);
105: }
106:
107: /*
108: * get next entry in a directory.
109: */
110: struct direct *
111: fsck_readdir(idesc)
112: register struct inodesc *idesc;
113: {
114: register struct direct *dp, *ndp;
115: register struct bufarea *bp;
116: long size, blksiz, fix;
117:
118: blksiz = idesc->id_numfrags * sblock.fs_fsize;
119: bp = getdirblk(idesc->id_blkno, blksiz);
120: if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
121: idesc->id_loc < blksiz) {
122: dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
123: if (dircheck(idesc, dp))
124: goto dpok;
125: idesc->id_loc += DIRBLKSIZ;
126: idesc->id_filesize -= DIRBLKSIZ;
127: fix = dofix(idesc, "DIRECTORY CORRUPTED");
128: bp = getdirblk(idesc->id_blkno, blksiz);
129: dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
130: dp->d_reclen = DIRBLKSIZ;
131: dp->d_ino = 0;
132: dp->d_namlen = 0;
133: dp->d_name[0] = '\0';
134: if (fix)
135: dirty(bp);
136: return (dp);
137: }
138: dpok:
139: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
140: return NULL;
141: dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
142: idesc->id_loc += dp->d_reclen;
143: idesc->id_filesize -= dp->d_reclen;
144: if ((idesc->id_loc % DIRBLKSIZ) == 0)
145: return (dp);
146: ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
147: if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
148: dircheck(idesc, ndp) == 0) {
149: size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
150: idesc->id_loc += size;
151: idesc->id_filesize -= size;
152: fix = dofix(idesc, "DIRECTORY CORRUPTED");
153: bp = getdirblk(idesc->id_blkno, blksiz);
154: dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
155: dp->d_reclen += size;
156: if (fix)
157: dirty(bp);
158: }
159: return (dp);
160: }
161:
162: /*
163: * Verify that a directory entry is valid.
164: * This is a superset of the checks made in the kernel.
165: */
166: dircheck(idesc, dp)
167: struct inodesc *idesc;
168: register struct direct *dp;
169: {
170: register int size;
171: register char *cp;
172: int spaceleft;
173:
174: size = DIRSIZ(dp);
175: spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
176: if (dp->d_ino < maxino &&
177: dp->d_reclen != 0 &&
178: dp->d_reclen <= spaceleft &&
179: (dp->d_reclen & 0x3) == 0 &&
180: dp->d_reclen >= size &&
181: idesc->id_filesize >= size &&
182: dp->d_namlen <= MAXNAMLEN) {
183: if (dp->d_ino == 0)
184: return (1);
185: for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
186: if (*cp == 0 || (*cp++ == '/'))
187: return (0);
188: if (*cp == 0)
189: return (1);
190: }
191: return (0);
192: }
193:
194: direrror(ino, errmesg)
195: ino_t ino;
196: char *errmesg;
197: {
198:
199: fileerror(ino, ino, errmesg);
200: }
201:
202: fileerror(cwd, ino, errmesg)
203: ino_t cwd, ino;
204: char *errmesg;
205: {
206: register struct dinode *dp;
207: char pathbuf[MAXPATHLEN + 1];
208:
209: pwarn("%s ", errmesg);
210: pinode(ino);
211: printf("\n");
212: getpathname(pathbuf, cwd, ino);
213: if (ino < ROOTINO || ino > maxino) {
214: pfatal("NAME=%s\n", pathbuf);
215: return;
216: }
217: dp = ginode(ino);
218: if (ftypeok(dp))
219: pfatal("%s=%s\n",
220: (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
221: else
222: pfatal("NAME=%s\n", pathbuf);
223: }
224:
225: adjust(idesc, lcnt)
226: register struct inodesc *idesc;
227: short lcnt;
228: {
229: register struct dinode *dp;
230:
231: dp = ginode(idesc->id_number);
232: if (dp->di_nlink == lcnt) {
233: if (linkup(idesc->id_number, (ino_t)0) == 0)
234: clri(idesc, "UNREF", 0);
235: } else {
236: pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
237: ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
238: pinode(idesc->id_number);
239: printf(" COUNT %d SHOULD BE %d",
240: dp->di_nlink, dp->di_nlink - lcnt);
241: if (preen) {
242: if (lcnt < 0) {
243: printf("\n");
244: pfatal("LINK COUNT INCREASING");
245: }
246: printf(" (ADJUSTED)\n");
247: }
248: if (preen || reply("ADJUST") == 1) {
249: dp->di_nlink -= lcnt;
250: inodirty();
251: }
252: }
253: }
254:
255: mkentry(idesc)
256: struct inodesc *idesc;
257: {
258: register struct direct *dirp = idesc->id_dirp;
259: struct direct newent;
260: int newlen, oldlen;
261:
262: newent.d_namlen = strlen(idesc->id_name);
263: newlen = DIRSIZ(&newent);
264: if (dirp->d_ino != 0)
265: oldlen = DIRSIZ(dirp);
266: else
267: oldlen = 0;
268: if (dirp->d_reclen - oldlen < newlen)
269: return (KEEPON);
270: newent.d_reclen = dirp->d_reclen - oldlen;
271: dirp->d_reclen = oldlen;
272: dirp = (struct direct *)(((char *)dirp) + oldlen);
273: dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
274: dirp->d_reclen = newent.d_reclen;
275: dirp->d_namlen = newent.d_namlen;
276: bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
277: return (ALTERED|STOP);
278: }
279:
280: chgino(idesc)
281: struct inodesc *idesc;
282: {
283: register struct direct *dirp = idesc->id_dirp;
284:
285: if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
286: return (KEEPON);
287: dirp->d_ino = idesc->id_parent;
288: return (ALTERED|STOP);
289: }
290:
291: linkup(orphan, parentdir)
292: ino_t orphan;
293: ino_t parentdir;
294: {
295: register struct dinode *dp;
296: int lostdir;
297: ino_t oldlfdir;
298: struct inodesc idesc;
299: char tempname[BUFSIZ];
300: extern int pass4check();
301:
302: bzero((char *)&idesc, sizeof(struct inodesc));
303: dp = ginode(orphan);
304: lostdir = (dp->di_mode & IFMT) == IFDIR;
305: pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
306: pinode(orphan);
307: if (preen && dp->di_size == 0)
308: return (0);
309: if (preen)
310: printf(" (RECONNECTED)\n");
311: else
312: if (reply("RECONNECT") == 0)
313: return (0);
314: if (lfdir == 0) {
315: dp = ginode(ROOTINO);
316: idesc.id_name = lfname;
317: idesc.id_type = DATA;
318: idesc.id_func = findino;
319: idesc.id_number = ROOTINO;
320: if ((ckinode(dp, &idesc) & FOUND) != 0) {
321: lfdir = idesc.id_parent;
322: } else {
323: pwarn("NO lost+found DIRECTORY");
324: if (preen || reply("CREATE")) {
325: lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
326: if (lfdir != 0) {
327: if (makeentry(ROOTINO, lfdir, lfname) != 0) {
328: if (preen)
329: printf(" (CREATED)\n");
330: } else {
331: freedir(lfdir, ROOTINO);
332: lfdir = 0;
333: if (preen)
334: printf("\n");
335: }
336: }
337: }
338: }
339: if (lfdir == 0) {
340: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
341: printf("\n\n");
342: return (0);
343: }
344: }
345: dp = ginode(lfdir);
346: if ((dp->di_mode & IFMT) != IFDIR) {
347: pfatal("lost+found IS NOT A DIRECTORY");
348: if (reply("REALLOCATE") == 0)
349: return (0);
350: oldlfdir = lfdir;
351: if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
352: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
353: return (0);
354: }
355: if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
356: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
357: return (0);
358: }
359: inodirty();
360: idesc.id_type = ADDR;
361: idesc.id_func = pass4check;
362: idesc.id_number = oldlfdir;
363: adjust(&idesc, lncntp[oldlfdir] + 1);
364: lncntp[oldlfdir] = 0;
365: dp = ginode(lfdir);
366: }
367: if (statemap[lfdir] != DFOUND) {
368: pfatal("SORRY. NO lost+found DIRECTORY\n\n");
369: return (0);
370: }
371: (void)lftempname(tempname, orphan);
372: if (makeentry(lfdir, orphan, tempname) == 0) {
373: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
374: printf("\n\n");
375: return (0);
376: }
377: lncntp[orphan]--;
378: if (lostdir) {
379: if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
380: parentdir != (ino_t)-1)
381: (void)makeentry(orphan, lfdir, "..");
382: dp = ginode(lfdir);
383: dp->di_nlink++;
384: inodirty();
385: lncntp[lfdir]++;
386: pwarn("DIR I=%lu CONNECTED. ", orphan);
387: if (parentdir != (ino_t)-1)
388: printf("PARENT WAS I=%lu\n", parentdir);
389: if (preen == 0)
390: printf("\n");
391: }
392: return (1);
393: }
394:
395: /*
396: * fix an entry in a directory.
397: */
398: changeino(dir, name, newnum)
399: ino_t dir;
400: char *name;
401: ino_t newnum;
402: {
403: struct inodesc idesc;
404:
405: bzero((char *)&idesc, sizeof(struct inodesc));
406: idesc.id_type = DATA;
407: idesc.id_func = chgino;
408: idesc.id_number = dir;
409: idesc.id_fix = DONTKNOW;
410: idesc.id_name = name;
411: idesc.id_parent = newnum; /* new value for name */
412: return (ckinode(ginode(dir), &idesc));
413: }
414:
415: /*
416: * make an entry in a directory
417: */
418: makeentry(parent, ino, name)
419: ino_t parent, ino;
420: char *name;
421: {
422: struct dinode *dp;
423: struct inodesc idesc;
424: char pathbuf[MAXPATHLEN + 1];
425:
426: if (parent < ROOTINO || parent >= maxino ||
427: ino < ROOTINO || ino >= maxino)
428: return (0);
429: bzero((char *)&idesc, sizeof(struct inodesc));
430: idesc.id_type = DATA;
431: idesc.id_func = mkentry;
432: idesc.id_number = parent;
433: idesc.id_parent = ino; /* this is the inode to enter */
434: idesc.id_fix = DONTKNOW;
435: idesc.id_name = name;
436: dp = ginode(parent);
437: if (dp->di_size % DIRBLKSIZ) {
438: dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
439: inodirty();
440: }
441: if ((ckinode(dp, &idesc) & ALTERED) != 0)
442: return (1);
443: getpathname(pathbuf, parent, parent);
444: dp = ginode(parent);
445: if (expanddir(dp, pathbuf) == 0)
446: return (0);
447: return (ckinode(dp, &idesc) & ALTERED);
448: }
449:
450: /*
451: * Attempt to expand the size of a directory
452: */
453: expanddir(dp, name)
454: register struct dinode *dp;
455: char *name;
456: {
457: daddr_t lastbn, newblk;
458: register struct bufarea *bp;
459: char *cp, firstblk[DIRBLKSIZ];
460:
461: lastbn = lblkno(&sblock, dp->di_size);
462: if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
463: return (0);
464: if ((newblk = allocblk(sblock.fs_frag)) == 0)
465: return (0);
466: dp->di_db[lastbn + 1] = dp->di_db[lastbn];
467: dp->di_db[lastbn] = newblk;
468: dp->di_size += sblock.fs_bsize;
469: dp->di_blocks += btodb(sblock.fs_bsize);
470: bp = getdirblk(dp->di_db[lastbn + 1],
471: (long)dblksize(&sblock, dp, lastbn + 1));
472: if (bp->b_errs)
473: goto bad;
474: bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
475: bp = getdirblk(newblk, sblock.fs_bsize);
476: if (bp->b_errs)
477: goto bad;
478: bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
479: for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
480: cp < &bp->b_un.b_buf[sblock.fs_bsize];
481: cp += DIRBLKSIZ)
482: bcopy((char *)&emptydir, cp, sizeof emptydir);
483: dirty(bp);
484: bp = getdirblk(dp->di_db[lastbn + 1],
485: (long)dblksize(&sblock, dp, lastbn + 1));
486: if (bp->b_errs)
487: goto bad;
488: bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
489: pwarn("NO SPACE LEFT IN %s", name);
490: if (preen)
491: printf(" (EXPANDED)\n");
492: else if (reply("EXPAND") == 0)
493: goto bad;
494: dirty(bp);
495: inodirty();
496: return (1);
497: bad:
498: dp->di_db[lastbn] = dp->di_db[lastbn + 1];
499: dp->di_db[lastbn + 1] = 0;
500: dp->di_size -= sblock.fs_bsize;
501: dp->di_blocks -= btodb(sblock.fs_bsize);
502: freeblk(newblk, sblock.fs_frag);
503: return (0);
504: }
505:
506: /*
507: * allocate a new directory
508: */
509: allocdir(parent, request, mode)
510: ino_t parent, request;
511: int mode;
512: {
513: ino_t ino;
514: char *cp;
515: struct dinode *dp;
516: register struct bufarea *bp;
517:
518: ino = allocino(request, IFDIR|mode);
519: dirhead.dot_ino = ino;
520: dirhead.dotdot_ino = parent;
521: dp = ginode(ino);
522: bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
523: if (bp->b_errs) {
524: freeino(ino);
525: return (0);
526: }
527: bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead);
528: for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
529: cp < &bp->b_un.b_buf[sblock.fs_fsize];
530: cp += DIRBLKSIZ)
531: bcopy((char *)&emptydir, cp, sizeof emptydir);
532: dirty(bp);
533: dp->di_nlink = 2;
534: inodirty();
535: if (ino == ROOTINO) {
536: lncntp[ino] = dp->di_nlink;
537: return(ino);
538: }
539: if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
540: freeino(ino);
541: return (0);
542: }
543: statemap[ino] = statemap[parent];
544: if (statemap[ino] == DSTATE) {
545: lncntp[ino] = dp->di_nlink;
546: lncntp[parent]++;
547: }
548: dp = ginode(parent);
549: dp->di_nlink++;
550: inodirty();
551: return (ino);
552: }
553:
554: /*
555: * free a directory inode
556: */
557: freedir(ino, parent)
558: ino_t ino, parent;
559: {
560: struct dinode *dp;
561:
562: if (ino != parent) {
563: dp = ginode(parent);
564: dp->di_nlink--;
565: inodirty();
566: }
567: freeino(ino);
568: }
569:
570: /*
571: * generate a temporary name for the lost+found directory.
572: */
573: lftempname(bufp, ino)
574: char *bufp;
575: ino_t ino;
576: {
577: register ino_t in;
578: register char *cp;
579: int namlen;
580:
581: cp = bufp + 2;
582: for (in = maxino; in > 0; in /= 10)
583: cp++;
584: *--cp = 0;
585: namlen = cp - bufp;
586: in = ino;
587: while (cp > bufp) {
588: *--cp = (in % 10) + '0';
589: in /= 10;
590: }
591: *cp = '#';
592: return (namlen);
593: }
594:
595: /*
596: * Get a directory block.
597: * Insure that it is held until another is requested.
598: */
599: struct bufarea *
600: getdirblk(blkno, size)
601: daddr_t blkno;
602: long size;
603: {
604:
605: if (pdirbp != 0)
606: pdirbp->b_flags &= ~B_INUSE;
607: pdirbp = getdatablk(blkno, size);
608: return (pdirbp);
609: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.