|
|
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.1 (Berkeley) 6/5/85";
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:
28: descend(parentino, inumber)
29: struct inodesc *parentino;
30: ino_t inumber;
31: {
32: register DINODE *dp;
33: struct inodesc curino;
34:
35: bzero((char *)&curino, sizeof(struct inodesc));
36: if (statemap[inumber] != DSTATE)
37: errexit("BAD INODE %d TO DESCEND", statemap[inumber]);
38: statemap[inumber] = DFOUND;
39: dp = ginode(inumber);
40: if (dp->di_size == 0) {
41: direrr(inumber, "ZERO LENGTH DIRECTORY");
42: if (reply("REMOVE") == 1)
43: statemap[inumber] = DCLEAR;
44: return;
45: }
46: if (dp->di_size < MINDIRSIZE) {
47: direrr(inumber, "DIRECTORY TOO SHORT");
48: dp->di_size = MINDIRSIZE;
49: if (reply("FIX") == 1)
50: inodirty();
51: }
52: if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) {
53: pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
54: pathname, dp->di_size, DIRBLKSIZ);
55: dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
56: if (preen)
57: printf(" (ADJUSTED)\n");
58: if (preen || reply("ADJUST") == 1)
59: inodirty();
60: }
61: curino.id_type = DATA;
62: curino.id_func = parentino->id_func;
63: curino.id_parent = parentino->id_number;
64: curino.id_number = inumber;
65: (void)ckinode(dp, &curino);
66: }
67:
68: dirscan(idesc)
69: register struct inodesc *idesc;
70: {
71: register DIRECT *dp;
72: int dsize, n;
73: long blksiz;
74: char dbuf[DIRBLKSIZ];
75:
76: if (idesc->id_type != DATA)
77: errexit("wrong type to dirscan %d\n", idesc->id_type);
78: if (idesc->id_entryno == 0 &&
79: (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
80: idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
81: blksiz = idesc->id_numfrags * sblock.fs_fsize;
82: if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
83: idesc->id_filesize -= blksiz;
84: return (SKIP);
85: }
86: idesc->id_loc = 0;
87: for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
88: dsize = dp->d_reclen;
89: bcopy((char *)dp, dbuf, dsize);
90: idesc->id_dirp = (DIRECT *)dbuf;
91: if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
92: getblk(&fileblk, idesc->id_blkno, blksiz);
93: if (fileblk.b_errs != NULL) {
94: n &= ~ALTERED;
95: } else {
96: bcopy(dbuf, (char *)dp, dsize);
97: dirty(&fileblk);
98: sbdirty();
99: }
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: DIRECT *
111: fsck_readdir(idesc)
112: register struct inodesc *idesc;
113: {
114: register DIRECT *dp, *ndp;
115: long size, blksiz;
116:
117: blksiz = idesc->id_numfrags * sblock.fs_fsize;
118: getblk(&fileblk, idesc->id_blkno, blksiz);
119: if (fileblk.b_errs != NULL) {
120: idesc->id_filesize -= blksiz - idesc->id_loc;
121: return NULL;
122: }
123: if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
124: idesc->id_loc < blksiz) {
125: dp = (DIRECT *)(dirblk.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(&fileblk);
136: return (dp);
137: }
138: dpok:
139: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
140: return NULL;
141: dp = (DIRECT *)(dirblk.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 *)(dirblk.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(&fileblk);
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: (void)ckinode(dp, &idesc);
310: if (idesc.id_parent >= ROOTINO && idesc.id_parent < imax) {
311: lfdir = idesc.id_parent;
312: } else {
313: pwarn("NO lost+found DIRECTORY");
314: if (preen || reply("CREATE")) {
315: lfdir = allocdir(ROOTINO, 0);
316: if (lfdir != 0) {
317: if (makeentry(ROOTINO, lfdir, lfname) != 0) {
318: if (preen)
319: printf(" (CREATED)\n");
320: } else {
321: freedir(lfdir, ROOTINO);
322: lfdir = 0;
323: if (preen)
324: printf("\n");
325: }
326: }
327: }
328: }
329: if (lfdir == 0) {
330: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
331: printf("\n\n");
332: return (0);
333: }
334: }
335: dp = ginode(lfdir);
336: if (!DIRCT(dp)) {
337: pfatal("lost+found IS NOT A DIRECTORY");
338: if (reply("REALLOCATE") == 0)
339: return (0);
340: oldlfdir = lfdir;
341: if ((lfdir = allocdir(ROOTINO, 0)) == 0) {
342: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
343: return (0);
344: }
345: idesc.id_type = DATA;
346: idesc.id_func = chgino;
347: idesc.id_number = ROOTINO;
348: idesc.id_parent = lfdir; /* new inumber for lost+found */
349: idesc.id_name = lfname;
350: if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) {
351: pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
352: return (0);
353: }
354: inodirty();
355: idesc.id_type = ADDR;
356: idesc.id_func = pass4check;
357: idesc.id_number = oldlfdir;
358: adjust(&idesc, lncntp[oldlfdir] + 1);
359: lncntp[oldlfdir] = 0;
360: dp = ginode(lfdir);
361: }
362: if (statemap[lfdir] != DFOUND) {
363: pfatal("SORRY. NO lost+found DIRECTORY\n\n");
364: return (0);
365: }
366: len = strlen(lfname);
367: bcopy(lfname, pathp, len + 1);
368: pathp += len;
369: len = lftempname(tempname, orphan);
370: if (makeentry(lfdir, orphan, tempname) == 0) {
371: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
372: printf("\n\n");
373: return (0);
374: }
375: lncntp[orphan]--;
376: *pathp++ = '/';
377: bcopy(idesc.id_name, pathp, len + 1);
378: pathp += len;
379: if (lostdir) {
380: dp = ginode(orphan);
381: idesc.id_type = DATA;
382: idesc.id_func = chgino;
383: idesc.id_number = orphan;
384: idesc.id_fix = DONTKNOW;
385: idesc.id_name = "..";
386: idesc.id_parent = lfdir; /* new value for ".." */
387: (void)ckinode(dp, &idesc);
388: dp = ginode(lfdir);
389: dp->di_nlink++;
390: inodirty();
391: lncntp[lfdir]++;
392: pwarn("DIR I=%u CONNECTED. ", orphan);
393: printf("PARENT WAS I=%u\n", pdir);
394: if (preen == 0)
395: printf("\n");
396: }
397: return (1);
398: }
399:
400: /*
401: * make an entry in a directory
402: */
403: makeentry(parent, ino, name)
404: ino_t parent, ino;
405: char *name;
406: {
407: DINODE *dp;
408: struct inodesc idesc;
409:
410: if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax)
411: return (0);
412: bzero(&idesc, sizeof(struct inodesc));
413: idesc.id_type = DATA;
414: idesc.id_func = mkentry;
415: idesc.id_number = parent;
416: idesc.id_parent = ino; /* this is the inode to enter */
417: idesc.id_fix = DONTKNOW;
418: idesc.id_name = name;
419: dp = ginode(parent);
420: if (dp->di_size % DIRBLKSIZ) {
421: dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
422: inodirty();
423: }
424: if ((ckinode(dp, &idesc) & ALTERED) != 0)
425: return (1);
426: if (expanddir(dp) == 0)
427: return (0);
428: return (ckinode(dp, &idesc) & ALTERED);
429: }
430:
431: /*
432: * Attempt to expand the size of a directory
433: */
434: expanddir(dp)
435: register DINODE *dp;
436: {
437: daddr_t lastbn, newblk;
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: getblk(&fileblk, dp->di_db[lastbn + 1],
450: dblksize(&sblock, dp, lastbn + 1));
451: if (fileblk.b_errs != NULL)
452: goto bad;
453: bcopy(dirblk.b_buf, firstblk, DIRBLKSIZ);
454: getblk(&fileblk, newblk, sblock.fs_bsize);
455: if (fileblk.b_errs != NULL)
456: goto bad;
457: bcopy(firstblk, dirblk.b_buf, DIRBLKSIZ);
458: for (cp = &dirblk.b_buf[DIRBLKSIZ];
459: cp < &dirblk.b_buf[sblock.fs_bsize];
460: cp += DIRBLKSIZ)
461: bcopy((char *)&emptydir, cp, sizeof emptydir);
462: dirty(&fileblk);
463: getblk(&fileblk, dp->di_db[lastbn + 1],
464: dblksize(&sblock, dp, lastbn + 1));
465: if (fileblk.b_errs != NULL)
466: goto bad;
467: bcopy((char *)&emptydir, dirblk.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(&fileblk);
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:
495: ino = allocino(request, IFDIR|0755);
496: dirhead.dot_ino = ino;
497: dirhead.dotdot_ino = parent;
498: dp = ginode(ino);
499: getblk(&fileblk, dp->di_db[0], sblock.fs_fsize);
500: if (fileblk.b_errs != NULL) {
501: freeino(ino);
502: return (0);
503: }
504: bcopy((char *)&dirhead, dirblk.b_buf, sizeof dirhead);
505: for (cp = &dirblk.b_buf[DIRBLKSIZ];
506: cp < &dirblk.b_buf[sblock.fs_fsize];
507: cp += DIRBLKSIZ)
508: bcopy((char *)&emptydir, cp, sizeof emptydir);
509: dirty(&fileblk);
510: dp->di_nlink = 2;
511: inodirty();
512: if (ino == ROOTINO) {
513: lncntp[ino] = dp->di_nlink;
514: return(ino);
515: }
516: if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
517: freeino(ino);
518: return (0);
519: }
520: statemap[ino] = statemap[parent];
521: if (statemap[ino] == DSTATE) {
522: lncntp[ino] = dp->di_nlink;
523: lncntp[parent]++;
524: }
525: dp = ginode(parent);
526: dp->di_nlink++;
527: inodirty();
528: return (ino);
529: }
530:
531: /*
532: * free a directory inode
533: */
534: freedir(ino, parent)
535: ino_t ino, parent;
536: {
537: DINODE *dp;
538:
539: if (ino != parent) {
540: dp = ginode(parent);
541: dp->di_nlink--;
542: inodirty();
543: }
544: freeino(ino);
545: }
546:
547: /*
548: * generate a temporary name for the lost+found directory.
549: */
550: lftempname(bufp, ino)
551: char *bufp;
552: ino_t ino;
553: {
554: register ino_t in;
555: register char *cp;
556: int namlen;
557:
558: cp = bufp + 2;
559: for (in = imax; in > 0; in /= 10)
560: cp++;
561: *--cp = 0;
562: namlen = cp - bufp;
563: in = ino;
564: while (cp > bufp) {
565: *--cp = (in % 10) + '0';
566: in /= 10;
567: }
568: *cp = '#';
569: return (namlen);
570: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.