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