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