1 #ifndef lint 2 static char version[] = "@(#)pass2.c 3.5 (Berkeley) 02/14/85"; 3 #endif 4 5 #include <sys/param.h> 6 #include <sys/inode.h> 7 #include <sys/fs.h> 8 #include <sys/dir.h> 9 #include <strings.h> 10 #include "fsck.h" 11 12 int pass2check(); 13 14 pass2() 15 { 16 register DINODE *dp; 17 struct inodesc rootdesc; 18 19 bzero((char *)&rootdesc, sizeof(struct inodesc)); 20 rootdesc.id_type = ADDR; 21 rootdesc.id_func = pass2check; 22 rootdesc.id_number = ROOTINO; 23 pathp = pathname; 24 switch (statemap[ROOTINO]) { 25 26 case USTATE: 27 pfatal("ROOT INODE UNALLOCATED"); 28 if (reply("ALLOCATE") == 0) 29 errexit(""); 30 if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 31 errexit("CANNOT ALLOCATE ROOT INODE\n"); 32 descend(&rootdesc, ROOTINO); 33 break; 34 35 case DCLEAR: 36 pfatal("DUPS/BAD IN ROOT INODE"); 37 if (reply("REALLOCATE")) { 38 freeino(ROOTINO); 39 if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 40 errexit("CANNOT ALLOCATE ROOT INODE\n"); 41 descend(&rootdesc, ROOTINO); 42 break; 43 } 44 if (reply("CONTINUE") == 0) 45 errexit(""); 46 statemap[ROOTINO] = DSTATE; 47 descend(&rootdesc, ROOTINO); 48 break; 49 50 case FSTATE: 51 case FCLEAR: 52 pfatal("ROOT INODE NOT DIRECTORY"); 53 if (reply("REALLOCATE")) { 54 freeino(ROOTINO); 55 if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 56 errexit("CANNOT ALLOCATE ROOT INODE\n"); 57 descend(&rootdesc, ROOTINO); 58 break; 59 } 60 if (reply("FIX") == 0) 61 errexit(""); 62 dp = ginode(ROOTINO); 63 dp->di_mode &= ~IFMT; 64 dp->di_mode |= IFDIR; 65 inodirty(); 66 statemap[ROOTINO] = DSTATE; 67 /* fall into ... */ 68 69 case DSTATE: 70 descend(&rootdesc, ROOTINO); 71 break; 72 73 default: 74 errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]); 75 } 76 } 77 78 pass2check(idesc) 79 struct inodesc *idesc; 80 { 81 register DIRECT *dirp = idesc->id_dirp; 82 char *curpathloc; 83 int n, entrysize, ret = 0; 84 DINODE *dp; 85 DIRECT proto; 86 87 /* 88 * check for "." 89 */ 90 if (idesc->id_entryno != 0) 91 goto chk1; 92 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 93 if (dirp->d_ino != idesc->id_number) { 94 direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 95 dirp->d_ino = idesc->id_number; 96 if (reply("FIX") == 1) 97 ret |= ALTERED; 98 } 99 goto chk1; 100 } 101 direrr(idesc->id_number, "MISSING '.'"); 102 proto.d_ino = idesc->id_number; 103 proto.d_namlen = 1; 104 (void)strcpy(proto.d_name, "."); 105 entrysize = DIRSIZ(&proto); 106 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 107 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 108 dirp->d_name); 109 } else if (dirp->d_reclen < entrysize) { 110 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 111 } else if (dirp->d_reclen < 2 * entrysize) { 112 proto.d_reclen = dirp->d_reclen; 113 bcopy((char *)&proto, (char *)dirp, entrysize); 114 if (reply("FIX") == 1) 115 ret |= ALTERED; 116 } else { 117 n = dirp->d_reclen - entrysize; 118 proto.d_reclen = entrysize; 119 bcopy((char *)&proto, (char *)dirp, entrysize); 120 idesc->id_entryno++; 121 lncntp[dirp->d_ino]--; 122 dirp = (DIRECT *)((char *)(dirp) + entrysize); 123 bzero((char *)dirp, n); 124 dirp->d_reclen = n; 125 if (reply("FIX") == 1) 126 ret |= ALTERED; 127 } 128 chk1: 129 if (idesc->id_entryno > 1) 130 goto chk2; 131 proto.d_ino = idesc->id_parent; 132 proto.d_namlen = 2; 133 (void)strcpy(proto.d_name, ".."); 134 entrysize = DIRSIZ(&proto); 135 if (idesc->id_entryno == 0) { 136 n = DIRSIZ(dirp); 137 if (dirp->d_reclen < n + entrysize) 138 goto chk2; 139 proto.d_reclen = dirp->d_reclen - n; 140 dirp->d_reclen = n; 141 idesc->id_entryno++; 142 lncntp[dirp->d_ino]--; 143 dirp = (DIRECT *)((char *)(dirp) + n); 144 bzero((char *)dirp, n); 145 dirp->d_reclen = n; 146 } 147 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 148 if (dirp->d_ino != idesc->id_parent) { 149 direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'"); 150 dirp->d_ino = idesc->id_parent; 151 if (reply("FIX") == 1) 152 ret |= ALTERED; 153 } 154 goto chk2; 155 } 156 direrr(idesc->id_number, "MISSING '..'"); 157 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 158 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 159 dirp->d_name); 160 } else if (dirp->d_reclen < entrysize) { 161 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 162 } else { 163 proto.d_reclen = dirp->d_reclen; 164 bcopy((char *)&proto, (char *)dirp, entrysize); 165 if (reply("FIX") == 1) 166 ret |= ALTERED; 167 } 168 chk2: 169 if (dirp->d_ino == 0) 170 return (ret|KEEPON); 171 if (dirp->d_namlen <= 2 && 172 dirp->d_name[0] == '.' && 173 idesc->id_entryno >= 2) { 174 if (dirp->d_namlen == 1) { 175 direrr(idesc->id_number, "EXTRA '.' ENTRY"); 176 dirp->d_ino = 0; 177 if (reply("FIX") == 1) 178 ret |= ALTERED; 179 return (KEEPON | ret); 180 } 181 if (dirp->d_name[1] == '.') { 182 direrr(idesc->id_number, "EXTRA '..' ENTRY"); 183 dirp->d_ino = 0; 184 if (reply("FIX") == 1) 185 ret |= ALTERED; 186 return (KEEPON | ret); 187 } 188 } 189 curpathloc = pathp; 190 *pathp++ = '/'; 191 if (pathp + dirp->d_namlen >= endpathname) { 192 *pathp = '\0'; 193 errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name); 194 } 195 bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); 196 pathp += dirp->d_namlen; 197 idesc->id_entryno++; 198 n = 0; 199 if (dirp->d_ino > imax || dirp->d_ino <= 0) { 200 direrr(dirp->d_ino, "I OUT OF RANGE"); 201 n = reply("REMOVE"); 202 } else { 203 again: 204 switch (statemap[dirp->d_ino]) { 205 case USTATE: 206 direrr(dirp->d_ino, "UNALLOCATED"); 207 n = reply("REMOVE"); 208 break; 209 210 case DCLEAR: 211 case FCLEAR: 212 direrr(dirp->d_ino, "DUP/BAD"); 213 if ((n = reply("REMOVE")) == 1) 214 break; 215 dp = ginode(dirp->d_ino); 216 statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE; 217 goto again; 218 219 case DFOUND: 220 if (idesc->id_entryno > 2) 221 pwarn("WARNING: %s IS %s\n", pathname, 222 "AN EXTRANEOUS HARD LINK TO A DIRECTORY"); 223 /* fall through */ 224 225 case FSTATE: 226 lncntp[dirp->d_ino]--; 227 break; 228 229 case DSTATE: 230 descend(idesc, dirp->d_ino); 231 if (statemap[dirp->d_ino] == DFOUND) { 232 lncntp[dirp->d_ino]--; 233 } else if (statemap[dirp->d_ino] == DCLEAR) { 234 dirp->d_ino = 0; 235 ret |= ALTERED; 236 } else 237 errexit("BAD RETURN STATE %d FROM DESCEND", 238 statemap[dirp->d_ino]); 239 break; 240 } 241 } 242 pathp = curpathloc; 243 *pathp = '\0'; 244 if (n == 0) 245 return (ret|KEEPON); 246 dirp->d_ino = 0; 247 return (ret|KEEPON|ALTERED); 248 } 249