1 #ifndef lint 2 static char version[] = "@(#)dir.c 3.4 (Berkeley) 02/11/85"; 3 #endif 4 5 #include <sys/param.h> 6 #include <sys/inode.h> 7 #include <sys/fs.h> 8 #define KERNEL 9 #include <sys/dir.h> 10 #undef KERNEL 11 #include "fsck.h" 12 13 #define MINDIRSIZE (sizeof (struct dirtemplate)) 14 15 char *endpathname = &pathname[BUFSIZ - 2]; 16 char *lfname = "lost+found"; 17 18 DIRECT *fsck_readdir(); 19 20 descend(parentino, inumber) 21 struct inodesc *parentino; 22 ino_t inumber; 23 { 24 register DINODE *dp; 25 struct inodesc curino; 26 27 bzero((char *)&curino, sizeof(struct inodesc)); 28 if (statemap[inumber] != DSTATE) 29 errexit("BAD INODE %d TO DESCEND", statemap[inumber]); 30 statemap[inumber] = DFOUND; 31 dp = ginode(inumber); 32 if (dp->di_size == 0) { 33 direrr(inumber, "ZERO LENGTH DIRECTORY"); 34 if (reply("REMOVE") == 1) 35 statemap[inumber] = DCLEAR; 36 return; 37 } 38 if (dp->di_size < MINDIRSIZE) { 39 direrr(inumber, "DIRECTORY TOO SHORT"); 40 dp->di_size = MINDIRSIZE; 41 if (reply("FIX") == 1) 42 inodirty(); 43 } 44 curino.id_type = DATA; 45 curino.id_func = parentino->id_func; 46 curino.id_parent = parentino->id_number; 47 curino.id_number = inumber; 48 curino.id_filesize = dp->di_size; 49 (void)ckinode(dp, &curino); 50 } 51 52 dirscan(idesc) 53 register struct inodesc *idesc; 54 { 55 register DIRECT *dp; 56 int dsize, n; 57 long blksiz; 58 char dbuf[DIRBLKSIZ]; 59 60 if (idesc->id_type != DATA) 61 errexit("wrong type to dirscan %d\n", idesc->id_type); 62 blksiz = idesc->id_numfrags * sblock.fs_fsize; 63 if (outrange(idesc->id_blkno, idesc->id_numfrags)) { 64 idesc->id_filesize -= blksiz; 65 return (SKIP); 66 } 67 idesc->id_loc = 0; 68 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 69 dsize = dp->d_reclen; 70 bcopy((char *)dp, dbuf, dsize); 71 idesc->id_dirp = (DIRECT *)dbuf; 72 if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 73 if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { 74 bcopy(dbuf, (char *)dp, dsize); 75 dirty(&fileblk); 76 sbdirty(); 77 } else 78 n &= ~ALTERED; 79 } 80 if (n & STOP) 81 return (n); 82 } 83 return (idesc->id_filesize > 0 ? KEEPON : STOP); 84 } 85 86 /* 87 * get next entry in a directory. 88 */ 89 DIRECT * 90 fsck_readdir(idesc) 91 register struct inodesc *idesc; 92 { 93 register DIRECT *dp, *ndp; 94 long size, blksiz; 95 96 blksiz = idesc->id_numfrags * sblock.fs_fsize; 97 if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { 98 idesc->id_filesize -= blksiz - idesc->id_loc; 99 return NULL; 100 } 101 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 102 idesc->id_loc < blksiz) { 103 dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 104 if (dircheck(idesc, dp)) 105 goto dpok; 106 idesc->id_loc += DIRBLKSIZ; 107 idesc->id_filesize -= DIRBLKSIZ; 108 dp->d_reclen = DIRBLKSIZ; 109 dp->d_ino = 0; 110 dp->d_namlen = 0; 111 dp->d_name[0] = '\0'; 112 if (dofix(idesc, "DIRECTORY CORRUPTED")) 113 dirty(&fileblk); 114 return (dp); 115 } 116 dpok: 117 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 118 return NULL; 119 dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 120 idesc->id_loc += dp->d_reclen; 121 idesc->id_filesize -= dp->d_reclen; 122 if ((idesc->id_loc % DIRBLKSIZ) == 0) 123 return (dp); 124 ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); 125 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 126 dircheck(idesc, ndp) == 0) { 127 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 128 dp->d_reclen += size; 129 idesc->id_loc += size; 130 idesc->id_filesize -= size; 131 if (dofix(idesc, "DIRECTORY CORRUPTED")) 132 dirty(&fileblk); 133 } 134 return (dp); 135 } 136 137 /* 138 * Verify that a directory entry is valid. 139 * This is a superset of the checks made in the kernel. 140 */ 141 dircheck(idesc, dp) 142 struct inodesc *idesc; 143 register DIRECT *dp; 144 { 145 register int size; 146 register char *cp; 147 int spaceleft; 148 149 size = DIRSIZ(dp); 150 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 151 if (dp->d_ino < imax && 152 dp->d_reclen != 0 && 153 dp->d_reclen <= spaceleft && 154 (dp->d_reclen & 0x3) == 0 && 155 dp->d_reclen >= size && 156 idesc->id_filesize >= size && 157 dp->d_namlen <= MAXNAMLEN) { 158 if (dp->d_ino == 0) 159 return (1); 160 for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 161 if (*cp == 0 || (*cp++ & 0200)) 162 return (0); 163 if (*cp == 0) 164 return (1); 165 } 166 return (0); 167 } 168 169 direrr(ino, s) 170 ino_t ino; 171 char *s; 172 { 173 register DINODE *dp; 174 175 pwarn("%s ", s); 176 pinode(ino); 177 printf("\n"); 178 if (ino < ROOTINO || ino > imax) { 179 pfatal("NAME=%s\n", pathname); 180 return; 181 } 182 dp = ginode(ino); 183 if (ftypeok(dp)) 184 pfatal("%s=%s\n", DIRCT(dp) ? "DIR" : "FILE", pathname); 185 else 186 pfatal("NAME=%s\n", pathname); 187 } 188 189 adjust(idesc, lcnt) 190 register struct inodesc *idesc; 191 short lcnt; 192 { 193 register DINODE *dp; 194 195 dp = ginode(idesc->id_number); 196 if (dp->di_nlink == lcnt) { 197 if (linkup(idesc->id_number, (ino_t)0) == 0) 198 clri(idesc, "UNREF", 0); 199 } else { 200 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 201 (DIRCT(dp) ? "DIR" : "FILE")); 202 pinode(idesc->id_number); 203 printf(" COUNT %d SHOULD BE %d", 204 dp->di_nlink, dp->di_nlink-lcnt); 205 if (preen) { 206 if (lcnt < 0) { 207 printf("\n"); 208 pfatal("LINK COUNT INCREASING"); 209 } 210 printf(" (ADJUSTED)\n"); 211 } 212 if (preen || reply("ADJUST") == 1) { 213 dp->di_nlink -= lcnt; 214 inodirty(); 215 } 216 } 217 } 218 219 mkentry(idesc) 220 struct inodesc *idesc; 221 { 222 register DIRECT *dirp = idesc->id_dirp; 223 DIRECT newent; 224 int newlen, oldlen; 225 226 newent.d_namlen = 11; 227 newlen = DIRSIZ(&newent); 228 if (dirp->d_ino != 0) 229 oldlen = DIRSIZ(dirp); 230 else 231 oldlen = 0; 232 if (dirp->d_reclen - oldlen < newlen) 233 return (KEEPON); 234 newent.d_reclen = dirp->d_reclen - oldlen; 235 dirp->d_reclen = oldlen; 236 dirp = (struct direct *)(((char *)dirp) + oldlen); 237 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 238 dirp->d_reclen = newent.d_reclen; 239 dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); 240 return (ALTERED|STOP); 241 } 242 243 chgdd(idesc) 244 struct inodesc *idesc; 245 { 246 register DIRECT *dirp = idesc->id_dirp; 247 248 if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && 249 dirp->d_name[2] == 0) { 250 dirp->d_ino = lfdir; 251 return (ALTERED|STOP); 252 } 253 return (KEEPON); 254 } 255 256 linkup(orphan, pdir) 257 ino_t orphan; 258 ino_t pdir; 259 { 260 register DINODE *dp; 261 int lostdir, len; 262 struct inodesc idesc; 263 264 bzero((char *)&idesc, sizeof(struct inodesc)); 265 dp = ginode(orphan); 266 lostdir = DIRCT(dp); 267 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 268 pinode(orphan); 269 if (preen && dp->di_size == 0) 270 return (0); 271 if (preen) 272 printf(" (RECONNECTED)\n"); 273 else 274 if (reply("RECONNECT") == 0) 275 return (0); 276 pathp = pathname; 277 *pathp++ = '/'; 278 *pathp = '\0'; 279 if (lfdir == 0) { 280 dp = ginode(ROOTINO); 281 idesc.id_name = lfname; 282 idesc.id_type = DATA; 283 idesc.id_func = findino; 284 idesc.id_number = ROOTINO; 285 idesc.id_filesize = dp->di_size; 286 (void)ckinode(dp, &idesc); 287 lfdir = idesc.id_parent; 288 if (lfdir < ROOTINO || lfdir > imax) 289 lfdir = 0; 290 if (lfdir == 0) { 291 pfatal("SORRY. NO lost+found DIRECTORY"); 292 printf("\n\n"); 293 return (0); 294 } 295 } 296 dp = ginode(lfdir); 297 if (!DIRCT(dp) || statemap[lfdir] != DFOUND) { 298 pfatal("SORRY. NO lost+found DIRECTORY"); 299 printf("\n\n"); 300 return (0); 301 } 302 if (fragoff(&sblock, dp->di_size)) { 303 dp->di_size = fragroundup(&sblock, dp->di_size); 304 inodirty(); 305 } 306 len = strlen(lfname); 307 bcopy(lfname, pathp, len + 1); 308 pathp += len; 309 idesc.id_type = DATA; 310 idesc.id_func = mkentry; 311 idesc.id_number = lfdir; 312 idesc.id_filesize = dp->di_size; 313 idesc.id_parent = orphan; /* this is the inode to enter */ 314 idesc.id_fix = DONTKNOW; 315 if ((ckinode(dp, &idesc) & ALTERED) == 0) { 316 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 317 printf("\n\n"); 318 return (0); 319 } 320 lncntp[orphan]--; 321 *pathp++ = '/'; 322 pathp += lftempname(pathp, orphan); 323 if (lostdir) { 324 dp = ginode(orphan); 325 idesc.id_type = DATA; 326 idesc.id_func = chgdd; 327 idesc.id_number = orphan; 328 idesc.id_filesize = dp->di_size; 329 idesc.id_fix = DONTKNOW; 330 (void)ckinode(dp, &idesc); 331 dp = ginode(lfdir); 332 dp->di_nlink++; 333 inodirty(); 334 lncntp[lfdir]++; 335 pwarn("DIR I=%u CONNECTED. ", orphan); 336 printf("PARENT WAS I=%u\n", pdir); 337 if (preen == 0) 338 printf("\n"); 339 } 340 return (1); 341 } 342 343 /* 344 * generate a temporary name for the lost+found directory. 345 */ 346 lftempname(bufp, ino) 347 char *bufp; 348 ino_t ino; 349 { 350 register ino_t in; 351 register char *cp; 352 int namlen; 353 354 cp = bufp + 2; 355 for (in = imax; in > 0; in /= 10) 356 cp++; 357 *--cp = 0; 358 namlen = cp - bufp; 359 in = ino; 360 while (cp > bufp) { 361 *--cp = (in % 10) + '0'; 362 in /= 10; 363 } 364 *cp = '#'; 365 return (namlen); 366 } 367