1 1.35 joerg /* $NetBSD: pass2.c,v 1.35 2020/04/03 19:36:33 joerg Exp $ */ 2 1.1 perseant 3 1.1 perseant /* 4 1.1 perseant * Copyright (c) 1980, 1986, 1993 5 1.1 perseant * The Regents of the University of California. All rights reserved. 6 1.1 perseant * 7 1.1 perseant * Redistribution and use in source and binary forms, with or without 8 1.1 perseant * modification, are permitted provided that the following conditions 9 1.1 perseant * are met: 10 1.1 perseant * 1. Redistributions of source code must retain the above copyright 11 1.1 perseant * notice, this list of conditions and the following disclaimer. 12 1.1 perseant * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 perseant * notice, this list of conditions and the following disclaimer in the 14 1.1 perseant * documentation and/or other materials provided with the distribution. 15 1.10 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 perseant * may be used to endorse or promote products derived from this software 17 1.1 perseant * without specific prior written permission. 18 1.1 perseant * 19 1.1 perseant * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 perseant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 perseant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 perseant * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 perseant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 perseant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 perseant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 perseant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 perseant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 perseant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 perseant * SUCH DAMAGE. 30 1.1 perseant */ 31 1.1 perseant 32 1.7 perseant #include <sys/types.h> 33 1.1 perseant #include <sys/param.h> 34 1.1 perseant #include <sys/time.h> 35 1.7 perseant #include <sys/mount.h> 36 1.7 perseant #include <sys/buf.h> 37 1.7 perseant 38 1.1 perseant #include <ufs/lfs/lfs.h> 39 1.26 dholland #include <ufs/lfs/lfs_accessors.h> 40 1.23 dholland #include <ufs/lfs/lfs_inode.h> 41 1.1 perseant 42 1.7 perseant #include <err.h> 43 1.1 perseant #include <stdio.h> 44 1.1 perseant #include <stdlib.h> 45 1.1 perseant #include <string.h> 46 1.1 perseant 47 1.7 perseant #include "bufcache.h" 48 1.15 christos #include "lfs_user.h" 49 1.7 perseant 50 1.1 perseant #include "fsck.h" 51 1.1 perseant #include "fsutil.h" 52 1.1 perseant #include "extern.h" 53 1.1 perseant 54 1.34 dholland #define MINDIRSIZE(fs) \ 55 1.34 dholland ((fs)->lfs_is64 ? sizeof(struct lfs_dirtemplate64) : \ 56 1.34 dholland sizeof(struct lfs_dirtemplate32)) 57 1.1 perseant 58 1.7 perseant static int pass2check(struct inodesc *); 59 1.7 perseant static int blksort(const void *, const void *); 60 1.1 perseant 61 1.1 perseant void 62 1.11 xtraeme pass2(void) 63 1.1 perseant { 64 1.26 dholland union lfs_dinode *dp; 65 1.7 perseant struct uvnode *vp; 66 1.7 perseant struct inoinfo **inpp, *inp; 67 1.1 perseant struct inoinfo **inpend; 68 1.7 perseant struct inodesc curino; 69 1.26 dholland union lfs_dinode dino; 70 1.7 perseant char pathbuf[MAXPATHLEN + 1]; 71 1.26 dholland uint16_t mode; 72 1.26 dholland unsigned ii; 73 1.1 perseant 74 1.19 dholland switch (statemap[ULFS_ROOTINO]) { 75 1.1 perseant 76 1.1 perseant case USTATE: 77 1.1 perseant pfatal("ROOT INODE UNALLOCATED"); 78 1.1 perseant if (reply("ALLOCATE") == 0) 79 1.17 christos err(EEXIT, "%s", ""); 80 1.19 dholland if (allocdir(ULFS_ROOTINO, ULFS_ROOTINO, 0755) != ULFS_ROOTINO) 81 1.25 christos err(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 82 1.1 perseant break; 83 1.1 perseant 84 1.1 perseant case DCLEAR: 85 1.1 perseant pfatal("DUPS/BAD IN ROOT INODE"); 86 1.1 perseant if (reply("REALLOCATE")) { 87 1.19 dholland freeino(ULFS_ROOTINO); 88 1.19 dholland if (allocdir(ULFS_ROOTINO, ULFS_ROOTINO, 0755) != ULFS_ROOTINO) 89 1.24 christos err(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 90 1.1 perseant break; 91 1.1 perseant } 92 1.1 perseant if (reply("CONTINUE") == 0) 93 1.17 christos err(EEXIT, "%s", ""); 94 1.1 perseant break; 95 1.1 perseant 96 1.1 perseant case FSTATE: 97 1.1 perseant case FCLEAR: 98 1.1 perseant pfatal("ROOT INODE NOT DIRECTORY"); 99 1.1 perseant if (reply("REALLOCATE")) { 100 1.19 dholland freeino(ULFS_ROOTINO); 101 1.19 dholland if (allocdir(ULFS_ROOTINO, ULFS_ROOTINO, 0755) != ULFS_ROOTINO) 102 1.24 christos err(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 103 1.1 perseant break; 104 1.1 perseant } 105 1.1 perseant if (reply("FIX") == 0) 106 1.17 christos errx(EEXIT, "%s", ""); 107 1.19 dholland vp = vget(fs, ULFS_ROOTINO); 108 1.7 perseant dp = VTOD(vp); 109 1.26 dholland mode = lfs_dino_getmode(fs, dp); 110 1.26 dholland mode &= ~LFS_IFMT; 111 1.26 dholland mode |= LFS_IFDIR; 112 1.26 dholland lfs_dino_setmode(fs, dp, mode); 113 1.7 perseant inodirty(VTOI(vp)); 114 1.1 perseant break; 115 1.1 perseant 116 1.1 perseant case DSTATE: 117 1.1 perseant break; 118 1.1 perseant 119 1.1 perseant default: 120 1.24 christos errx(EEXIT, "BAD STATE %d FOR ROOT INODE", statemap[ULFS_ROOTINO]); 121 1.1 perseant } 122 1.19 dholland statemap[ULFS_WINO] = FSTATE; 123 1.21 dholland typemap[ULFS_WINO] = LFS_DT_WHT; 124 1.1 perseant /* 125 1.1 perseant * Sort the directory list into disk block order. 126 1.1 perseant */ 127 1.7 perseant qsort((char *) inpsort, (size_t) inplast, sizeof *inpsort, blksort); 128 1.1 perseant /* 129 1.1 perseant * Check the integrity of each directory. 130 1.1 perseant */ 131 1.1 perseant memset(&curino, 0, sizeof(struct inodesc)); 132 1.1 perseant curino.id_type = DATA; 133 1.1 perseant curino.id_func = pass2check; 134 1.1 perseant inpend = &inpsort[inplast]; 135 1.1 perseant for (inpp = inpsort; inpp < inpend; inpp++) { 136 1.1 perseant inp = *inpp; 137 1.1 perseant if (inp->i_isize == 0) 138 1.1 perseant continue; 139 1.34 dholland if (inp->i_isize < MINDIRSIZE(fs)) { 140 1.1 perseant direrror(inp->i_number, "DIRECTORY TOO SHORT"); 141 1.34 dholland inp->i_isize = roundup(MINDIRSIZE(fs), LFS_DIRBLKSIZ); 142 1.1 perseant if (reply("FIX") == 1) { 143 1.7 perseant vp = vget(fs, inp->i_number); 144 1.7 perseant dp = VTOD(vp); 145 1.26 dholland lfs_dino_setsize(fs, dp, inp->i_isize); 146 1.7 perseant inodirty(VTOI(vp)); 147 1.1 perseant } 148 1.22 dholland } else if ((inp->i_isize & (LFS_DIRBLKSIZ - 1)) != 0) { 149 1.9 itojun getpathname(pathbuf, sizeof(pathbuf), inp->i_number, 150 1.9 itojun inp->i_number); 151 1.2 nathanw pwarn("DIRECTORY %s: LENGTH %lu NOT MULTIPLE OF %d", 152 1.22 dholland pathbuf, (unsigned long) inp->i_isize, LFS_DIRBLKSIZ); 153 1.1 perseant if (preen) 154 1.1 perseant printf(" (ADJUSTED)\n"); 155 1.22 dholland inp->i_isize = roundup(inp->i_isize, LFS_DIRBLKSIZ); 156 1.1 perseant if (preen || reply("ADJUST") == 1) { 157 1.7 perseant vp = vget(fs, inp->i_number); 158 1.7 perseant dp = VTOD(vp); 159 1.26 dholland lfs_dino_setsize(fs, dp, inp->i_isize); 160 1.7 perseant inodirty(VTOI(vp)); 161 1.1 perseant } 162 1.1 perseant } 163 1.26 dholland memset(&dino, 0, sizeof(dino)); 164 1.26 dholland lfs_dino_setmode(fs, &dino, LFS_IFDIR); 165 1.26 dholland lfs_dino_setsize(fs, &dino, inp->i_isize); 166 1.26 dholland for (ii = 0; ii < inp->i_numblks / sizeof(inp->i_blks[0]) && 167 1.26 dholland ii < ULFS_NDADDR; ii++) { 168 1.26 dholland lfs_dino_setdb(fs, &dino, ii, inp->i_blks[ii]); 169 1.26 dholland } 170 1.26 dholland for (; ii < inp->i_numblks / sizeof(inp->i_blks[0]); ii++) { 171 1.26 dholland lfs_dino_setib(fs, &dino, ii - ULFS_NDADDR, 172 1.26 dholland inp->i_blks[ii]); 173 1.26 dholland } 174 1.1 perseant curino.id_number = inp->i_number; 175 1.1 perseant curino.id_parent = inp->i_parent; 176 1.7 perseant (void) ckinode(&dino, &curino); 177 1.1 perseant } 178 1.1 perseant /* 179 1.1 perseant * Now that the parents of all directories have been found, 180 1.1 perseant * make another pass to verify the value of `..' 181 1.1 perseant */ 182 1.1 perseant for (inpp = inpsort; inpp < inpend; inpp++) { 183 1.1 perseant inp = *inpp; 184 1.1 perseant if (inp->i_parent == 0 || inp->i_isize == 0) 185 1.1 perseant continue; 186 1.1 perseant if (inp->i_dotdot == inp->i_parent || 187 1.7 perseant inp->i_dotdot == (ino_t) - 1) 188 1.1 perseant continue; 189 1.1 perseant if (inp->i_dotdot == 0) { 190 1.1 perseant inp->i_dotdot = inp->i_parent; 191 1.1 perseant fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); 192 1.1 perseant if (reply("FIX") == 0) 193 1.1 perseant continue; 194 1.7 perseant (void) makeentry(inp->i_number, inp->i_parent, ".."); 195 1.1 perseant lncntp[inp->i_parent]--; 196 1.1 perseant continue; 197 1.1 perseant } 198 1.1 perseant fileerror(inp->i_parent, inp->i_number, 199 1.7 perseant "BAD INODE NUMBER FOR '..'"); 200 1.1 perseant if (reply("FIX") == 0) 201 1.1 perseant continue; 202 1.1 perseant lncntp[inp->i_dotdot]++; 203 1.1 perseant lncntp[inp->i_parent]--; 204 1.1 perseant inp->i_dotdot = inp->i_parent; 205 1.7 perseant (void) changeino(inp->i_number, "..", inp->i_parent); 206 1.1 perseant } 207 1.1 perseant /* 208 1.1 perseant * Mark all the directories that can be found from the root. 209 1.1 perseant */ 210 1.1 perseant propagate(); 211 1.1 perseant } 212 1.1 perseant 213 1.1 perseant static int 214 1.4 perseant pass2check(struct inodesc * idesc) 215 1.1 perseant { 216 1.34 dholland LFS_DIRHEADER *dirp = idesc->id_dirp; 217 1.12 perry struct inoinfo *inp; 218 1.7 perseant int n, entrysize, ret = 0; 219 1.26 dholland union lfs_dinode *dp; 220 1.14 christos const char *errmsg; 221 1.34 dholland LFS_DIRHEADER proto; 222 1.7 perseant char namebuf[MAXPATHLEN + 1]; 223 1.7 perseant char pathbuf[MAXPATHLEN + 1]; 224 1.1 perseant 225 1.1 perseant /* 226 1.1 perseant * check for "." 227 1.1 perseant */ 228 1.1 perseant if (idesc->id_entryno != 0) 229 1.1 perseant goto chk1; 230 1.31 dholland if (lfs_dir_getino(fs, dirp) != 0 && strcmp(lfs_dir_nameptr(fs, dirp), ".") == 0) { 231 1.28 dholland if (lfs_dir_getino(fs, dirp) != idesc->id_number) { 232 1.1 perseant direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 233 1.27 dholland if (reply("FIX") == 1) { 234 1.28 dholland lfs_dir_setino(fs, dirp, idesc->id_number); 235 1.1 perseant ret |= ALTERED; 236 1.27 dholland } 237 1.1 perseant } 238 1.27 dholland if (lfs_dir_gettype(fs, dirp) != LFS_DT_DIR) { 239 1.1 perseant direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 240 1.27 dholland if (reply("FIX") == 1) { 241 1.27 dholland lfs_dir_settype(fs, dirp, LFS_DT_DIR); 242 1.1 perseant ret |= ALTERED; 243 1.27 dholland } 244 1.1 perseant } 245 1.1 perseant goto chk1; 246 1.1 perseant } 247 1.1 perseant direrror(idesc->id_number, "MISSING '.'"); 248 1.28 dholland lfs_dir_setino(fs, &proto, idesc->id_number); 249 1.27 dholland lfs_dir_settype(fs, &proto, LFS_DT_DIR); 250 1.27 dholland lfs_dir_setnamlen(fs, &proto, 1); 251 1.33 dholland entrysize = LFS_DIRECTSIZ(fs, 1); 252 1.29 dholland lfs_dir_setreclen(fs, &proto, entrysize); 253 1.31 dholland if (lfs_dir_getino(fs, dirp) != 0 && strcmp(lfs_dir_nameptr(fs, dirp), "..") != 0) { 254 1.1 perseant pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 255 1.31 dholland lfs_dir_nameptr(fs, dirp)); 256 1.28 dholland } else if (lfs_dir_getreclen(fs, dirp) < entrysize) { 257 1.1 perseant pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 258 1.28 dholland } else if (lfs_dir_getreclen(fs, dirp) < 2 * entrysize) { 259 1.29 dholland /* convert this entry to a . entry */ 260 1.28 dholland lfs_dir_setreclen(fs, &proto, lfs_dir_getreclen(fs, dirp)); 261 1.29 dholland memcpy(dirp, &proto, sizeof(proto)); 262 1.31 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), ".", 1, 263 1.30 dholland lfs_dir_getreclen(fs, dirp)); 264 1.1 perseant if (reply("FIX") == 1) 265 1.1 perseant ret |= ALTERED; 266 1.1 perseant } else { 267 1.29 dholland /* split this entry and use the beginning for the . entry */ 268 1.28 dholland n = lfs_dir_getreclen(fs, dirp) - entrysize; 269 1.29 dholland memcpy(dirp, &proto, sizeof(proto)); 270 1.31 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), ".", 1, 271 1.30 dholland lfs_dir_getreclen(fs, dirp)); 272 1.1 perseant idesc->id_entryno++; 273 1.28 dholland lncntp[lfs_dir_getino(fs, dirp)]--; 274 1.29 dholland dirp = LFS_NEXTDIR(fs, dirp); 275 1.7 perseant memset(dirp, 0, (size_t) n); 276 1.28 dholland lfs_dir_setreclen(fs, dirp, n); 277 1.1 perseant if (reply("FIX") == 1) 278 1.1 perseant ret |= ALTERED; 279 1.1 perseant } 280 1.1 perseant chk1: 281 1.1 perseant if (idesc->id_entryno > 1) 282 1.1 perseant goto chk2; 283 1.1 perseant inp = getinoinfo(idesc->id_number); 284 1.28 dholland lfs_dir_setino(fs, &proto, inp->i_parent); 285 1.27 dholland lfs_dir_settype(fs, &proto, LFS_DT_DIR); 286 1.27 dholland lfs_dir_setnamlen(fs, &proto, 2); 287 1.33 dholland entrysize = LFS_DIRECTSIZ(fs, 2); 288 1.29 dholland lfs_dir_setreclen(fs, &proto, entrysize); 289 1.1 perseant if (idesc->id_entryno == 0) { 290 1.27 dholland n = LFS_DIRSIZ(fs, dirp); 291 1.28 dholland if (lfs_dir_getreclen(fs, dirp) < n + entrysize) 292 1.1 perseant goto chk2; 293 1.28 dholland lfs_dir_setreclen(fs, &proto, lfs_dir_getreclen(fs, dirp) - n); 294 1.28 dholland lfs_dir_setreclen(fs, dirp, n); 295 1.1 perseant idesc->id_entryno++; 296 1.28 dholland lncntp[lfs_dir_getino(fs, dirp)]--; 297 1.34 dholland dirp = (LFS_DIRHEADER *) ((char *) (dirp) + n); 298 1.28 dholland memset(dirp, 0, lfs_dir_getreclen(fs, &proto)); 299 1.28 dholland lfs_dir_setreclen(fs, dirp, lfs_dir_getreclen(fs, &proto)); 300 1.1 perseant } 301 1.31 dholland if (lfs_dir_getino(fs, dirp) != 0 && strcmp(lfs_dir_nameptr(fs, dirp), "..") == 0) { 302 1.28 dholland inp->i_dotdot = lfs_dir_getino(fs, dirp); 303 1.27 dholland if (lfs_dir_gettype(fs, dirp) != LFS_DT_DIR) { 304 1.1 perseant direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 305 1.27 dholland lfs_dir_settype(fs, dirp, LFS_DT_DIR); 306 1.1 perseant if (reply("FIX") == 1) 307 1.1 perseant ret |= ALTERED; 308 1.1 perseant } 309 1.1 perseant goto chk2; 310 1.1 perseant } 311 1.31 dholland if (lfs_dir_getino(fs, dirp) != 0 && strcmp(lfs_dir_nameptr(fs, dirp), ".") != 0) { 312 1.1 perseant fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 313 1.1 perseant pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 314 1.31 dholland lfs_dir_nameptr(fs, dirp)); 315 1.7 perseant inp->i_dotdot = (ino_t) - 1; 316 1.28 dholland } else if (lfs_dir_getreclen(fs, dirp) < entrysize) { 317 1.1 perseant fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 318 1.1 perseant pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 319 1.7 perseant inp->i_dotdot = (ino_t) - 1; 320 1.1 perseant } else if (inp->i_parent != 0) { 321 1.1 perseant /* 322 1.1 perseant * We know the parent, so fix now. 323 1.1 perseant */ 324 1.1 perseant inp->i_dotdot = inp->i_parent; 325 1.1 perseant fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 326 1.28 dholland lfs_dir_setreclen(fs, &proto, lfs_dir_getreclen(fs, dirp)); 327 1.7 perseant memcpy(dirp, &proto, (size_t) entrysize); 328 1.31 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), "..", 2, 329 1.30 dholland lfs_dir_getreclen(fs, dirp)); 330 1.1 perseant if (reply("FIX") == 1) 331 1.1 perseant ret |= ALTERED; 332 1.1 perseant } 333 1.1 perseant idesc->id_entryno++; 334 1.28 dholland if (lfs_dir_getino(fs, dirp) != 0) 335 1.28 dholland lncntp[lfs_dir_getino(fs, dirp)]--; 336 1.4 perseant return (ret | KEEPON); 337 1.1 perseant chk2: 338 1.28 dholland if (lfs_dir_getino(fs, dirp) == 0) 339 1.4 perseant return (ret | KEEPON); 340 1.27 dholland if (lfs_dir_getnamlen(fs, dirp) <= 2 && 341 1.31 dholland lfs_dir_nameptr(fs, dirp)[0] == '.' && 342 1.1 perseant idesc->id_entryno >= 2) { 343 1.27 dholland if (lfs_dir_getnamlen(fs, dirp) == 1) { 344 1.1 perseant direrror(idesc->id_number, "EXTRA '.' ENTRY"); 345 1.27 dholland if (reply("FIX") == 1) { 346 1.28 dholland lfs_dir_setino(fs, dirp, 0); 347 1.1 perseant ret |= ALTERED; 348 1.27 dholland } 349 1.1 perseant return (KEEPON | ret); 350 1.1 perseant } 351 1.31 dholland if (lfs_dir_nameptr(fs, dirp)[1] == '.') { 352 1.1 perseant direrror(idesc->id_number, "EXTRA '..' ENTRY"); 353 1.27 dholland if (reply("FIX") == 1) { 354 1.28 dholland lfs_dir_setino(fs, dirp, 0); 355 1.1 perseant ret |= ALTERED; 356 1.27 dholland } 357 1.1 perseant return (KEEPON | ret); 358 1.1 perseant } 359 1.1 perseant } 360 1.1 perseant idesc->id_entryno++; 361 1.1 perseant n = 0; 362 1.28 dholland if (lfs_dir_getino(fs, dirp) >= maxino) { 363 1.28 dholland fileerror(idesc->id_number, lfs_dir_getino(fs, dirp), "I OUT OF RANGE"); 364 1.1 perseant n = reply("REMOVE"); 365 1.28 dholland } else if (lfs_dir_getino(fs, dirp) == LFS_IFILE_INUM && 366 1.19 dholland idesc->id_number == ULFS_ROOTINO) { 367 1.27 dholland if (lfs_dir_gettype(fs, dirp) != LFS_DT_REG) { 368 1.28 dholland fileerror(idesc->id_number, lfs_dir_getino(fs, dirp), 369 1.7 perseant "BAD TYPE FOR IFILE"); 370 1.27 dholland if (reply("FIX") == 1) { 371 1.27 dholland lfs_dir_settype(fs, dirp, LFS_DT_REG); 372 1.4 perseant ret |= ALTERED; 373 1.27 dholland } 374 1.4 perseant } 375 1.28 dholland } else if (((lfs_dir_getino(fs, dirp) == ULFS_WINO && lfs_dir_gettype(fs, dirp) != LFS_DT_WHT) || 376 1.28 dholland (lfs_dir_getino(fs, dirp) != ULFS_WINO && lfs_dir_gettype(fs, dirp) == LFS_DT_WHT))) { 377 1.28 dholland fileerror(idesc->id_number, lfs_dir_getino(fs, dirp), "BAD WHITEOUT ENTRY"); 378 1.27 dholland if (reply("FIX") == 1) { 379 1.28 dholland lfs_dir_setino(fs, dirp, ULFS_WINO); 380 1.27 dholland lfs_dir_settype(fs, dirp, LFS_DT_WHT); 381 1.1 perseant ret |= ALTERED; 382 1.27 dholland } 383 1.1 perseant } else { 384 1.1 perseant again: 385 1.28 dholland switch (statemap[lfs_dir_getino(fs, dirp)]) { 386 1.1 perseant case USTATE: 387 1.1 perseant if (idesc->id_entryno <= 2) 388 1.1 perseant break; 389 1.28 dholland fileerror(idesc->id_number, lfs_dir_getino(fs, dirp), 390 1.28 dholland "UNALLOCATED"); 391 1.1 perseant n = reply("REMOVE"); 392 1.1 perseant break; 393 1.1 perseant 394 1.1 perseant case DCLEAR: 395 1.1 perseant case FCLEAR: 396 1.1 perseant if (idesc->id_entryno <= 2) 397 1.1 perseant break; 398 1.28 dholland if (statemap[lfs_dir_getino(fs, dirp)] == FCLEAR) 399 1.1 perseant errmsg = "DUP/BAD"; 400 1.1 perseant else if (!preen) 401 1.1 perseant errmsg = "ZERO LENGTH DIRECTORY"; 402 1.1 perseant else { 403 1.1 perseant n = 1; 404 1.1 perseant break; 405 1.1 perseant } 406 1.28 dholland fileerror(idesc->id_number, lfs_dir_getino(fs, dirp), errmsg); 407 1.1 perseant if ((n = reply("REMOVE")) == 1) 408 1.1 perseant break; 409 1.28 dholland dp = ginode(lfs_dir_getino(fs, dirp)); 410 1.28 dholland statemap[lfs_dir_getino(fs, dirp)] = 411 1.26 dholland (lfs_dino_getmode(fs, dp) & LFS_IFMT) == LFS_IFDIR ? DSTATE : FSTATE; 412 1.28 dholland lncntp[lfs_dir_getino(fs, dirp)] = lfs_dino_getnlink(fs, dp); 413 1.1 perseant goto again; 414 1.1 perseant 415 1.1 perseant case DSTATE: 416 1.1 perseant case DFOUND: 417 1.28 dholland inp = getinoinfo(lfs_dir_getino(fs, dirp)); 418 1.1 perseant if (inp->i_parent != 0 && idesc->id_entryno > 2) { 419 1.9 itojun getpathname(pathbuf, sizeof(pathbuf), 420 1.9 itojun idesc->id_number, idesc->id_number); 421 1.9 itojun getpathname(namebuf, sizeof(namebuf), 422 1.28 dholland lfs_dir_getino(fs, dirp), 423 1.28 dholland lfs_dir_getino(fs, dirp)); 424 1.1 perseant pwarn("%s %s %s\n", pathbuf, 425 1.7 perseant "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 426 1.7 perseant namebuf); 427 1.1 perseant if (preen) 428 1.1 perseant printf(" (IGNORED)\n"); 429 1.1 perseant else if ((n = reply("REMOVE")) == 1) 430 1.1 perseant break; 431 1.1 perseant } 432 1.1 perseant if (idesc->id_entryno > 2) 433 1.1 perseant inp->i_parent = idesc->id_number; 434 1.1 perseant /* fall through */ 435 1.1 perseant 436 1.1 perseant case FSTATE: 437 1.28 dholland if (lfs_dir_gettype(fs, dirp) != typemap[lfs_dir_getino(fs, dirp)]) { 438 1.28 dholland fileerror(idesc->id_number, 439 1.28 dholland lfs_dir_getino(fs, dirp), 440 1.7 perseant "BAD TYPE VALUE"); 441 1.13 perseant if (debug) 442 1.13 perseant pwarn("dir has %d, typemap has %d\n", 443 1.28 dholland lfs_dir_gettype(fs, dirp), typemap[lfs_dir_getino(fs, dirp)]); 444 1.28 dholland lfs_dir_settype(fs, dirp, typemap[lfs_dir_getino(fs, dirp)]); 445 1.1 perseant if (reply("FIX") == 1) 446 1.1 perseant ret |= ALTERED; 447 1.1 perseant } 448 1.28 dholland lncntp[lfs_dir_getino(fs, dirp)]--; 449 1.1 perseant break; 450 1.1 perseant 451 1.1 perseant default: 452 1.28 dholland errx(EEXIT, "BAD STATE %d FOR INODE I=%ju", 453 1.28 dholland statemap[lfs_dir_getino(fs, dirp)], 454 1.28 dholland (uintmax_t)lfs_dir_getino(fs, dirp)); 455 1.1 perseant } 456 1.1 perseant } 457 1.1 perseant if (n == 0) 458 1.4 perseant return (ret | KEEPON); 459 1.28 dholland lfs_dir_setino(fs, dirp, 0); 460 1.4 perseant return (ret | KEEPON | ALTERED); 461 1.1 perseant } 462 1.1 perseant /* 463 1.1 perseant * Routine to sort disk blocks. 464 1.1 perseant */ 465 1.1 perseant static int 466 1.4 perseant blksort(const void *inpp1, const void *inpp2) 467 1.1 perseant { 468 1.14 christos return ((*(const struct inoinfo *const *) inpp1)->i_blks[0] - 469 1.14 christos (*(const struct inoinfo *const *) inpp2)->i_blks[0]); 470 1.1 perseant } 471