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