1 #ifndef lint 2 static char version[] = "@(#)pass2.c 3.6 (Berkeley) 02/15/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 char namebuf[BUFSIZ]; 87 88 /* 89 * check for "." 90 */ 91 if (idesc->id_entryno != 0) 92 goto chk1; 93 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 94 if (dirp->d_ino != idesc->id_number) { 95 direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 96 dirp->d_ino = idesc->id_number; 97 if (reply("FIX") == 1) 98 ret |= ALTERED; 99 } 100 goto chk1; 101 } 102 direrr(idesc->id_number, "MISSING '.'"); 103 proto.d_ino = idesc->id_number; 104 proto.d_namlen = 1; 105 (void)strcpy(proto.d_name, "."); 106 entrysize = DIRSIZ(&proto); 107 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 108 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 109 dirp->d_name); 110 } else if (dirp->d_reclen < entrysize) { 111 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 112 } else if (dirp->d_reclen < 2 * entrysize) { 113 proto.d_reclen = dirp->d_reclen; 114 bcopy((char *)&proto, (char *)dirp, entrysize); 115 if (reply("FIX") == 1) 116 ret |= ALTERED; 117 } else { 118 n = dirp->d_reclen - entrysize; 119 proto.d_reclen = entrysize; 120 bcopy((char *)&proto, (char *)dirp, entrysize); 121 idesc->id_entryno++; 122 lncntp[dirp->d_ino]--; 123 dirp = (DIRECT *)((char *)(dirp) + entrysize); 124 bzero((char *)dirp, n); 125 dirp->d_reclen = n; 126 if (reply("FIX") == 1) 127 ret |= ALTERED; 128 } 129 chk1: 130 if (idesc->id_entryno > 1) 131 goto chk2; 132 proto.d_ino = idesc->id_parent; 133 proto.d_namlen = 2; 134 (void)strcpy(proto.d_name, ".."); 135 entrysize = DIRSIZ(&proto); 136 if (idesc->id_entryno == 0) { 137 n = DIRSIZ(dirp); 138 if (dirp->d_reclen < n + entrysize) 139 goto chk2; 140 proto.d_reclen = dirp->d_reclen - n; 141 dirp->d_reclen = n; 142 idesc->id_entryno++; 143 lncntp[dirp->d_ino]--; 144 dirp = (DIRECT *)((char *)(dirp) + n); 145 bzero((char *)dirp, n); 146 dirp->d_reclen = n; 147 } 148 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 149 if (dirp->d_ino != idesc->id_parent) { 150 direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'"); 151 dirp->d_ino = idesc->id_parent; 152 if (reply("FIX") == 1) 153 ret |= ALTERED; 154 } 155 goto chk2; 156 } 157 direrr(idesc->id_number, "MISSING '..'"); 158 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 159 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 160 dirp->d_name); 161 } else if (dirp->d_reclen < entrysize) { 162 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 163 } else { 164 proto.d_reclen = dirp->d_reclen; 165 bcopy((char *)&proto, (char *)dirp, entrysize); 166 if (reply("FIX") == 1) 167 ret |= ALTERED; 168 } 169 chk2: 170 if (dirp->d_ino == 0) 171 return (ret|KEEPON); 172 if (dirp->d_namlen <= 2 && 173 dirp->d_name[0] == '.' && 174 idesc->id_entryno >= 2) { 175 if (dirp->d_namlen == 1) { 176 direrr(idesc->id_number, "EXTRA '.' ENTRY"); 177 dirp->d_ino = 0; 178 if (reply("FIX") == 1) 179 ret |= ALTERED; 180 return (KEEPON | ret); 181 } 182 if (dirp->d_name[1] == '.') { 183 direrr(idesc->id_number, "EXTRA '..' ENTRY"); 184 dirp->d_ino = 0; 185 if (reply("FIX") == 1) 186 ret |= ALTERED; 187 return (KEEPON | ret); 188 } 189 } 190 curpathloc = pathp; 191 *pathp++ = '/'; 192 if (pathp + dirp->d_namlen >= endpathname) { 193 *pathp = '\0'; 194 errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name); 195 } 196 bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); 197 pathp += dirp->d_namlen; 198 idesc->id_entryno++; 199 n = 0; 200 if (dirp->d_ino > imax || dirp->d_ino <= 0) { 201 direrr(dirp->d_ino, "I OUT OF RANGE"); 202 n = reply("REMOVE"); 203 } else { 204 again: 205 switch (statemap[dirp->d_ino]) { 206 case USTATE: 207 direrr(dirp->d_ino, "UNALLOCATED"); 208 n = reply("REMOVE"); 209 break; 210 211 case DCLEAR: 212 case FCLEAR: 213 direrr(dirp->d_ino, "DUP/BAD"); 214 if ((n = reply("REMOVE")) == 1) 215 break; 216 dp = ginode(dirp->d_ino); 217 statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE; 218 goto again; 219 220 case DFOUND: 221 if (idesc->id_entryno > 2) { 222 getpathname(namebuf, dirp->d_ino, dirp->d_ino); 223 pwarn("%s %s %s\n", pathname, 224 "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 225 namebuf); 226 if (preen) 227 printf(" (IGNORED)\n"); 228 else if ((n = reply("REMOVE")) == 1) 229 break; 230 } 231 /* fall through */ 232 233 case FSTATE: 234 lncntp[dirp->d_ino]--; 235 break; 236 237 case DSTATE: 238 descend(idesc, dirp->d_ino); 239 if (statemap[dirp->d_ino] == DFOUND) { 240 lncntp[dirp->d_ino]--; 241 } else if (statemap[dirp->d_ino] == DCLEAR) { 242 dirp->d_ino = 0; 243 ret |= ALTERED; 244 } else 245 errexit("BAD RETURN STATE %d FROM DESCEND", 246 statemap[dirp->d_ino]); 247 break; 248 } 249 } 250 pathp = curpathloc; 251 *pathp = '\0'; 252 if (n == 0) 253 return (ret|KEEPON); 254 dirp->d_ino = 0; 255 return (ret|KEEPON|ALTERED); 256 } 257