1 1.53 riastrad /* $NetBSD: pass2.c,v 1.53 2023/07/04 20:40:53 riastradh Exp $ */ 2 1.12 cgd 3 1.1 cgd /* 4 1.6 mycroft * Copyright (c) 1980, 1986, 1993 5 1.6 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.36 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.18 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.12 cgd #if 0 35 1.20 lukem static char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95"; 36 1.12 cgd #else 37 1.53 riastrad __RCSID("$NetBSD: pass2.c,v 1.53 2023/07/04 20:40:53 riastradh Exp $"); 38 1.12 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #include <sys/param.h> 42 1.5 cgd #include <sys/time.h> 43 1.20 lukem 44 1.6 mycroft #include <ufs/ufs/dinode.h> 45 1.6 mycroft #include <ufs/ufs/dir.h> 46 1.6 mycroft #include <ufs/ffs/fs.h> 47 1.9 cgd 48 1.20 lukem #include <err.h> 49 1.21 lukem #include <stdio.h> 50 1.21 lukem #include <stdlib.h> 51 1.1 cgd #include <string.h> 52 1.16 christos 53 1.1 cgd #include "fsck.h" 54 1.17 christos #include "fsutil.h" 55 1.9 cgd #include "extern.h" 56 1.45 christos #include "exitvalues.h" 57 1.1 cgd 58 1.1 cgd #define MINDIRSIZE (sizeof (struct dirtemplate)) 59 1.1 cgd 60 1.41 xtraeme static int blksort(const void *, const void *); 61 1.41 xtraeme static int pass2check(struct inodesc *); 62 1.1 cgd 63 1.9 cgd void 64 1.40 xtraeme pass2(void) 65 1.1 cgd { 66 1.33 fvdl union dinode *dp; 67 1.29 mycroft struct inoinfo **inpp, *inp, *pinp; 68 1.1 cgd struct inoinfo **inpend; 69 1.33 fvdl struct inostat *rinfo, *info; 70 1.1 cgd struct inodesc curino; 71 1.33 fvdl union dinode dino; 72 1.33 fvdl int i, maxblk; 73 1.51 rin #ifndef NO_FFS_EI 74 1.48 christos unsigned ii; 75 1.51 rin #endif 76 1.1 cgd char pathbuf[MAXPATHLEN + 1]; 77 1.1 cgd 78 1.49 dholland rinfo = inoinfo(UFS_ROOTINO); 79 1.33 fvdl switch (rinfo->ino_state) { 80 1.1 cgd 81 1.1 cgd case USTATE: 82 1.1 cgd pfatal("ROOT INODE UNALLOCATED"); 83 1.26 fvdl if (reply("ALLOCATE") == 0) { 84 1.26 fvdl markclean = 0; 85 1.47 christos ckfini(1); 86 1.45 christos exit(FSCK_EXIT_CHECK_FAILED); 87 1.26 fvdl } 88 1.49 dholland if (allocdir(UFS_ROOTINO, UFS_ROOTINO, 0755) != UFS_ROOTINO) 89 1.45 christos errexit("CANNOT ALLOCATE ROOT INODE"); 90 1.1 cgd break; 91 1.1 cgd 92 1.1 cgd case DCLEAR: 93 1.1 cgd pfatal("DUPS/BAD IN ROOT INODE"); 94 1.1 cgd if (reply("REALLOCATE")) { 95 1.49 dholland freeino(UFS_ROOTINO); 96 1.49 dholland if (allocdir(UFS_ROOTINO, UFS_ROOTINO, 0755) != UFS_ROOTINO) 97 1.45 christos errexit("CANNOT ALLOCATE ROOT INODE"); 98 1.1 cgd break; 99 1.1 cgd } 100 1.26 fvdl markclean = 0; 101 1.26 fvdl if (reply("CONTINUE") == 0) { 102 1.47 christos ckfini(1); 103 1.45 christos exit(FSCK_EXIT_CHECK_FAILED); 104 1.26 fvdl } 105 1.1 cgd break; 106 1.1 cgd 107 1.1 cgd case FSTATE: 108 1.1 cgd case FCLEAR: 109 1.1 cgd pfatal("ROOT INODE NOT DIRECTORY"); 110 1.1 cgd if (reply("REALLOCATE")) { 111 1.49 dholland freeino(UFS_ROOTINO); 112 1.49 dholland if (allocdir(UFS_ROOTINO, UFS_ROOTINO, 0755) != UFS_ROOTINO) 113 1.45 christos errexit("CANNOT ALLOCATE ROOT INODE"); 114 1.1 cgd break; 115 1.1 cgd } 116 1.26 fvdl if (reply("FIX") == 0) { 117 1.26 fvdl markclean = 0; 118 1.47 christos ckfini(1); 119 1.45 christos exit(FSCK_EXIT_CHECK_FAILED); 120 1.26 fvdl } 121 1.49 dholland dp = ginode(UFS_ROOTINO); 122 1.43 skrll DIP_SET(dp, mode, 123 1.43 skrll iswap16((iswap16(DIP(dp, mode)) & ~IFMT) | IFDIR)); 124 1.1 cgd inodirty(); 125 1.1 cgd break; 126 1.1 cgd 127 1.1 cgd case DSTATE: 128 1.1 cgd break; 129 1.1 cgd 130 1.1 cgd default: 131 1.45 christos errexit("BAD STATE %d FOR ROOT INODE", rinfo->ino_state); 132 1.1 cgd } 133 1.10 mycroft if (newinofmt) { 134 1.49 dholland info = inoinfo(UFS_WINO); 135 1.33 fvdl info->ino_state = FSTATE; 136 1.33 fvdl info->ino_type = DT_WHT; 137 1.10 mycroft } 138 1.1 cgd /* 139 1.1 cgd * Sort the directory list into disk block order. 140 1.1 cgd */ 141 1.1 cgd qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); 142 1.1 cgd /* 143 1.1 cgd * Check the integrity of each directory. 144 1.1 cgd */ 145 1.7 mycroft memset(&curino, 0, sizeof(struct inodesc)); 146 1.1 cgd curino.id_type = DATA; 147 1.1 cgd curino.id_func = pass2check; 148 1.1 cgd inpend = &inpsort[inplast]; 149 1.1 cgd for (inpp = inpsort; inpp < inpend; inpp++) { 150 1.30 lukem if (got_siginfo) { 151 1.30 lukem fprintf(stderr, 152 1.31 agc "%s: phase 2: dir %ld of %d (%d%%)\n", cdevname(), 153 1.53 riastrad (long)(inpp - inpsort), (int)inplast, 154 1.30 lukem (int)((inpp - inpsort) * 100 / inplast)); 155 1.30 lukem got_siginfo = 0; 156 1.30 lukem } 157 1.39 christos #ifdef PROGRESS 158 1.38 christos progress_bar(cdevname(), preen ? NULL : "phase 2", 159 1.38 christos (inpp - inpsort), inplast); 160 1.39 christos #endif /* PROGRESS */ 161 1.1 cgd inp = *inpp; 162 1.1 cgd if (inp->i_isize == 0) 163 1.1 cgd continue; 164 1.1 cgd if (inp->i_isize < MINDIRSIZE) { 165 1.1 cgd direrror(inp->i_number, "DIRECTORY TOO SHORT"); 166 1.32 dbj inp->i_isize = roundup(MINDIRSIZE, dirblksiz); 167 1.1 cgd if (reply("FIX") == 1) { 168 1.1 cgd dp = ginode(inp->i_number); 169 1.43 skrll DIP_SET(dp, size, iswap64(inp->i_isize)); 170 1.1 cgd inodirty(); 171 1.24 bouyer } else 172 1.24 bouyer markclean = 0; 173 1.32 dbj } else if ((inp->i_isize & (dirblksiz - 1)) != 0) { 174 1.35 itojun getpathname(pathbuf, sizeof(pathbuf), inp->i_number, 175 1.35 itojun inp->i_number); 176 1.26 fvdl if (usedsoftdep) 177 1.28 lukem pfatal("%s %s: LENGTH %lld NOT MULTIPLE OF %d", 178 1.27 mrg "DIRECTORY", pathbuf, 179 1.32 dbj (long long)inp->i_isize, dirblksiz); 180 1.26 fvdl else 181 1.28 lukem pwarn("%s %s: LENGTH %lld NOT MULTIPLE OF %d", 182 1.27 mrg "DIRECTORY", pathbuf, 183 1.32 dbj (long long)inp->i_isize, dirblksiz); 184 1.1 cgd if (preen) 185 1.1 cgd printf(" (ADJUSTED)\n"); 186 1.32 dbj inp->i_isize = roundup(inp->i_isize, dirblksiz); 187 1.1 cgd if (preen || reply("ADJUST") == 1) { 188 1.1 cgd dp = ginode(inp->i_number); 189 1.43 skrll DIP_SET(dp, size, iswap64(inp->i_isize)); 190 1.1 cgd inodirty(); 191 1.24 bouyer } else 192 1.24 bouyer markclean = 0; 193 1.34 fvdl } 194 1.33 fvdl memset(&dino, 0, sizeof dino); 195 1.33 fvdl dp = &dino; 196 1.33 fvdl if (!is_ufs2) { 197 1.33 fvdl dp->dp1.di_mode = iswap16(IFDIR); 198 1.33 fvdl dp->dp1.di_size = iswap64(inp->i_isize); 199 1.49 dholland maxblk = inp->i_numblks < UFS_NDADDR ? inp->i_numblks : 200 1.49 dholland UFS_NDADDR; 201 1.33 fvdl for (i = 0; i < maxblk; i++) 202 1.33 fvdl dp->dp1.di_db[i] = inp->i_blks[i]; 203 1.49 dholland if (inp->i_numblks > UFS_NDADDR) { 204 1.49 dholland for (i = 0; i < UFS_NIADDR; i++) 205 1.34 fvdl dp->dp1.di_ib[i] = 206 1.49 dholland inp->i_blks[UFS_NDADDR + i]; 207 1.34 fvdl } 208 1.33 fvdl } else { 209 1.33 fvdl dp->dp2.di_mode = iswap16(IFDIR); 210 1.33 fvdl dp->dp2.di_size = iswap64(inp->i_isize); 211 1.49 dholland maxblk = inp->i_numblks < UFS_NDADDR ? inp->i_numblks : 212 1.49 dholland UFS_NDADDR; 213 1.33 fvdl for (i = 0; i < maxblk; i++) 214 1.33 fvdl dp->dp2.di_db[i] = inp->i_blks[i]; 215 1.49 dholland if (inp->i_numblks > UFS_NDADDR) { 216 1.49 dholland for (i = 0; i < UFS_NIADDR; i++) 217 1.34 fvdl dp->dp2.di_ib[i] = 218 1.49 dholland inp->i_blks[UFS_NDADDR + i]; 219 1.34 fvdl } 220 1.33 fvdl } 221 1.24 bouyer curino.id_number = inp->i_number; 222 1.24 bouyer curino.id_parent = inp->i_parent; 223 1.46 bouyer curino.id_uid = iswap32(DIP(dp, uid)); 224 1.46 bouyer curino.id_gid = iswap32(DIP(dp, gid)); 225 1.24 bouyer (void)ckinode(&dino, &curino); 226 1.33 fvdl } 227 1.24 bouyer 228 1.51 rin #ifndef NO_FFS_EI 229 1.33 fvdl /* 230 1.33 fvdl * Byte swapping in directory entries, if needed, has been done. 231 1.24 bouyer * Now rescan dirs for pass2check() 232 1.24 bouyer */ 233 1.53 riastrad if (do_dirswap) { 234 1.24 bouyer do_dirswap = 0; 235 1.24 bouyer for (inpp = inpsort; inpp < inpend; inpp++) { 236 1.24 bouyer inp = *inpp; 237 1.24 bouyer if (inp->i_isize == 0) 238 1.24 bouyer continue; 239 1.33 fvdl memset(&dino, 0, sizeof dino); 240 1.33 fvdl if (!is_ufs2) { 241 1.33 fvdl dino.dp1.di_mode = iswap16(IFDIR); 242 1.33 fvdl dino.dp1.di_size = iswap64(inp->i_isize); 243 1.48 christos for (ii = 0; ii < inp->i_numblks; ii++) 244 1.48 christos dino.dp1.di_db[ii] = inp->i_blks[ii]; 245 1.33 fvdl } else { 246 1.33 fvdl dino.dp2.di_mode = iswap16(IFDIR); 247 1.33 fvdl dino.dp2.di_size = iswap64(inp->i_isize); 248 1.48 christos for (ii = 0; ii < inp->i_numblks; ii++) 249 1.48 christos dino.dp2.di_db[ii] = inp->i_blks[ii]; 250 1.33 fvdl } 251 1.33 fvdl curino.id_number = inp->i_number; 252 1.33 fvdl curino.id_parent = inp->i_parent; 253 1.46 bouyer curino.id_uid = iswap32(DIP(&dino, uid)); 254 1.46 bouyer curino.id_gid = iswap32(DIP(&dino, gid)); 255 1.33 fvdl (void)ckinode(&dino, &curino); 256 1.33 fvdl } 257 1.24 bouyer } 258 1.51 rin #endif /* !NO_FFS_EI */ 259 1.24 bouyer 260 1.1 cgd /* 261 1.1 cgd * Now that the parents of all directories have been found, 262 1.1 cgd * make another pass to verify the value of `..' 263 1.1 cgd */ 264 1.1 cgd for (inpp = inpsort; inpp < inpend; inpp++) { 265 1.1 cgd inp = *inpp; 266 1.1 cgd if (inp->i_parent == 0 || inp->i_isize == 0) 267 1.1 cgd continue; 268 1.1 cgd if (inp->i_dotdot == inp->i_parent || 269 1.1 cgd inp->i_dotdot == (ino_t)-1) 270 1.1 cgd continue; 271 1.33 fvdl info = inoinfo(inp->i_parent); 272 1.1 cgd if (inp->i_dotdot == 0) { 273 1.1 cgd inp->i_dotdot = inp->i_parent; 274 1.52 chs if (debug) 275 1.52 chs fileerror(inp->i_parent, inp->i_number, 276 1.52 chs "DEFERRED MISSING '..' FIX"); 277 1.1 cgd (void)makeentry(inp->i_number, inp->i_parent, ".."); 278 1.33 fvdl info->ino_linkcnt--; 279 1.1 cgd continue; 280 1.1 cgd } 281 1.1 cgd fileerror(inp->i_parent, inp->i_number, 282 1.6 mycroft "BAD INODE NUMBER FOR '..'"); 283 1.24 bouyer if (reply("FIX") == 0) { 284 1.24 bouyer markclean = 0; 285 1.1 cgd continue; 286 1.24 bouyer } 287 1.33 fvdl inoinfo(inp->i_dotdot)->ino_linkcnt++; 288 1.33 fvdl info->ino_linkcnt--; 289 1.1 cgd inp->i_dotdot = inp->i_parent; 290 1.1 cgd (void)changeino(inp->i_number, "..", inp->i_parent); 291 1.1 cgd } 292 1.1 cgd /* 293 1.29 mycroft * Create a list of children for each directory. 294 1.29 mycroft */ 295 1.29 mycroft inpend = &inpsort[inplast]; 296 1.29 mycroft for (inpp = inpsort; inpp < inpend; inpp++) { 297 1.29 mycroft inp = *inpp; 298 1.33 fvdl info = inoinfo(inp->i_number); 299 1.37 mycroft inp->i_child = inp->i_sibling = 0; 300 1.33 fvdl if (info->ino_state == DFOUND) 301 1.33 fvdl info->ino_state = DSTATE; 302 1.29 mycroft } 303 1.29 mycroft for (inpp = inpsort; inpp < inpend; inpp++) { 304 1.29 mycroft inp = *inpp; 305 1.29 mycroft if (inp->i_parent == 0 || 306 1.49 dholland inp->i_number == UFS_ROOTINO) 307 1.29 mycroft continue; 308 1.29 mycroft pinp = getinoinfo(inp->i_parent); 309 1.29 mycroft inp->i_sibling = pinp->i_child; 310 1.29 mycroft pinp->i_child = inp; 311 1.29 mycroft } 312 1.29 mycroft /* 313 1.1 cgd * Mark all the directories that can be found from the root. 314 1.1 cgd */ 315 1.49 dholland propagate(UFS_ROOTINO); 316 1.38 christos 317 1.39 christos #ifdef PROGRESS 318 1.44 apb if (!preen) 319 1.38 christos progress_done(); 320 1.39 christos #endif /* PROGRESS */ 321 1.1 cgd } 322 1.1 cgd 323 1.16 christos static int 324 1.40 xtraeme pass2check(struct inodesc *idesc) 325 1.1 cgd { 326 1.18 lukem struct direct *dirp = idesc->id_dirp; 327 1.18 lukem struct inoinfo *inp; 328 1.33 fvdl struct inostat *info; 329 1.1 cgd int n, entrysize, ret = 0; 330 1.33 fvdl union dinode *dp; 331 1.42 christos const char *errmsg; 332 1.52 chs struct direct proto, *newdirp; 333 1.1 cgd char namebuf[MAXPATHLEN + 1]; 334 1.1 cgd char pathbuf[MAXPATHLEN + 1]; 335 1.1 cgd 336 1.6 mycroft /* 337 1.6 mycroft * If converting, set directory entry type. 338 1.6 mycroft */ 339 1.33 fvdl if (!is_ufs2 && doinglevel2 && iswap32(dirp->d_ino) > 0 && 340 1.33 fvdl iswap32(dirp->d_ino) < maxino) { 341 1.33 fvdl dirp->d_type = inoinfo(iswap32(dirp->d_ino))->ino_type; 342 1.6 mycroft ret |= ALTERED; 343 1.6 mycroft } 344 1.53 riastrad /* 345 1.1 cgd * check for "." 346 1.1 cgd */ 347 1.1 cgd if (idesc->id_entryno != 0) 348 1.1 cgd goto chk1; 349 1.1 cgd if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 350 1.24 bouyer if (iswap32(dirp->d_ino) != idesc->id_number) { 351 1.1 cgd direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 352 1.52 chs if (reply("FIX") == 1) { 353 1.52 chs dirp->d_ino = iswap32(idesc->id_number); 354 1.1 cgd ret |= ALTERED; 355 1.52 chs } else 356 1.24 bouyer markclean = 0; 357 1.1 cgd } 358 1.6 mycroft if (newinofmt && dirp->d_type != DT_DIR) { 359 1.6 mycroft direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 360 1.52 chs if (reply("FIX") == 1) { 361 1.52 chs dirp->d_type = DT_DIR; 362 1.6 mycroft ret |= ALTERED; 363 1.52 chs } else 364 1.24 bouyer markclean = 0; 365 1.6 mycroft } 366 1.1 cgd goto chk1; 367 1.1 cgd } 368 1.24 bouyer proto.d_ino = iswap32(idesc->id_number); 369 1.6 mycroft if (newinofmt) 370 1.6 mycroft proto.d_type = DT_DIR; 371 1.6 mycroft else 372 1.6 mycroft proto.d_type = 0; 373 1.1 cgd proto.d_namlen = 1; 374 1.35 itojun (void)strlcpy(proto.d_name, ".", sizeof(proto.d_name)); 375 1.10 mycroft # if BYTE_ORDER == LITTLE_ENDIAN 376 1.24 bouyer if (!newinofmt && !needswap) { 377 1.24 bouyer # else 378 1.24 bouyer if (!newinofmt && needswap) { 379 1.24 bouyer # endif 380 1.10 mycroft u_char tmp; 381 1.10 mycroft 382 1.10 mycroft tmp = proto.d_type; 383 1.10 mycroft proto.d_type = proto.d_namlen; 384 1.10 mycroft proto.d_namlen = tmp; 385 1.10 mycroft } 386 1.50 dholland entrysize = UFS_DIRSIZ(0, &proto, 0); 387 1.52 chs direrror(idesc->id_number, "MISSING '.'"); 388 1.52 chs errmsg = "ADD '.' ENTRY"; 389 1.52 chs if (iswap16(dirp->d_reclen) < entrysize + UFS_DIRSIZ(0, dirp, 0)) { 390 1.52 chs /* Not enough space to add '.', replace first entry with '.' */ 391 1.52 chs if (dirp->d_ino != 0) { 392 1.52 chs pwarn("\nFIRST ENTRY IN DIRECTORY CONTAINS %s\n", 393 1.52 chs dirp->d_name); 394 1.52 chs errmsg = "REPLACE WITH '.'"; 395 1.52 chs } 396 1.52 chs if (reply(errmsg) == 0) 397 1.52 chs goto chk1; 398 1.1 cgd proto.d_reclen = dirp->d_reclen; 399 1.20 lukem memmove(dirp, &proto, (size_t)entrysize); 400 1.52 chs ret |= ALTERED; 401 1.1 cgd } else { 402 1.52 chs /* Move over first entry and add '.' entry */ 403 1.52 chs if (reply(errmsg) == 0) 404 1.52 chs goto chk1; 405 1.52 chs newdirp = (struct direct *)((char *)(dirp) + entrysize); 406 1.52 chs dirp->d_reclen = iswap16(iswap16(dirp->d_reclen) - entrysize); 407 1.52 chs memmove(newdirp, dirp, iswap16(dirp->d_reclen)); 408 1.24 bouyer proto.d_reclen = iswap16(entrysize); 409 1.20 lukem memmove(dirp, &proto, (size_t)entrysize); 410 1.1 cgd idesc->id_entryno++; 411 1.52 chs inoinfo(idesc->id_number)->ino_linkcnt--; 412 1.52 chs dirp = newdirp; 413 1.52 chs ret |= ALTERED; 414 1.1 cgd } 415 1.1 cgd chk1: 416 1.1 cgd if (idesc->id_entryno > 1) 417 1.1 cgd goto chk2; 418 1.1 cgd inp = getinoinfo(idesc->id_number); 419 1.24 bouyer proto.d_ino = iswap32(inp->i_parent); 420 1.6 mycroft if (newinofmt) 421 1.6 mycroft proto.d_type = DT_DIR; 422 1.6 mycroft else 423 1.6 mycroft proto.d_type = 0; 424 1.1 cgd proto.d_namlen = 2; 425 1.35 itojun (void)strlcpy(proto.d_name, "..", sizeof(proto.d_name)); 426 1.35 itojun #if BYTE_ORDER == LITTLE_ENDIAN 427 1.35 itojun if (!newinofmt && !needswap) { 428 1.35 itojun #else 429 1.35 itojun if (!newinofmt && needswap) { 430 1.35 itojun #endif 431 1.35 itojun u_char tmp; 432 1.11 mycroft 433 1.35 itojun tmp = proto.d_type; 434 1.35 itojun proto.d_type = proto.d_namlen; 435 1.35 itojun proto.d_namlen = tmp; 436 1.35 itojun } 437 1.50 dholland entrysize = UFS_DIRSIZ(0, &proto, 0); 438 1.1 cgd if (idesc->id_entryno == 0) { 439 1.50 dholland n = UFS_DIRSIZ(0, dirp, 0); 440 1.24 bouyer if (iswap16(dirp->d_reclen) < n + entrysize) 441 1.1 cgd goto chk2; 442 1.24 bouyer proto.d_reclen = iswap16(iswap16(dirp->d_reclen) - n); 443 1.24 bouyer dirp->d_reclen = iswap16(n); 444 1.1 cgd idesc->id_entryno++; 445 1.33 fvdl inoinfo(iswap32(dirp->d_ino))->ino_linkcnt--; 446 1.1 cgd dirp = (struct direct *)((char *)(dirp) + n); 447 1.24 bouyer memset(dirp, 0, (size_t)iswap16(proto.d_reclen)); 448 1.1 cgd dirp->d_reclen = proto.d_reclen; 449 1.1 cgd } 450 1.1 cgd if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 451 1.24 bouyer inp->i_dotdot = iswap32(dirp->d_ino); 452 1.6 mycroft if (newinofmt && dirp->d_type != DT_DIR) { 453 1.6 mycroft direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 454 1.6 mycroft dirp->d_type = DT_DIR; 455 1.6 mycroft if (reply("FIX") == 1) 456 1.6 mycroft ret |= ALTERED; 457 1.24 bouyer else 458 1.24 bouyer markclean = 0; 459 1.6 mycroft } 460 1.1 cgd goto chk2; 461 1.1 cgd } 462 1.52 chs fileerror(inp->i_parent != 0 ? inp->i_parent : idesc->id_number, 463 1.52 chs idesc->id_number, "MISSING '..'"); 464 1.52 chs errmsg = "ADD '..' ENTRY"; 465 1.52 chs if (dirp->d_reclen < entrysize + UFS_DIRSIZ(0, dirp, 0)) { 466 1.52 chs /* No space to add '..', replace second entry with '..' */ 467 1.52 chs if (dirp->d_ino != 0) { 468 1.52 chs pfatal("SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 469 1.52 chs dirp->d_name); 470 1.52 chs errmsg = "REPLACE WITH '..'"; 471 1.52 chs } 472 1.52 chs if (reply(errmsg) == 0) { 473 1.52 chs inp->i_dotdot = (ino_t)-1; 474 1.52 chs goto chk2; 475 1.52 chs } 476 1.52 chs if (proto.d_ino == 0) { 477 1.52 chs /* Defer processing until parent known */ 478 1.52 chs idesc->id_entryno++; 479 1.52 chs if (debug) 480 1.52 chs printf("(FIX DEFERRED)\n"); 481 1.52 chs } 482 1.52 chs inp->i_dotdot = proto.d_ino; 483 1.1 cgd proto.d_reclen = dirp->d_reclen; 484 1.20 lukem memmove(dirp, &proto, (size_t)entrysize); 485 1.52 chs ret |= ALTERED; 486 1.52 chs } else { 487 1.52 chs /* Move over second entry and add '..' entry */ 488 1.52 chs if (reply(errmsg) == 0) { 489 1.52 chs inp->i_dotdot = (ino_t)-1; 490 1.52 chs goto chk2; 491 1.52 chs } 492 1.52 chs if (proto.d_ino == 0) { 493 1.52 chs /* Defer processing until parent known */ 494 1.52 chs idesc->id_entryno++; 495 1.52 chs if (debug) 496 1.52 chs printf("(FIX DEFERRED)\n"); 497 1.52 chs } 498 1.52 chs inp->i_dotdot = proto.d_ino; 499 1.52 chs if (dirp->d_ino == 0) { 500 1.52 chs proto.d_reclen = dirp->d_reclen; 501 1.52 chs memmove(dirp, &proto, (size_t)entrysize); 502 1.52 chs } else { 503 1.52 chs newdirp = (struct direct *)((char *)(dirp) + entrysize); 504 1.52 chs dirp->d_reclen -= entrysize; 505 1.52 chs memmove(newdirp, dirp, dirp->d_reclen); 506 1.52 chs proto.d_reclen = entrysize; 507 1.52 chs memmove(dirp, &proto, (size_t)entrysize); 508 1.52 chs if (dirp->d_ino != 0) { 509 1.52 chs idesc->id_entryno++; 510 1.52 chs inoinfo(dirp->d_ino)->ino_linkcnt--; 511 1.52 chs } 512 1.52 chs dirp = newdirp; 513 1.52 chs } 514 1.52 chs ret |= ALTERED; 515 1.1 cgd } 516 1.1 cgd chk2: 517 1.1 cgd if (dirp->d_ino == 0) 518 1.1 cgd return (ret|KEEPON); 519 1.1 cgd if (dirp->d_namlen <= 2 && 520 1.1 cgd dirp->d_name[0] == '.' && 521 1.1 cgd idesc->id_entryno >= 2) { 522 1.1 cgd if (dirp->d_namlen == 1) { 523 1.1 cgd direrror(idesc->id_number, "EXTRA '.' ENTRY"); 524 1.1 cgd dirp->d_ino = 0; 525 1.1 cgd if (reply("FIX") == 1) 526 1.1 cgd ret |= ALTERED; 527 1.24 bouyer else 528 1.24 bouyer markclean = 0; 529 1.1 cgd return (KEEPON | ret); 530 1.1 cgd } 531 1.1 cgd if (dirp->d_name[1] == '.') { 532 1.1 cgd direrror(idesc->id_number, "EXTRA '..' ENTRY"); 533 1.1 cgd dirp->d_ino = 0; 534 1.1 cgd if (reply("FIX") == 1) 535 1.1 cgd ret |= ALTERED; 536 1.24 bouyer else 537 1.24 bouyer markclean = 0; 538 1.1 cgd return (KEEPON | ret); 539 1.1 cgd } 540 1.1 cgd } 541 1.1 cgd idesc->id_entryno++; 542 1.1 cgd n = 0; 543 1.24 bouyer if (iswap32(dirp->d_ino) > maxino) { 544 1.1 cgd fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 545 1.1 cgd n = reply("REMOVE"); 546 1.24 bouyer if (n == 0) 547 1.24 bouyer markclean = 0; 548 1.10 mycroft } else if (newinofmt && 549 1.49 dholland ((iswap32(dirp->d_ino) == UFS_WINO && dirp->d_type != DT_WHT) || 550 1.49 dholland (iswap32(dirp->d_ino) != UFS_WINO && dirp->d_type == DT_WHT))) { 551 1.24 bouyer fileerror(idesc->id_number, iswap32(dirp->d_ino), "BAD WHITEOUT ENTRY"); 552 1.49 dholland dirp->d_ino = iswap32(UFS_WINO); 553 1.10 mycroft dirp->d_type = DT_WHT; 554 1.10 mycroft if (reply("FIX") == 1) 555 1.10 mycroft ret |= ALTERED; 556 1.24 bouyer else 557 1.24 bouyer markclean = 0; 558 1.1 cgd } else { 559 1.1 cgd again: 560 1.33 fvdl info = inoinfo(iswap32(dirp->d_ino)); 561 1.33 fvdl switch (info->ino_state) { 562 1.1 cgd case USTATE: 563 1.1 cgd if (idesc->id_entryno <= 2) 564 1.1 cgd break; 565 1.24 bouyer fileerror(idesc->id_number, iswap32(dirp->d_ino), "UNALLOCATED"); 566 1.1 cgd n = reply("REMOVE"); 567 1.24 bouyer if (n == 0) 568 1.24 bouyer markclean = 0; 569 1.1 cgd break; 570 1.1 cgd 571 1.1 cgd case DCLEAR: 572 1.1 cgd case FCLEAR: 573 1.1 cgd if (idesc->id_entryno <= 2) 574 1.1 cgd break; 575 1.33 fvdl if (info->ino_state == FCLEAR) 576 1.6 mycroft errmsg = "DUP/BAD"; 577 1.26 fvdl else if (!preen && !usedsoftdep) 578 1.1 cgd errmsg = "ZERO LENGTH DIRECTORY"; 579 1.6 mycroft else { 580 1.6 mycroft n = 1; 581 1.6 mycroft break; 582 1.6 mycroft } 583 1.24 bouyer fileerror(idesc->id_number, iswap32(dirp->d_ino), errmsg); 584 1.1 cgd if ((n = reply("REMOVE")) == 1) 585 1.1 cgd break; 586 1.24 bouyer dp = ginode(iswap32(dirp->d_ino)); 587 1.33 fvdl info->ino_state = 588 1.33 fvdl (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? DSTATE : FSTATE; 589 1.33 fvdl info->ino_linkcnt = iswap16(DIP(dp, nlink)); 590 1.1 cgd goto again; 591 1.1 cgd 592 1.1 cgd case DSTATE: 593 1.1 cgd case DFOUND: 594 1.24 bouyer inp = getinoinfo(iswap32(dirp->d_ino)); 595 1.1 cgd if (inp->i_parent != 0 && idesc->id_entryno > 2) { 596 1.35 itojun getpathname(pathbuf, sizeof(pathbuf), 597 1.35 itojun idesc->id_number, idesc->id_number); 598 1.35 itojun getpathname(namebuf, sizeof(namebuf), 599 1.35 itojun iswap32(dirp->d_ino), iswap32(dirp->d_ino)); 600 1.1 cgd pwarn("%s %s %s\n", pathbuf, 601 1.1 cgd "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 602 1.1 cgd namebuf); 603 1.1 cgd if (preen) 604 1.1 cgd printf(" (IGNORED)\n"); 605 1.1 cgd else if ((n = reply("REMOVE")) == 1) 606 1.1 cgd break; 607 1.1 cgd } 608 1.1 cgd if (idesc->id_entryno > 2) 609 1.1 cgd inp->i_parent = idesc->id_number; 610 1.1 cgd /* fall through */ 611 1.1 cgd 612 1.1 cgd case FSTATE: 613 1.33 fvdl if (newinofmt && dirp->d_type != info->ino_type) { 614 1.24 bouyer fileerror(idesc->id_number, iswap32(dirp->d_ino), 615 1.6 mycroft "BAD TYPE VALUE"); 616 1.33 fvdl dirp->d_type = info->ino_type; 617 1.6 mycroft if (reply("FIX") == 1) 618 1.6 mycroft ret |= ALTERED; 619 1.24 bouyer else 620 1.24 bouyer markclean = 0; 621 1.6 mycroft } 622 1.33 fvdl info->ino_linkcnt--; 623 1.1 cgd break; 624 1.1 cgd 625 1.1 cgd default: 626 1.45 christos errexit("BAD STATE %d FOR INODE I=%d", 627 1.33 fvdl info->ino_state, iswap32(dirp->d_ino)); 628 1.1 cgd } 629 1.1 cgd } 630 1.1 cgd if (n == 0) 631 1.1 cgd return (ret|KEEPON); 632 1.1 cgd dirp->d_ino = 0; 633 1.1 cgd return (ret|KEEPON|ALTERED); 634 1.1 cgd } 635 1.1 cgd 636 1.1 cgd /* 637 1.1 cgd * Routine to sort disk blocks. 638 1.1 cgd */ 639 1.16 christos static int 640 1.40 xtraeme blksort(const void *arg1, const void *arg2) 641 1.1 cgd { 642 1.20 lukem 643 1.42 christos return ((*(const struct inoinfo *const *)arg1)->i_blks[0] - 644 1.42 christos (*(const struct inoinfo *const *)arg2)->i_blks[0]); 645 1.1 cgd } 646