1*22050Sdist /* 2*22050Sdist * Copyright (c) 1980 Regents of the University of California. 3*22050Sdist * All rights reserved. The Berkeley software License Agreement 4*22050Sdist * specifies the terms and conditions for redistribution. 5*22050Sdist */ 6*22050Sdist 716264Smckusick #ifndef lint 8*22050Sdist static char sccsid[] = "@(#)pass2.c 5.1 (Berkeley) 06/05/85"; 9*22050Sdist #endif not lint 1016264Smckusick 1116264Smckusick #include <sys/param.h> 1216264Smckusick #include <sys/inode.h> 1316264Smckusick #include <sys/fs.h> 1416264Smckusick #include <sys/dir.h> 1516264Smckusick #include <strings.h> 1616264Smckusick #include "fsck.h" 1716264Smckusick 1816264Smckusick int pass2check(); 1916264Smckusick 2016264Smckusick pass2() 2116264Smckusick { 2216264Smckusick register DINODE *dp; 2316264Smckusick struct inodesc rootdesc; 2416264Smckusick 2516264Smckusick bzero((char *)&rootdesc, sizeof(struct inodesc)); 2616264Smckusick rootdesc.id_type = ADDR; 2716264Smckusick rootdesc.id_func = pass2check; 2816264Smckusick rootdesc.id_number = ROOTINO; 2916264Smckusick pathp = pathname; 3016264Smckusick switch (statemap[ROOTINO]) { 3116264Smckusick 3216264Smckusick case USTATE: 3317966Smckusick pfatal("ROOT INODE UNALLOCATED"); 3417966Smckusick if (reply("ALLOCATE") == 0) 3517966Smckusick errexit(""); 3617966Smckusick if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 3717966Smckusick errexit("CANNOT ALLOCATE ROOT INODE\n"); 3817966Smckusick descend(&rootdesc, ROOTINO); 3917966Smckusick break; 4016264Smckusick 4117966Smckusick case DCLEAR: 4217966Smckusick pfatal("DUPS/BAD IN ROOT INODE"); 4317966Smckusick if (reply("REALLOCATE")) { 4417966Smckusick freeino(ROOTINO); 4517966Smckusick if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 4617966Smckusick errexit("CANNOT ALLOCATE ROOT INODE\n"); 4717966Smckusick descend(&rootdesc, ROOTINO); 4817966Smckusick break; 4917966Smckusick } 5017966Smckusick if (reply("CONTINUE") == 0) 5117966Smckusick errexit(""); 5217966Smckusick statemap[ROOTINO] = DSTATE; 5317966Smckusick descend(&rootdesc, ROOTINO); 5417966Smckusick break; 5517966Smckusick 5616264Smckusick case FSTATE: 5717937Smckusick case FCLEAR: 5816264Smckusick pfatal("ROOT INODE NOT DIRECTORY"); 5917966Smckusick if (reply("REALLOCATE")) { 6017966Smckusick freeino(ROOTINO); 6117966Smckusick if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 6217966Smckusick errexit("CANNOT ALLOCATE ROOT INODE\n"); 6317966Smckusick descend(&rootdesc, ROOTINO); 6417966Smckusick break; 6517966Smckusick } 6617943Smckusick if (reply("FIX") == 0) 6716264Smckusick errexit(""); 6817943Smckusick dp = ginode(ROOTINO); 6916264Smckusick dp->di_mode &= ~IFMT; 7016264Smckusick dp->di_mode |= IFDIR; 7116264Smckusick inodirty(); 7216264Smckusick statemap[ROOTINO] = DSTATE; 7316264Smckusick /* fall into ... */ 7416264Smckusick 7516264Smckusick case DSTATE: 7616264Smckusick descend(&rootdesc, ROOTINO); 7716264Smckusick break; 7816264Smckusick 7917937Smckusick default: 8017937Smckusick errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]); 8116264Smckusick } 8216264Smckusick } 8316264Smckusick 8416264Smckusick pass2check(idesc) 8516264Smckusick struct inodesc *idesc; 8616264Smckusick { 8716264Smckusick register DIRECT *dirp = idesc->id_dirp; 8816264Smckusick char *curpathloc; 8916264Smckusick int n, entrysize, ret = 0; 9016264Smckusick DINODE *dp; 9116264Smckusick DIRECT proto; 9217991Smckusick char namebuf[BUFSIZ]; 9316264Smckusick 9416264Smckusick /* 9516264Smckusick * check for "." 9616264Smckusick */ 9716264Smckusick if (idesc->id_entryno != 0) 9816264Smckusick goto chk1; 9916264Smckusick if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 10016264Smckusick if (dirp->d_ino != idesc->id_number) { 10116264Smckusick direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 10216264Smckusick dirp->d_ino = idesc->id_number; 10316264Smckusick if (reply("FIX") == 1) 10416264Smckusick ret |= ALTERED; 10516264Smckusick } 10616264Smckusick goto chk1; 10716264Smckusick } 10816264Smckusick direrr(idesc->id_number, "MISSING '.'"); 10916264Smckusick proto.d_ino = idesc->id_number; 11016264Smckusick proto.d_namlen = 1; 11116264Smckusick (void)strcpy(proto.d_name, "."); 11216264Smckusick entrysize = DIRSIZ(&proto); 11316264Smckusick if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 11416264Smckusick pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 11516264Smckusick dirp->d_name); 11616264Smckusick } else if (dirp->d_reclen < entrysize) { 11716264Smckusick pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 11816264Smckusick } else if (dirp->d_reclen < 2 * entrysize) { 11916264Smckusick proto.d_reclen = dirp->d_reclen; 12016264Smckusick bcopy((char *)&proto, (char *)dirp, entrysize); 12116264Smckusick if (reply("FIX") == 1) 12216264Smckusick ret |= ALTERED; 12316264Smckusick } else { 12416264Smckusick n = dirp->d_reclen - entrysize; 12516264Smckusick proto.d_reclen = entrysize; 12616264Smckusick bcopy((char *)&proto, (char *)dirp, entrysize); 12716264Smckusick idesc->id_entryno++; 12816264Smckusick lncntp[dirp->d_ino]--; 12916264Smckusick dirp = (DIRECT *)((char *)(dirp) + entrysize); 13016264Smckusick bzero((char *)dirp, n); 13116264Smckusick dirp->d_reclen = n; 13216264Smckusick if (reply("FIX") == 1) 13316264Smckusick ret |= ALTERED; 13416264Smckusick } 13516264Smckusick chk1: 13616264Smckusick if (idesc->id_entryno > 1) 13716264Smckusick goto chk2; 13816264Smckusick proto.d_ino = idesc->id_parent; 13916264Smckusick proto.d_namlen = 2; 14016264Smckusick (void)strcpy(proto.d_name, ".."); 14116264Smckusick entrysize = DIRSIZ(&proto); 14216264Smckusick if (idesc->id_entryno == 0) { 14316264Smckusick n = DIRSIZ(dirp); 14416264Smckusick if (dirp->d_reclen < n + entrysize) 14516264Smckusick goto chk2; 14616264Smckusick proto.d_reclen = dirp->d_reclen - n; 14716264Smckusick dirp->d_reclen = n; 14816264Smckusick idesc->id_entryno++; 14916264Smckusick lncntp[dirp->d_ino]--; 15016264Smckusick dirp = (DIRECT *)((char *)(dirp) + n); 15116264Smckusick bzero((char *)dirp, n); 15216264Smckusick dirp->d_reclen = n; 15316264Smckusick } 15416264Smckusick if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 15516264Smckusick if (dirp->d_ino != idesc->id_parent) { 15616264Smckusick direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'"); 15716264Smckusick dirp->d_ino = idesc->id_parent; 15816264Smckusick if (reply("FIX") == 1) 15916264Smckusick ret |= ALTERED; 16016264Smckusick } 16116264Smckusick goto chk2; 16216264Smckusick } 16316264Smckusick direrr(idesc->id_number, "MISSING '..'"); 16416264Smckusick if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 16516264Smckusick pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 16616264Smckusick dirp->d_name); 16716264Smckusick } else if (dirp->d_reclen < entrysize) { 16816264Smckusick pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 16916264Smckusick } else { 17016264Smckusick proto.d_reclen = dirp->d_reclen; 17116264Smckusick bcopy((char *)&proto, (char *)dirp, entrysize); 17216264Smckusick if (reply("FIX") == 1) 17316264Smckusick ret |= ALTERED; 17416264Smckusick } 17516264Smckusick chk2: 17616264Smckusick if (dirp->d_ino == 0) 17716264Smckusick return (ret|KEEPON); 17816264Smckusick if (dirp->d_namlen <= 2 && 17916264Smckusick dirp->d_name[0] == '.' && 18016264Smckusick idesc->id_entryno >= 2) { 18116264Smckusick if (dirp->d_namlen == 1) { 18216264Smckusick direrr(idesc->id_number, "EXTRA '.' ENTRY"); 18316264Smckusick dirp->d_ino = 0; 18416264Smckusick if (reply("FIX") == 1) 18516264Smckusick ret |= ALTERED; 18616264Smckusick return (KEEPON | ret); 18716264Smckusick } 18816264Smckusick if (dirp->d_name[1] == '.') { 18916264Smckusick direrr(idesc->id_number, "EXTRA '..' ENTRY"); 19016264Smckusick dirp->d_ino = 0; 19116264Smckusick if (reply("FIX") == 1) 19216264Smckusick ret |= ALTERED; 19316264Smckusick return (KEEPON | ret); 19416264Smckusick } 19516264Smckusick } 19616264Smckusick curpathloc = pathp; 19716264Smckusick *pathp++ = '/'; 19816264Smckusick if (pathp + dirp->d_namlen >= endpathname) { 19916264Smckusick *pathp = '\0'; 20016264Smckusick errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name); 20116264Smckusick } 20216264Smckusick bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); 20316264Smckusick pathp += dirp->d_namlen; 20416264Smckusick idesc->id_entryno++; 20516264Smckusick n = 0; 20616264Smckusick if (dirp->d_ino > imax || dirp->d_ino <= 0) { 20716264Smckusick direrr(dirp->d_ino, "I OUT OF RANGE"); 20816264Smckusick n = reply("REMOVE"); 20916264Smckusick } else { 21016264Smckusick again: 21116264Smckusick switch (statemap[dirp->d_ino]) { 21216264Smckusick case USTATE: 21316264Smckusick direrr(dirp->d_ino, "UNALLOCATED"); 21416264Smckusick n = reply("REMOVE"); 21516264Smckusick break; 21616264Smckusick 21717937Smckusick case DCLEAR: 21817937Smckusick case FCLEAR: 21916264Smckusick direrr(dirp->d_ino, "DUP/BAD"); 22016264Smckusick if ((n = reply("REMOVE")) == 1) 22116264Smckusick break; 22217943Smckusick dp = ginode(dirp->d_ino); 22317931Smckusick statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE; 22416264Smckusick goto again; 22516264Smckusick 22617937Smckusick case DFOUND: 22717991Smckusick if (idesc->id_entryno > 2) { 22817991Smckusick getpathname(namebuf, dirp->d_ino, dirp->d_ino); 22917991Smckusick pwarn("%s %s %s\n", pathname, 23017991Smckusick "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 23117991Smckusick namebuf); 23217991Smckusick if (preen) 23317991Smckusick printf(" (IGNORED)\n"); 23417991Smckusick else if ((n = reply("REMOVE")) == 1) 23517991Smckusick break; 23617991Smckusick } 23717937Smckusick /* fall through */ 23817937Smckusick 23916264Smckusick case FSTATE: 24016264Smckusick lncntp[dirp->d_ino]--; 24116264Smckusick break; 24216264Smckusick 24316264Smckusick case DSTATE: 24416264Smckusick descend(idesc, dirp->d_ino); 24517937Smckusick if (statemap[dirp->d_ino] == DFOUND) { 24616264Smckusick lncntp[dirp->d_ino]--; 24717937Smckusick } else if (statemap[dirp->d_ino] == DCLEAR) { 24816264Smckusick dirp->d_ino = 0; 24916264Smckusick ret |= ALTERED; 25017937Smckusick } else 25117937Smckusick errexit("BAD RETURN STATE %d FROM DESCEND", 25217937Smckusick statemap[dirp->d_ino]); 25316264Smckusick break; 25416264Smckusick } 25516264Smckusick } 25616264Smckusick pathp = curpathloc; 25716264Smckusick *pathp = '\0'; 25816264Smckusick if (n == 0) 25916264Smckusick return (ret|KEEPON); 26016264Smckusick dirp->d_ino = 0; 26116264Smckusick return (ret|KEEPON|ALTERED); 26216264Smckusick } 263