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