mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-25 01:55:19 +01:00
Improve handling of missing '.' and '..' in UFS directories.
The UFS filesystem expects to find '.' and '..' as the first two entries in a directory. The kernel's UFS name cache can become quite confused when these two entries are not present as the first two entries. Prior to this change, when the fsck_ffs(8) utility detected that '.' and/or '..' were missing, it would report them, but only offered to replace them if the space at the beginning of the directory was available. Otherwise it was left to the system administrator to move the offending file(s) out of the way and then rerun fsck_ffs(8) to create the '.' and '..' entries. With this change, fsck_ffs(8) will always be able to create the '.' and/or '..' entries. It moves any files in the way elsewhere in the directory block. If there is no room in the directory block to which to move them, they are placed in the lost+found directory. Reported by: Peter Holm Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
4f9606c9a6
commit
6bae6625e0
@ -217,9 +217,9 @@ pass2(void)
|
|||||||
continue;
|
continue;
|
||||||
if (inp->i_dotdot == 0) {
|
if (inp->i_dotdot == 0) {
|
||||||
inp->i_dotdot = inp->i_parent;
|
inp->i_dotdot = inp->i_parent;
|
||||||
fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
|
if (debug)
|
||||||
if (reply("FIX") == 0)
|
fileerror(inp->i_parent, inp->i_number,
|
||||||
continue;
|
"DEFERRED MISSING '..' FIX");
|
||||||
(void)makeentry(inp->i_number, inp->i_parent, "..");
|
(void)makeentry(inp->i_number, inp->i_parent, "..");
|
||||||
inoinfo(inp->i_parent)->ino_linkcnt--;
|
inoinfo(inp->i_parent)->ino_linkcnt--;
|
||||||
continue;
|
continue;
|
||||||
@ -289,7 +289,7 @@ pass2check(struct inodesc *idesc)
|
|||||||
struct inode ip;
|
struct inode ip;
|
||||||
union dinode *dp;
|
union dinode *dp;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
struct direct proto;
|
struct direct proto, *newdirp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check for "."
|
* check for "."
|
||||||
@ -301,45 +301,52 @@ pass2check(struct inodesc *idesc)
|
|||||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
|
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
|
||||||
if (dirp->d_ino != idesc->id_number) {
|
if (dirp->d_ino != idesc->id_number) {
|
||||||
direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
|
direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
|
||||||
dirp->d_ino = idesc->id_number;
|
if (reply("FIX") == 1) {
|
||||||
if (reply("FIX") == 1)
|
dirp->d_ino = idesc->id_number;
|
||||||
ret |= ALTERED;
|
ret |= ALTERED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dirp->d_type != DT_DIR) {
|
if (dirp->d_type != DT_DIR) {
|
||||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
|
direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
|
||||||
dirp->d_type = DT_DIR;
|
if (reply("FIX") == 1) {
|
||||||
if (reply("FIX") == 1)
|
dirp->d_type = DT_DIR;
|
||||||
ret |= ALTERED;
|
ret |= ALTERED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto chk1;
|
goto chk1;
|
||||||
}
|
}
|
||||||
direrror(idesc->id_number, "MISSING '.'");
|
|
||||||
proto.d_ino = idesc->id_number;
|
proto.d_ino = idesc->id_number;
|
||||||
proto.d_type = DT_DIR;
|
proto.d_type = DT_DIR;
|
||||||
proto.d_namlen = 1;
|
proto.d_namlen = 1;
|
||||||
(void)strcpy(proto.d_name, ".");
|
(void)strcpy(proto.d_name, ".");
|
||||||
entrysize = DIRSIZ(0, &proto);
|
entrysize = DIRSIZ(0, &proto);
|
||||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
|
direrror(idesc->id_number, "MISSING '.'");
|
||||||
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
|
errmsg = "ADD '.' ENTRY";
|
||||||
dirp->d_name);
|
if (dirp->d_reclen < entrysize + DIRSIZ(0, dirp)) {
|
||||||
} else if (dirp->d_reclen < entrysize) {
|
/* Not enough space to add '.', replace first entry with '.' */
|
||||||
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
|
if (dirp->d_ino != 0) {
|
||||||
} else if (dirp->d_reclen < 2 * entrysize) {
|
pwarn("\nFIRST ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||||
|
dirp->d_name);
|
||||||
|
errmsg = "REPLACE WITH '.'";
|
||||||
|
}
|
||||||
|
if (reply(errmsg) == 0)
|
||||||
|
goto chk1;
|
||||||
proto.d_reclen = dirp->d_reclen;
|
proto.d_reclen = dirp->d_reclen;
|
||||||
memmove(dirp, &proto, (size_t)entrysize);
|
memmove(dirp, &proto, (size_t)entrysize);
|
||||||
if (reply("FIX") == 1)
|
ret |= ALTERED;
|
||||||
ret |= ALTERED;
|
|
||||||
} else {
|
} else {
|
||||||
n = dirp->d_reclen - entrysize;
|
/* Move over first entry and add '.' entry */
|
||||||
|
if (reply(errmsg) == 0)
|
||||||
|
goto chk1;
|
||||||
|
newdirp = (struct direct *)((char *)(dirp) + entrysize);
|
||||||
|
dirp->d_reclen -= entrysize;
|
||||||
|
memmove(newdirp, dirp, dirp->d_reclen);
|
||||||
proto.d_reclen = entrysize;
|
proto.d_reclen = entrysize;
|
||||||
memmove(dirp, &proto, (size_t)entrysize);
|
memmove(dirp, &proto, (size_t)entrysize);
|
||||||
idesc->id_entryno++;
|
idesc->id_entryno++;
|
||||||
inoinfo(dirp->d_ino)->ino_linkcnt--;
|
inoinfo(idesc->id_number)->ino_linkcnt--;
|
||||||
dirp = (struct direct *)((char *)(dirp) + entrysize);
|
dirp = newdirp;
|
||||||
memset(dirp, 0, (size_t)n);
|
ret |= ALTERED;
|
||||||
dirp->d_reclen = n;
|
|
||||||
if (reply("FIX") == 1)
|
|
||||||
ret |= ALTERED;
|
|
||||||
}
|
}
|
||||||
chk1:
|
chk1:
|
||||||
if (idesc->id_entryno > 1)
|
if (idesc->id_entryno > 1)
|
||||||
@ -372,30 +379,60 @@ chk1:
|
|||||||
}
|
}
|
||||||
goto chk2;
|
goto chk2;
|
||||||
}
|
}
|
||||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
|
fileerror(inp->i_parent != 0 ? inp->i_parent : idesc->id_number,
|
||||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
idesc->id_number, "MISSING '..'");
|
||||||
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
|
errmsg = "ADD '..' ENTRY";
|
||||||
dirp->d_name);
|
if (dirp->d_reclen < entrysize + DIRSIZ(0, dirp)) {
|
||||||
inp->i_dotdot = (ino_t)-1;
|
/* No space to add '..', replace second entry with '..' */
|
||||||
} else if (dirp->d_reclen < entrysize) {
|
if (dirp->d_ino != 0) {
|
||||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
pfatal("SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||||
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
|
dirp->d_name);
|
||||||
inp->i_dotdot = (ino_t)-1;
|
errmsg = "REPLACE WITH '..'";
|
||||||
} else if (inp->i_parent != 0) {
|
}
|
||||||
/*
|
if (reply(errmsg) == 0) {
|
||||||
* We know the parent, so fix now.
|
inp->i_dotdot = (ino_t)-1;
|
||||||
*/
|
goto chk2;
|
||||||
inp->i_dotdot = inp->i_parent;
|
}
|
||||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
if (proto.d_ino == 0) {
|
||||||
|
/* Defer processing until parent known */
|
||||||
|
idesc->id_entryno++;
|
||||||
|
if (debug)
|
||||||
|
printf("(FIX DEFERRED)\n");
|
||||||
|
}
|
||||||
|
inp->i_dotdot = proto.d_ino;
|
||||||
proto.d_reclen = dirp->d_reclen;
|
proto.d_reclen = dirp->d_reclen;
|
||||||
memmove(dirp, &proto, (size_t)entrysize);
|
memmove(dirp, &proto, (size_t)entrysize);
|
||||||
if (reply("FIX") == 1)
|
ret |= ALTERED;
|
||||||
ret |= ALTERED;
|
} else {
|
||||||
|
/* Move over second entry and add '..' entry */
|
||||||
|
if (reply(errmsg) == 0) {
|
||||||
|
inp->i_dotdot = (ino_t)-1;
|
||||||
|
goto chk2;
|
||||||
|
}
|
||||||
|
if (proto.d_ino == 0) {
|
||||||
|
/* Defer processing until parent known */
|
||||||
|
idesc->id_entryno++;
|
||||||
|
if (debug)
|
||||||
|
printf("(FIX DEFERRED)\n");
|
||||||
|
}
|
||||||
|
inp->i_dotdot = proto.d_ino;
|
||||||
|
if (dirp->d_ino == 0) {
|
||||||
|
proto.d_reclen = dirp->d_reclen;
|
||||||
|
memmove(dirp, &proto, (size_t)entrysize);
|
||||||
|
} else {
|
||||||
|
newdirp = (struct direct *)((char *)(dirp) + entrysize);
|
||||||
|
dirp->d_reclen -= entrysize;
|
||||||
|
memmove(newdirp, dirp, dirp->d_reclen);
|
||||||
|
proto.d_reclen = entrysize;
|
||||||
|
memmove(dirp, &proto, (size_t)entrysize);
|
||||||
|
if (dirp->d_ino != 0) {
|
||||||
|
idesc->id_entryno++;
|
||||||
|
inoinfo(dirp->d_ino)->ino_linkcnt--;
|
||||||
|
}
|
||||||
|
dirp = newdirp;
|
||||||
|
}
|
||||||
|
ret |= ALTERED;
|
||||||
}
|
}
|
||||||
idesc->id_entryno++;
|
|
||||||
if (dirp->d_ino != 0)
|
|
||||||
inoinfo(dirp->d_ino)->ino_linkcnt--;
|
|
||||||
return (ret|KEEPON);
|
|
||||||
chk2:
|
chk2:
|
||||||
if (dirp->d_ino == 0)
|
if (dirp->d_ino == 0)
|
||||||
return (ret|KEEPON);
|
return (ret|KEEPON);
|
||||||
|
Loading…
Reference in New Issue
Block a user