2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms are permitted
14 * provided that: (1) source distributions retain this entire copyright
15 * notice and comment, and (2) distributions including binaries display
16 * the following acknowledgement: ``This product includes software
17 * developed by the University of California, Berkeley and its contributors''
18 * in the documentation or other materials provided with the distribution
19 * and in all advertising materials mentioning features or use of this
20 * software. Neither the name of the University nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/mntent.h>
36 #include <sys/fs/ufs_fs.h>
37 #include <sys/vnode.h>
38 #include <sys/fs/ufs_inode.h>
40 #include <sys/fs/ufs_fsdir.h>
45 #define MINDIRSIZE (sizeof (struct dirtemplate))
47 static int blksort(const void *, const void *);
48 static int pass2check(struct inodesc
*);
53 struct dinode
*dp
, *dp2
, *dpattr
;
54 struct inoinfo
**inpp
, *inp
;
55 struct inoinfo
**inpend
;
56 struct inodesc curino
;
59 char pathbuf
[MAXPATHLEN
+ 1];
63 struct shadowclientinfo
*sci
;
65 switch (statemap
[UFSROOTINO
] & ~INDELAYD
) {
67 pfatal("ROOT INODE UNALLOCATED");
68 if (reply("ALLOCATE") == 0) {
69 errexit("Program terminated.");
71 if (allocdir(UFSROOTINO
, UFSROOTINO
, 0755, 0) != UFSROOTINO
)
72 errexit("CANNOT ALLOCATE ROOT INODE\n");
76 pfatal("DUPS/BAD IN ROOT INODE");
77 if (reply("REALLOCATE") == 1) {
78 freeino(UFSROOTINO
, TI_NOPARENT
);
79 if (allocdir(UFSROOTINO
, UFSROOTINO
,
80 0755, 0) != UFSROOTINO
)
81 errexit("CANNOT ALLOCATE ROOT INODE\n");
84 if (reply("CONTINUE") == 0) {
85 errexit("Program terminated.");
94 pfatal("ROOT INODE NOT DIRECTORY");
95 if (reply("REALLOCATE") == 1) {
96 freeino(UFSROOTINO
, TI_NOPARENT
);
97 if (allocdir(UFSROOTINO
, UFSROOTINO
, 0755, 0) !=
99 errexit("CANNOT ALLOCATE ROOT INODE\n");
102 if (reply("FIX") == 0) {
104 errexit("Program terminated.");
106 dp
= ginode(UFSROOTINO
);
107 dp
->di_mode
&= ~IFMT
;
108 dp
->di_mode
|= IFDIR
;
117 errexit("BAD STATE 0x%x FOR ROOT INODE\n",
118 statemap
[UFSROOTINO
]);
120 statemap
[UFSROOTINO
] = DFOUND
;
123 * Technically, we do know who the parent is. However,
124 * if this is set, then we'll get confused during the
125 * second-dir-entry-is-dotdot test for the root inode.
127 inp
= getinoinfo(UFSROOTINO
);
128 if (inp
!= NULL
&& inp
->i_dotdot
!= 0)
132 * Sort the directory list into disk block order. There's no
133 * requirement to do this, but it may help improve our i/o times
136 qsort((void *)inpsort
, (size_t)inplast
, sizeof (*inpsort
), blksort
);
138 * Check the integrity of each directory. In general, we treat
139 * attribute directories just like normal ones. Only the handling
140 * of .. is really different.
142 (void) memset(&dino
, 0, sizeof (struct dinode
));
143 dino
.di_mode
= IFDIR
;
144 inpend
= &inpsort
[inplast
];
145 for (inpp
= inpsort
; inpp
< inpend
; inpp
++) {
148 if (inp
->i_isize
== 0)
151 /* != DSTATE also covers case of == USTATE */
152 if (((statemap
[inp
->i_number
] & STMASK
) != DSTATE
) ||
153 ((statemap
[inp
->i_number
] & INCLEAR
) == INCLEAR
))
156 if (inp
->i_isize
< (offset_t
)MINDIRSIZE
) {
157 direrror(inp
->i_number
, "DIRECTORY TOO SHORT");
158 inp
->i_isize
= (offset_t
)roundup(MINDIRSIZE
, DIRBLKSIZ
);
159 if (reply("FIX") == 1) {
160 dp
= ginode(inp
->i_number
);
161 dp
->di_size
= (uoff_t
)inp
->i_isize
;
167 if ((inp
->i_isize
& (offset_t
)(DIRBLKSIZ
- 1)) != 0) {
168 getpathname(pathbuf
, inp
->i_number
, inp
->i_number
);
169 pwarn("DIRECTORY %s: LENGTH %lld NOT MULTIPLE OF %d",
170 pathbuf
, (longlong_t
)inp
->i_isize
, DIRBLKSIZ
);
171 inp
->i_isize
= roundup(inp
->i_isize
,
172 (offset_t
)DIRBLKSIZ
);
173 if (preen
|| reply("ADJUST") == 1) {
174 dp
= ginode(inp
->i_number
);
176 (uoff_t
)roundup(inp
->i_isize
,
177 (offset_t
)DIRBLKSIZ
);
180 (void) printf(" (ADJUSTED)\n");
185 dp
= ginode(inp
->i_number
);
186 if ((dp
->di_mode
& IFMT
) == IFATTRDIR
&&
187 (dp
->di_cflags
& IXATTR
) == 0) {
188 pwarn("ATTRIBUTE DIRECTORY I=%d MISSING IXATTR FLAG",
190 if (preen
|| reply("CORRECT") == 1) {
191 dp
->di_cflags
|= IXATTR
;
194 (void) printf(" (CORRECTED)\n");
198 dp
->di_size
= (uoff_t
)inp
->i_isize
;
199 (void) memmove((void *)&dp
->di_db
[0], (void *)&inp
->i_blks
[0],
201 init_inodesc(&curino
);
202 curino
.id_type
= DATA
;
203 curino
.id_func
= pass2check
;
204 curino
.id_number
= inp
->i_number
;
205 curino
.id_parent
= inp
->i_parent
;
206 curino
.id_fix
= DONTKNOW
;
207 (void) ckinode(dp
, &curino
, CKI_TRAVERSE
);
210 * Make sure we mark attrdirs as DFOUND, since they won't
211 * be located during normal scan of standard directories.
213 if (curino
.id_parent
== 0) {
214 dpattr
= ginode(inp
->i_number
);
215 if ((dpattr
->di_mode
& IFMT
) == IFATTRDIR
) {
216 for (sci
= attrclientinfo
; sci
!= NULL
;
218 if (sci
->shadow
== inp
->i_number
) {
220 sci
->clients
->client
[0];
221 statemap
[inp
->i_number
] =
231 * Now that the parents of all directories have been found,
232 * make another pass to verify the value of ..
234 for (inpp
= inpsort
; inpp
< inpend
; inpp
++) {
236 if (inp
->i_parent
== 0 || inp
->i_isize
== 0)
239 * There are only directories in inpsort[], so only
240 * directory-related states need to be checked. There
241 * should never be any flags associated with USTATE.
243 if ((statemap
[inp
->i_number
] & STMASK
) == DCLEAR
||
244 statemap
[inp
->i_number
] == USTATE
) {
247 if (statemap
[inp
->i_parent
] == DFOUND
&&
248 S_IS_DUNFOUND(statemap
[inp
->i_number
])) {
249 statemap
[inp
->i_number
] = DFOUND
|
250 (statemap
[inp
->i_number
] & INCLEAR
);
252 if (inp
->i_dotdot
== inp
->i_parent
||
253 inp
->i_dotdot
== (fsck_ino_t
)-1) {
256 if (inp
->i_dotdot
== 0) {
257 inp
->i_dotdot
= inp
->i_parent
;
258 fileerror(inp
->i_parent
, inp
->i_number
,
260 if (reply("FIX") == 0) {
264 dp
= ginode(inp
->i_number
);
266 dirtype
= (dp
->di_mode
& IFMT
);
269 * See if this is an attrdir that we located in pass1.
270 * i.e. it was on an i_oeftflag of some other inode.
271 * if it isn't found then we have an orphaned attrdir
272 * that needs to be tossed into lost+found.
274 if (dirtype
== IFATTRDIR
) {
275 for (sci
= attrclientinfo
;
278 if (sci
->shadow
== inp
->i_number
) {
280 sci
->clients
->client
[0];
287 * We've already proven there's no "..", so this
288 * can't create a duplicate.
290 if (makeentry(inp
->i_number
, inp
->i_parent
, "..")) {
293 * is it an orphaned attrdir?
295 if (dirtype
== IFATTRDIR
&& found
== 0) {
297 * Throw it into lost+found
299 if (linkup(inp
->i_number
, lfdir
,
302 "Unable to move attrdir I=%d to lost+found\n",
306 maybe_convert_attrdir_to_dir(
309 if (dirtype
== IFDIR
) {
311 lncntp
[inp
->i_parent
], -1);
312 if (errmsg
!= NULL
) {
314 inp
->i_parent
, IFDIR
,
316 if (statemap
[inp
->i_parent
] !=
325 TRACK_LNCNTP(inp
->i_parent
,
326 lncntp
[inp
->i_parent
]--);
331 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
333 inp
->i_dotdot
= (fsck_ino_t
)-1;
337 dp2
= ginode(inp
->i_parent
);
339 if ((dp2
->di_mode
& IFMT
) == IFATTRDIR
) {
342 fileerror(inp
->i_parent
, inp
->i_number
,
343 "BAD INODE NUMBER FOR '..'");
344 if (reply("FIX") == 0) {
349 LINK_RANGE(errmsg
, lncntp
[inp
->i_dotdot
], 1);
350 if (errmsg
!= NULL
) {
351 LINK_CLEAR(errmsg
, inp
->i_dotdot
, IFDIR
, &ldesc
);
352 if (statemap
[inp
->i_dotdot
] != USTATE
) {
353 /* iscorrupt is already set */
357 TRACK_LNCNTP(inp
->i_dotdot
, lncntp
[inp
->i_dotdot
]++);
359 LINK_RANGE(errmsg
, lncntp
[inp
->i_parent
], -1);
360 if (errmsg
!= NULL
) {
361 LINK_CLEAR(errmsg
, inp
->i_parent
, IFDIR
, &ldesc
);
362 if (statemap
[inp
->i_parent
] != USTATE
) {
363 /* iscorrupt is already set */
367 TRACK_LNCNTP(inp
->i_parent
, lncntp
[inp
->i_parent
]--);
369 inp
->i_dotdot
= inp
->i_parent
;
370 (void) changeino(inp
->i_number
, "..", inp
->i_parent
);
373 * Mark all the directories that can be found from the root.
379 * Sanity-check a single directory entry. Which entry is being
380 * examined is tracked via idesc->id_entryno. There are two
381 * special ones, 0 (.) and 1 (..). Those have to exist in order
382 * in the first two locations in the directory, and have the usual
383 * properties. All other entries have to not be for either of
384 * the special two, and the inode they reference has to be
387 * This is only called from dirscan(), which looks for the
388 * ALTERED flag after each invocation. If it finds it, the
389 * relevant buffer gets pushed out, so we don't have to worry
392 #define PASS2B_PROMPT "REMOVE DIRECTORY ENTRY FROM I=%d"
395 pass2check(struct inodesc
*idesc
)
397 struct direct
*dirp
= idesc
->id_dirp
;
398 struct inodesc ldesc
;
400 short reclen
, entrysize
;
402 int act
, update_lncntp
;
403 struct dinode
*dp
, *pdirp
, *attrdirp
;
406 char namebuf
[MAXPATHLEN
+ 1];
407 char pathbuf
[MAXPATHLEN
+ 1];
413 if (idesc
->id_entryno
!= 0)
418 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, ".") == 0) {
419 if (dirp
->d_ino
!= idesc
->id_number
) {
420 direrror(idesc
->id_number
, "BAD INODE NUMBER FOR '.'");
421 dirp
->d_ino
= idesc
->id_number
;
422 if (reply("FIX") == 1) {
431 * Build up a new one, and make sure there's room to put
432 * it where it belongs.
434 direrror(idesc
->id_number
, "MISSING '.'");
435 proto
.d_ino
= idesc
->id_number
;
437 (void) strcpy(proto
.d_name
, ".");
438 entrysize
= DIRSIZ(&proto
);
439 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, "..") != 0) {
440 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
443 } else if ((int)dirp
->d_reclen
< entrysize
) {
444 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
446 } else if ((int)dirp
->d_reclen
< 2 * entrysize
) {
448 * No room for another entry after us ("." is the
449 * smallest entry you can have), so just put all
450 * of the old entry's space into the new entry.
452 * Because we don't touch id_entryno, we end up going
453 * through the chk2 tests as well.
455 proto
.d_reclen
= dirp
->d_reclen
;
456 (void) memmove((void *)dirp
, (void *)&proto
,
458 if (reply("FIX") == 1) {
465 * There's enough room for an entire additional entry
466 * after this, so create the "." entry and follow it
467 * with an empty entry that covers the rest of the
470 * The increment of id_entryno means we'll skip the
471 * "." case of chk1, doing the ".." tests instead.
472 * Since we know that there's not a ".." where it
473 * should be (because we just created an empty entry
474 * there), that's the best way of getting it recreated
477 reclen
= dirp
->d_reclen
- entrysize
;
478 proto
.d_reclen
= entrysize
;
479 (void) memmove((void *)dirp
, (void *)&proto
,
483 * Make sure the link count is in range before updating
484 * it. This makes the assumption that the link count
485 * for this inode included one for ".", even though
486 * there wasn't a "." entry. Even if that's not true,
487 * it's a reasonable working hypothesis, and the link
488 * count verification done in pass4 will fix it for
491 LINK_RANGE(errmsg
, lncntp
[dirp
->d_ino
], -1);
492 if (errmsg
!= NULL
) {
493 LINK_CLEAR(errmsg
, dirp
->d_ino
, IFDIR
, &ldesc
);
494 if (statemap
[dirp
->d_ino
] == USTATE
) {
496 * The inode got zapped, so reset the
497 * directory entry. Extend it to also
498 * cover the space we were going to make
502 dirp
->d_reclen
+= reclen
;
509 * Create the new empty entry.
511 /* LINTED pointer cast alignment (entrysize is valid) */
512 dirp
= (struct direct
*)((char *)(dirp
) + entrysize
);
513 (void) memset(dirp
, 0, (size_t)reclen
);
514 dirp
->d_reclen
= reclen
;
517 * Did the user want us to create a new "."? This
518 * query assumes that the direrror(MISSING) was the
519 * last thing printed, so if the LINK_RANGE() check
520 * fails, it can't pass through here.
522 if (reply("FIX") == 1) {
523 TRACK_LNCNTP(idesc
->id_number
,
524 lncntp
[idesc
->id_number
]--);
532 * XXX The next few lines are needed whether we're processing "."
533 * or "..". However, there are some extra steps still needed
534 * for the former, hence the big block of code for
535 * id_entryno == 0. Alternatively, there could be a label just
536 * before this comment, and everything through the end of that
537 * block moved there. In some ways, that might make the
538 * control flow more logical (factoring out to separate functions
539 * would be even better).
543 if (idesc
->id_entryno
> 1)
545 inp
= getinoinfo(idesc
->id_number
);
548 * This is a can't-happen, since inodes get cached before
549 * we get called on them.
551 errexit("pass2check got NULL from getinoinfo at chk1 I=%d\n",
554 proto
.d_ino
= inp
->i_parent
;
556 (void) strcpy(proto
.d_name
, "..");
557 entrysize
= DIRSIZ(&proto
);
558 if (idesc
->id_entryno
== 0) {
560 * We may not actually need to split things up, but if
561 * there's room to do so, we should, as that implies
562 * that the "." entry is larger than it is supposed
563 * to be, and therefore there's something wrong, albeit
564 * possibly harmlessly so.
566 reclen
= DIRSIZ(dirp
);
567 if ((int)dirp
->d_reclen
< reclen
+ entrysize
) {
569 * Not enough room for inserting a ".." after
575 * There's enough room for an entire additional entry
576 * after "."'s, so split it up. There's no reason "."
577 * should be bigger than the minimum, so shrink it to
578 * fit, too. Since by the time we're done with this
579 * part, dirp will be pointing at where ".." should be,
580 * update id_entryno to show that that's the entry
583 proto
.d_reclen
= dirp
->d_reclen
- reclen
;
584 dirp
->d_reclen
= reclen
;
586 if (dirp
->d_ino
> 0 && dirp
->d_ino
<= maxino
) {
588 * Account for the link to ourselves.
590 LINK_RANGE(errmsg
, lncntp
[dirp
->d_ino
], -1);
591 if (errmsg
!= NULL
) {
592 LINK_CLEAR(errmsg
, dirp
->d_ino
, IFDIR
, &ldesc
);
593 if (statemap
[dirp
->d_ino
] == USTATE
) {
595 * We were going to split the entry
596 * up, but the link count overflowed.
597 * Since we got rid of the inode,
598 * we need to also zap the directory
599 * entry, and restoring the original
600 * state of things is the least-bad
604 dirp
->d_reclen
+= proto
.d_reclen
;
609 TRACK_LNCNTP(dirp
->d_ino
, lncntp
[dirp
->d_ino
]--);
611 * Make sure the new entry doesn't get interpreted
612 * as having actual content.
614 /* LINTED pointer cast alignment (reclen is valid) */
615 dirp
= (struct direct
*)((char *)(dirp
) + reclen
);
616 (void) memset(dirp
, 0, (size_t)proto
.d_reclen
);
617 dirp
->d_reclen
= proto
.d_reclen
;
620 * Everything was fine, up until we realized that
621 * the indicated inode was impossible. By clearing
622 * d_ino here, we'll trigger the recreation of it
623 * down below, using i_parent. Unlike the other
624 * half of this if(), we're everything so it shows
625 * that we're still on the "." entry.
627 fileerror(idesc
->id_number
, dirp
->d_ino
,
630 if (reply("FIX") == 1) {
638 * Record this ".." inode, but only if we haven't seen one before.
639 * If this isn't the first, it'll get cleared below, and so we
640 * want to remember the entry that'll still be around later.
642 if (dirp
->d_ino
!= 0 && inp
->i_dotdot
== 0 &&
643 strcmp(dirp
->d_name
, "..") == 0) {
644 inp
->i_dotdot
= dirp
->d_ino
;
647 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, "..") != 0) {
648 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
649 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
652 inp
->i_dotdot
= (fsck_ino_t
)-1;
653 } else if ((int)dirp
->d_reclen
< entrysize
) {
654 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
655 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
656 /* XXX Same consideration as immediately above. */
658 inp
->i_dotdot
= (fsck_ino_t
)-1;
659 } else if (inp
->i_parent
!= 0) {
661 * We know the parent, so fix now.
663 proto
.d_ino
= inp
->i_dotdot
= inp
->i_parent
;
664 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
666 * Lint won't be quiet about d_reclen being set but not
667 * used. It apparently doesn't understand the implications
668 * of calling memmove(), and won't believe us that it's ok.
670 proto
.d_reclen
= dirp
->d_reclen
;
671 (void) memmove((void *)dirp
, (void *)&proto
,
673 if (reply("FIX") == 1) {
678 } else if (inp
->i_number
== UFSROOTINO
) {
680 * Always know parent of root inode, so fix now.
682 proto
.d_ino
= inp
->i_dotdot
= inp
->i_parent
= UFSROOTINO
;
683 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
685 * Lint won't be quiet about d_reclen being set but not
686 * used. It apparently doesn't understand the implications
687 * of calling memmove(), and won't believe us that it's ok.
689 proto
.d_reclen
= dirp
->d_reclen
;
690 (void) memmove((void *)dirp
, (void *)&proto
, (size_t)entrysize
);
691 if (reply("FIX") == 1) {
698 if (dirp
->d_ino
!= 0) {
699 LINK_RANGE(errmsg
, lncntp
[dirp
->d_ino
], -1);
700 if (errmsg
!= NULL
) {
701 LINK_CLEAR(errmsg
, dirp
->d_ino
, IFDIR
, &ldesc
);
702 if (statemap
[dirp
->d_ino
] == USTATE
) {
707 TRACK_LNCNTP(dirp
->d_ino
, lncntp
[dirp
->d_ino
]--);
711 if (dirp
->d_ino
== 0)
713 if (dirp
->d_namlen
<= 2 &&
714 dirp
->d_name
[0] == '.' &&
715 idesc
->id_entryno
>= 2) {
716 if (dirp
->d_namlen
== 1) {
717 direrror(idesc
->id_number
, "EXTRA '.' ENTRY");
719 if (reply("FIX") == 1) {
724 return (KEEPON
| ret
);
726 if (dirp
->d_name
[1] == '.') {
727 direrror(idesc
->id_number
, "EXTRA '..' ENTRY");
729 if (reply("FIX") == 1) {
734 return (KEEPON
| ret
);
738 * Because of this increment, all tests for skipping . and ..
739 * below are ``> 2'', not ``> 1'' as would logically be expected.
744 * The obvious check would be for d_ino < UFSROOTINO. However,
745 * 1 is a valid inode number. Although it isn't currently used,
746 * as it was once the bad block list, there's nothing to prevent
747 * it from acquiring a new purpose in the future. So, don't
748 * arbitrarily disallow it. We don't test for <= zero, because
752 if (dirp
->d_ino
> maxino
|| dirp
->d_ino
== 0) {
753 fileerror(idesc
->id_number
, dirp
->d_ino
, "I OUT OF RANGE");
754 act
= (reply(PASS2B_PROMPT
, idesc
->id_number
) == 1);
758 switch (statemap
[dirp
->d_ino
] & ~(INDELAYD
)) {
760 if (idesc
->id_entryno
<= 2)
762 fileerror(idesc
->id_number
, dirp
->d_ino
, "UNALLOCATED");
763 act
= (reply(PASS2B_PROMPT
, idesc
->id_number
) == 1);
769 if (idesc
->id_entryno
<= 2)
771 dp
= ginode(dirp
->d_ino
);
772 if (statemap
[dirp
->d_ino
] == DCLEAR
) {
773 errmsg
= ((dp
->di_mode
& IFMT
) == IFATTRDIR
) ?
774 "REFERENCE TO ZERO LENGTH ATTRIBUTE DIRECTORY" :
775 "REFERENCE TO ZERO LENGTH DIRECTORY";
776 inp
= getinoinfo(dirp
->d_ino
);
779 * The inode doesn't exist, as all
780 * should be cached by now. This
781 * gets caught by the range check
782 * above, and so it is a can't-happen
785 errexit("pass2check found a zero-len "
786 "reference to bad I=%d\n",
789 if (inp
->i_parent
!= 0) {
791 "Multiple links to I=%d, link counts wrong, rerun fsck\n",
795 } else if (statemap
[dirp
->d_ino
] == SCLEAR
) {
797 * In theory, this is a can't-happen,
798 * because shadows don't appear in directory
799 * entries. However, an inode might've
800 * been reused without a stale directory
801 * entry having been cleared, so check
802 * for it just in case. We'll check for
803 * the no-dir-entry shadows in pass3b().
805 errmsg
= "ZERO LENGTH SHADOW";
809 fileerror(idesc
->id_number
, dirp
->d_ino
, errmsg
);
810 if ((act
= reply(PASS2B_PROMPT
, idesc
->id_number
)) == 1)
813 * Not doing anything about it, so just try
814 * again as whatever the base type was.
816 * fileerror() invalidated dp. Lint thinks this
817 * is unnecessary, but we know better.
819 dp
= ginode(dirp
->d_ino
);
820 statemap
[dirp
->d_ino
] &= STMASK
;
821 TRACK_LNCNTP(dirp
->d_ino
, lncntp
[dirp
->d_ino
] = 0);
826 if (statemap
[idesc
->id_number
] == DFOUND
) {
827 statemap
[dirp
->d_ino
] = DFOUND
;
833 * This is encouraging the best-practice of not
834 * hard-linking directories. It's legal (see POSIX),
835 * but not a good idea. So, don't consider it an
836 * instance of corruption, but offer to nuke it.
838 inp
= getinoinfo(dirp
->d_ino
);
841 * Same can't-happen argument as in the
842 * zero-len case above.
844 errexit("pass2check found bad reference to "
845 "hard-linked directory I=%d\n",
848 dp
= ginode(idesc
->id_number
);
849 if (inp
->i_parent
!= 0 && idesc
->id_entryno
> 2 &&
850 ((dp
->di_mode
& IFMT
) != IFATTRDIR
)) {
852 * XXX For nested dirs, this can report
853 * the same name for both paths.
855 getpathname(pathbuf
, idesc
->id_number
,
857 getpathname(namebuf
, dirp
->d_ino
, dirp
->d_ino
);
859 "%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n",
862 (void) printf(" (IGNORED)\n");
863 else if ((act
= reply(PASS2B_PROMPT
,
864 idesc
->id_number
)) == 1) {
871 if ((idesc
->id_entryno
> 2) &&
872 (inp
->i_extattr
!= idesc
->id_number
)) {
873 inp
->i_parent
= idesc
->id_number
;
880 * There's nothing to do for normal file-like
881 * things. Extended attributes come through
882 * here as well, though, and for them, .. may point
883 * to a file. In this situation we don't want
884 * to decrement link count as it was already
885 * decremented when the entry was seen in the
886 * directory it actually lives in.
888 pdirp
= ginode(idesc
->id_number
);
889 pdirtype
= (pdirp
->di_mode
& IFMT
);
890 dp
= ginode(dirp
->d_ino
);
891 isattr
= (dp
->di_cflags
& IXATTR
);
893 if (pdirtype
== IFATTRDIR
&&
894 (strcmp(dirp
->d_name
, "..") == 0)) {
896 if (dp
->di_oeftflag
!= 0) {
897 attrdirp
= ginode(dp
->di_oeftflag
);
900 * is it really an attrdir?
901 * if so, then don't do anything.
904 if ((attrdirp
->di_mode
& IFMT
) ==
907 dp
= ginode(dirp
->d_ino
);
910 * Rare corner case - the attrdir's ..
911 * points to the attrdir itself.
913 if (dirp
->d_ino
== idesc
->id_number
) {
915 TRACK_LNCNTP(idesc
->id_number
,
916 lncntp
[idesc
->id_number
]--);
919 * Lets see if we have an orphaned attrdir
920 * that thinks it belongs to this file.
921 * Only re-connect it if the current
922 * attrdir is 0 or not an attrdir.
924 if ((dp
->di_oeftflag
!= idesc
->id_number
) &&
925 (dontreconnect
== 0)) {
926 fileerror(idesc
->id_number
,
928 "Attribute directory I=%d not "
929 "attached to file I=%d\n",
930 idesc
->id_number
, dirp
->d_ino
);
931 if ((act
= reply("FIX")) == 1) {
932 dp
= ginode(dirp
->d_ino
);
935 "debug: changing i=%d's oeft from %d ",
941 (void) printf("to %d\n",
944 registershadowclient(
949 dp
= ginode(dirp
->d_ino
);
953 * This can only be true if we've modified
954 * an inode/xattr connection, and we
955 * don't keep track of those in the link
956 * counts. So, skipping the checks just
957 * after this is not a problem.
960 return (KEEPON
| ALTERED
);
963 * Don't screw up link counts for directories.
964 * If we aren't careful we can perform
965 * an extra decrement, since the .. of
966 * an attrdir could be either a file or a
967 * directory. If it's a file then its link
968 * should be correct after it is seen when the
969 * directory it lives in scanned.
971 if ((pdirtype
== IFATTRDIR
) &&
972 ((dp
->di_mode
& IFMT
) == IFDIR
))
974 if ((dp
->di_mode
& IFMT
) != IFDIR
)
977 } else if ((pdirtype
!= IFATTRDIR
) ||
978 (strcmp(dirp
->d_name
, ".") != 0)) {
979 if ((pdirtype
== IFDIR
) && isattr
) {
980 fileerror(idesc
->id_number
,
982 "File should NOT be marked as "
983 "extended attribute\n");
984 if ((act
= reply("FIX")) == 1) {
985 dp
= ginode(dirp
->d_ino
);
988 "changing i=%d's cflags from 0x%x to ",
992 dp
->di_cflags
&= ~IXATTR
;
994 (void) printf("0x%x\n",
997 if ((dp
->di_mode
& IFMT
) ==
1001 dp
->di_mode
|= IFDIR
;
1005 if (pdirp
->di_oeftflag
1007 pdirp
->di_oeftflag
= 0;
1013 if (pdirtype
== IFATTRDIR
&&
1015 fileerror(idesc
->id_number
,
1017 "File should BE marked as "
1018 "extended attribute\n");
1019 if ((act
= reply("FIX")) == 1) {
1022 dp
->di_cflags
|= IXATTR
;
1024 * Make sure it's a file
1025 * while we're at it.
1027 dp
->di_mode
&= ~IFMT
;
1028 dp
->di_mode
|= IFREG
;
1035 if (breakout
== 0 || dontreconnect
== 0) {
1036 TRACK_LNCNTP(dirp
->d_ino
,
1037 lncntp
[dirp
->d_ino
]--);
1039 return (KEEPON
| ALTERED
);
1044 errmsg
= "ACL IN DIRECTORY";
1045 fileerror(idesc
->id_number
, dirp
->d_ino
, errmsg
);
1046 act
= (reply(PASS2B_PROMPT
, idesc
->id_number
) == 1);
1050 errexit("BAD STATE 0x%x FOR INODE I=%d",
1051 statemap
[dirp
->d_ino
], dirp
->d_ino
);
1060 return (ret
|KEEPON
);
1062 if (update_lncntp
) {
1063 LINK_RANGE(errmsg
, lncntp
[idesc
->id_number
], 1);
1064 if (errmsg
!= NULL
) {
1065 LINK_CLEAR(errmsg
, idesc
->id_number
, IFDIR
, &ldesc
);
1066 if (statemap
[idesc
->id_number
] == USTATE
) {
1067 idesc
->id_number
= 0;
1071 TRACK_LNCNTP(idesc
->id_number
, lncntp
[idesc
->id_number
]++);
1076 return (ret
|KEEPON
|ALTERED
);
1079 #undef PASS2B_PROMPT
1082 * Routine to sort disk blocks.
1085 blksort(const void *arg1
, const void *arg2
)
1087 const struct inoinfo
**inpp1
= (const struct inoinfo
**)arg1
;
1088 const struct inoinfo
**inpp2
= (const struct inoinfo
**)arg2
;
1090 return ((*inpp1
)->i_blks
[0] - (*inpp2
)->i_blks
[0]);