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