* Copyright (c) 1980, 1986, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
#include <ufs/ufs/dinode.h>
#define MINDIRSIZE (sizeof (struct dirtemplate))
static int blksort
__P((const void *, const void *));
static int pass2check
__P((struct inodesc
*));
register struct dinode
*dp
;
register struct inoinfo
**inpp
, *inp
;
char pathbuf
[MAXPATHLEN
+ 1];
switch (statemap
[ROOTINO
]) {
pfatal("ROOT INODE UNALLOCATED");
if (reply("ALLOCATE") == 0)
if (allocdir(ROOTINO
, ROOTINO
, 0755) != ROOTINO
)
errx(EEXIT
, "CANNOT ALLOCATE ROOT INODE");
pfatal("DUPS/BAD IN ROOT INODE");
if (reply("REALLOCATE")) {
if (allocdir(ROOTINO
, ROOTINO
, 0755) != ROOTINO
)
errx(EEXIT
, "CANNOT ALLOCATE ROOT INODE");
if (reply("CONTINUE") == 0)
pfatal("ROOT INODE NOT DIRECTORY");
if (reply("REALLOCATE")) {
if (allocdir(ROOTINO
, ROOTINO
, 0755) != ROOTINO
)
errx(EEXIT
, "CANNOT ALLOCATE ROOT INODE");
errx(EEXIT
, "BAD STATE %d FOR ROOT INODE", statemap
[ROOTINO
]);
statemap
[ROOTINO
] = DFOUND
;
* Sort the directory list into disk block order.
qsort((char *)inpsort
, (size_t)inplast
, sizeof *inpsort
, blksort
);
* Check the integrity of each directory.
memset(&curino
, 0, sizeof(struct inodesc
));
curino
.id_func
= pass2check
;
inpend
= &inpsort
[inplast
];
for (inpp
= inpsort
; inpp
< inpend
; inpp
++) {
if (inp
->i_isize
< MINDIRSIZE
) {
direrror(inp
->i_number
, "DIRECTORY TOO SHORT");
inp
->i_isize
= roundup(MINDIRSIZE
, DIRBLKSIZ
);
dp
= ginode(inp
->i_number
);
dp
->di_size
= inp
->i_isize
;
} else if ((inp
->i_isize
& (DIRBLKSIZ
- 1)) != 0) {
getpathname(pathbuf
, inp
->i_number
, inp
->i_number
);
pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
pathbuf
, inp
->i_isize
, DIRBLKSIZ
);
inp
->i_isize
= roundup(inp
->i_isize
, DIRBLKSIZ
);
if (preen
|| reply("ADJUST") == 1) {
dp
= ginode(inp
->i_number
);
dp
->di_size
= roundup(inp
->i_isize
, DIRBLKSIZ
);
memset(&dino
, 0, sizeof(struct dinode
));
dp
->di_size
= inp
->i_isize
;
memmove(&dp
->di_db
[0], &inp
->i_blks
[0], (size_t)inp
->i_numblks
);
curino
.id_number
= inp
->i_number
;
curino
.id_parent
= inp
->i_parent
;
(void)ckinode(dp
, &curino
);
* Now that the parents of all directories have been found,
* make another pass to verify the value of `..'
for (inpp
= inpsort
; inpp
< inpend
; inpp
++) {
if (inp
->i_parent
== 0 || inp
->i_isize
== 0)
if (statemap
[inp
->i_parent
] == DFOUND
&&
statemap
[inp
->i_number
] == DSTATE
)
statemap
[inp
->i_number
] = DFOUND
;
if (inp
->i_dotdot
== inp
->i_parent
||
inp
->i_dotdot
== (ino_t
)-1)
if (inp
->i_dotdot
== 0) {
inp
->i_dotdot
= inp
->i_parent
;
fileerror(inp
->i_parent
, inp
->i_number
, "MISSING '..'");
(void)makeentry(inp
->i_number
, inp
->i_parent
, "..");
fileerror(inp
->i_parent
, inp
->i_number
,
"BAD INODE NUMBER FOR '..'");
inp
->i_dotdot
= inp
->i_parent
;
(void)changeino(inp
->i_number
, "..", inp
->i_parent
);
* Mark all the directories that can be found from the root.
register struct direct
*dirp
= idesc
->id_dirp
;
register struct inoinfo
*inp
;
int n
, entrysize
, ret
= 0;
char namebuf
[MAXPATHLEN
+ 1];
char pathbuf
[MAXPATHLEN
+ 1];
* If converting, set directory entry type.
if (doinglevel2
&& dirp
->d_ino
> 0 && dirp
->d_ino
< maxino
) {
dirp
->d_type
= typemap
[dirp
->d_ino
];
if (idesc
->id_entryno
!= 0)
if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, ".") == 0) {
if (dirp
->d_ino
!= idesc
->id_number
) {
direrror(idesc
->id_number
, "BAD INODE NUMBER FOR '.'");
dirp
->d_ino
= idesc
->id_number
;
if (newinofmt
&& dirp
->d_type
!= DT_DIR
) {
direrror(idesc
->id_number
, "BAD TYPE VALUE FOR '.'");
direrror(idesc
->id_number
, "MISSING '.'");
proto
.d_ino
= idesc
->id_number
;
(void)strcpy(proto
.d_name
, ".");
# if BYTE_ORDER == LITTLE_ENDIAN
proto
.d_type
= proto
.d_namlen
;
entrysize
= DIRSIZ(0, &proto
);
if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, "..") != 0) {
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
} else if (dirp
->d_reclen
< entrysize
) {
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
} else if (dirp
->d_reclen
< 2 * entrysize
) {
proto
.d_reclen
= dirp
->d_reclen
;
memmove(dirp
, &proto
, (size_t)entrysize
);
n
= dirp
->d_reclen
- entrysize
;
proto
.d_reclen
= entrysize
;
memmove(dirp
, &proto
, (size_t)entrysize
);
dirp
= (struct direct
*)((char *)(dirp
) + entrysize
);
memset(dirp
, 0, (size_t)n
);
if (idesc
->id_entryno
> 1)
inp
= getinoinfo(idesc
->id_number
);
proto
.d_ino
= inp
->i_parent
;
(void)strcpy(proto
.d_name
, "..");
# if BYTE_ORDER == LITTLE_ENDIAN
proto
.d_type
= proto
.d_namlen
;
entrysize
= DIRSIZ(0, &proto
);
if (idesc
->id_entryno
== 0) {
if (dirp
->d_reclen
< n
+ entrysize
)
proto
.d_reclen
= dirp
->d_reclen
- n
;
dirp
= (struct direct
*)((char *)(dirp
) + n
);
memset(dirp
, 0, (size_t)proto
.d_reclen
);
dirp
->d_reclen
= proto
.d_reclen
;
if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, "..") == 0) {
inp
->i_dotdot
= dirp
->d_ino
;
if (newinofmt
&& dirp
->d_type
!= DT_DIR
) {
direrror(idesc
->id_number
, "BAD TYPE VALUE FOR '..'");
if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, ".") != 0) {
fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
inp
->i_dotdot
= (ino_t
)-1;
} else if (dirp
->d_reclen
< entrysize
) {
fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
inp
->i_dotdot
= (ino_t
)-1;
} else if (inp
->i_parent
!= 0) {
* We know the parent, so fix now.
inp
->i_dotdot
= inp
->i_parent
;
fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
proto
.d_reclen
= dirp
->d_reclen
;
memmove(dirp
, &proto
, (size_t)entrysize
);
if (dirp
->d_namlen
<= 2 &&
dirp
->d_name
[0] == '.' &&
idesc
->id_entryno
>= 2) {
if (dirp
->d_namlen
== 1) {
direrror(idesc
->id_number
, "EXTRA '.' ENTRY");
if (dirp
->d_name
[1] == '.') {
direrror(idesc
->id_number
, "EXTRA '..' ENTRY");
if (dirp
->d_ino
> maxino
) {
fileerror(idesc
->id_number
, dirp
->d_ino
, "I OUT OF RANGE");
((dirp
->d_ino
== WINO
&& dirp
->d_type
!= DT_WHT
) ||
(dirp
->d_ino
!= WINO
&& dirp
->d_type
== DT_WHT
))) {
fileerror(idesc
->id_number
, dirp
->d_ino
, "BAD WHITEOUT ENTRY");
switch (statemap
[dirp
->d_ino
]) {
if (idesc
->id_entryno
<= 2)
fileerror(idesc
->id_number
, dirp
->d_ino
, "UNALLOCATED");
if (idesc
->id_entryno
<= 2)
if (statemap
[dirp
->d_ino
] == FCLEAR
)
errmsg
= "ZERO LENGTH DIRECTORY";
fileerror(idesc
->id_number
, dirp
->d_ino
, errmsg
);
if ((n
= reply("REMOVE")) == 1)
dp
= ginode(dirp
->d_ino
);
(dp
->di_mode
& IFMT
) == IFDIR
? DSTATE
: FSTATE
;
lncntp
[dirp
->d_ino
] = dp
->di_nlink
;
if (statemap
[idesc
->id_number
] == DFOUND
)
statemap
[dirp
->d_ino
] = DFOUND
;
inp
= getinoinfo(dirp
->d_ino
);
if (inp
->i_parent
!= 0 && idesc
->id_entryno
> 2) {
getpathname(pathbuf
, idesc
->id_number
,
getpathname(namebuf
, dirp
->d_ino
, dirp
->d_ino
);
pwarn("%s %s %s\n", pathbuf
,
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
else if ((n
= reply("REMOVE")) == 1)
if (idesc
->id_entryno
> 2)
inp
->i_parent
= idesc
->id_number
;
if (newinofmt
&& dirp
->d_type
!= typemap
[dirp
->d_ino
]) {
fileerror(idesc
->id_number
, dirp
->d_ino
,
dirp
->d_type
= typemap
[dirp
->d_ino
];
errx(EEXIT
, "BAD STATE %d FOR INODE I=%d",
statemap
[dirp
->d_ino
], dirp
->d_ino
);
return (ret
|KEEPON
|ALTERED
);
* Routine to sort disk blocks.
return ((*(struct inoinfo
**)arg1
)->i_blks
[0] -
(*(struct inoinfo
**)arg2
)->i_blks
[0]);