clang-format

This commit is contained in:
2024-09-10 13:03:02 -04:00
parent 53c617d779
commit d66450e427
381 changed files with 28864 additions and 34170 deletions

View File

@@ -41,7 +41,6 @@
#include "support.h"
#include "kern/sfs.h"
#ifdef HOST
/*
* OS/161 runs natively on a big-endian platform, so we can
@@ -78,53 +77,44 @@ static bool recurse;
static unsigned dumppos;
static
void
dumpval(const char *desc, const char *val)
{
size_t dlen, vlen, used;
static void dumpval(const char *desc, const char *val) {
size_t dlen, vlen, used;
dlen = strlen(desc);
vlen = strlen(val);
dlen = strlen(desc);
vlen = strlen(val);
printf(" ");
printf(" ");
printf("%s: %s", desc, val);
printf("%s: %s", desc, val);
used = dlen + 2 + vlen;
for (; used < 36; used++) {
putchar(' ');
}
used = dlen + 2 + vlen;
for (; used < 36; used++) {
putchar(' ');
}
if (dumppos % 2 == 1) {
printf("\n");
}
dumppos++;
if (dumppos % 2 == 1) {
printf("\n");
}
dumppos++;
}
static
void
dumpvalf(const char *desc, const char *valf, ...)
{
va_list ap;
char buf[128];
static void dumpvalf(const char *desc, const char *valf, ...) {
va_list ap;
char buf[128];
va_start(ap, valf);
vsnprintf(buf, sizeof(buf), valf, ap);
va_end(ap);
dumpval(desc, buf);
va_start(ap, valf);
vsnprintf(buf, sizeof(buf), valf, ap);
va_end(ap);
dumpval(desc, buf);
}
static
void
dumplval(const char *desc, const char *lval)
{
if (dumppos % 2 == 1) {
printf("\n");
dumppos++;
}
printf(" %s: %s\n", desc, lval);
dumppos += 2;
static void dumplval(const char *desc, const char *lval) {
if (dumppos % 2 == 1) {
printf("\n");
dumppos++;
}
printf(" %s: %s\n", desc, lval);
dumppos += 2;
}
////////////////////////////////////////////////////////////
@@ -132,476 +122,437 @@ dumplval(const char *desc, const char *lval)
static void dumpinode(uint32_t ino, const char *name);
static
uint32_t
readsb(void)
{
struct sfs_superblock sb;
static uint32_t readsb(void) {
struct sfs_superblock sb;
diskread(&sb, SFS_SUPER_BLOCK);
if (SWAP32(sb.sb_magic) != SFS_MAGIC) {
errx(1, "Not an sfs filesystem");
}
return SWAP32(sb.sb_nblocks);
diskread(&sb, SFS_SUPER_BLOCK);
if (SWAP32(sb.sb_magic) != SFS_MAGIC) {
errx(1, "Not an sfs filesystem");
}
return SWAP32(sb.sb_nblocks);
}
static
void
dumpsb(void)
{
struct sfs_superblock sb;
unsigned i;
static void dumpsb(void) {
struct sfs_superblock sb;
unsigned i;
diskread(&sb, SFS_SUPER_BLOCK);
sb.sb_volname[sizeof(sb.sb_volname)-1] = 0;
diskread(&sb, SFS_SUPER_BLOCK);
sb.sb_volname[sizeof(sb.sb_volname) - 1] = 0;
printf("Superblock\n");
printf("----------\n");
dumpvalf("Magic", "0x%8x", SWAP32(sb.sb_magic));
dumpvalf("Size", "%u blocks", SWAP32(sb.sb_nblocks));
dumpvalf("Freemap size", "%u blocks",
SFS_FREEMAPBLOCKS(SWAP32(sb.sb_nblocks)));
dumpvalf("Block size", "%u bytes", SFS_BLOCKSIZE);
dumplval("Volume name", sb.sb_volname);
printf("Superblock\n");
printf("----------\n");
dumpvalf("Magic", "0x%8x", SWAP32(sb.sb_magic));
dumpvalf("Size", "%u blocks", SWAP32(sb.sb_nblocks));
dumpvalf("Freemap size", "%u blocks",
SFS_FREEMAPBLOCKS(SWAP32(sb.sb_nblocks)));
dumpvalf("Block size", "%u bytes", SFS_BLOCKSIZE);
dumplval("Volume name", sb.sb_volname);
for (i=0; i<ARRAYCOUNT(sb.reserved); i++) {
if (sb.reserved[i] != 0) {
printf(" Word %u in reserved area: 0x%x\n",
i, SWAP32(sb.reserved[i]));
}
}
printf("\n");
for (i = 0; i < ARRAYCOUNT(sb.reserved); i++) {
if (sb.reserved[i] != 0) {
printf(" Word %u in reserved area: 0x%x\n", i, SWAP32(sb.reserved[i]));
}
}
printf("\n");
}
static
void
dumpfreemap(uint32_t fsblocks)
{
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
uint32_t i, j, k, bn;
uint8_t data[SFS_BLOCKSIZE], mask;
char tmp[16];
static void dumpfreemap(uint32_t fsblocks) {
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
uint32_t i, j, k, bn;
uint8_t data[SFS_BLOCKSIZE], mask;
char tmp[16];
printf("Free block bitmap\n");
printf("-----------------\n");
for (i=0; i<freemapblocks; i++) {
diskread(data, SFS_FREEMAP_START+i);
printf(" Freemap block #%u in disk block %u: blocks %u - %u"
" (0x%x - 0x%x)\n",
i, SFS_FREEMAP_START+i,
i*SFS_BITSPERBLOCK, (i+1)*SFS_BITSPERBLOCK - 1,
i*SFS_BITSPERBLOCK, (i+1)*SFS_BITSPERBLOCK - 1);
for (j=0; j<SFS_BLOCKSIZE; j++) {
if (j % 8 == 0) {
snprintf(tmp, sizeof(tmp), "0x%x",
i*SFS_BITSPERBLOCK + j*8);
printf("%-7s ", tmp);
}
for (k=0; k<8; k++) {
bn = i*SFS_BITSPERBLOCK + j*8 + k;
mask = 1U << k;
if (bn >= fsblocks) {
if (data[j] & mask) {
putchar('x');
}
else {
putchar('!');
}
}
else {
if (data[j] & mask) {
putchar('*');
}
else {
putchar('.');
}
}
}
if (j % 8 == 7) {
printf("\n");
}
else {
printf(" ");
}
}
}
printf("\n");
printf("Free block bitmap\n");
printf("-----------------\n");
for (i = 0; i < freemapblocks; i++) {
diskread(data, SFS_FREEMAP_START + i);
printf(" Freemap block #%u in disk block %u: blocks %u - %u"
" (0x%x - 0x%x)\n",
i, SFS_FREEMAP_START + i, i * SFS_BITSPERBLOCK,
(i + 1) * SFS_BITSPERBLOCK - 1, i * SFS_BITSPERBLOCK,
(i + 1) * SFS_BITSPERBLOCK - 1);
for (j = 0; j < SFS_BLOCKSIZE; j++) {
if (j % 8 == 0) {
snprintf(tmp, sizeof(tmp), "0x%x", i * SFS_BITSPERBLOCK + j * 8);
printf("%-7s ", tmp);
}
for (k = 0; k < 8; k++) {
bn = i * SFS_BITSPERBLOCK + j * 8 + k;
mask = 1U << k;
if (bn >= fsblocks) {
if (data[j] & mask) {
putchar('x');
} else {
putchar('!');
}
} else {
if (data[j] & mask) {
putchar('*');
} else {
putchar('.');
}
}
}
if (j % 8 == 7) {
printf("\n");
} else {
printf(" ");
}
}
}
printf("\n");
}
static
void
dumpindirect(uint32_t block)
{
uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)];
char tmp[128];
unsigned i;
static void dumpindirect(uint32_t block) {
uint32_t ib[SFS_BLOCKSIZE / sizeof(uint32_t)];
char tmp[128];
unsigned i;
if (block == 0) {
return;
}
printf("Indirect block %u\n", block);
if (block == 0) {
return;
}
printf("Indirect block %u\n", block);
diskread(ib, block);
for (i=0; i<ARRAYCOUNT(ib); i++) {
if (i % 4 == 0) {
printf("@%-3u ", i);
}
snprintf(tmp, sizeof(tmp), "%u (0x%x)",
SWAP32(ib[i]), SWAP32(ib[i]));
printf(" %-16s", tmp);
if (i % 4 == 3) {
printf("\n");
}
}
diskread(ib, block);
for (i = 0; i < ARRAYCOUNT(ib); i++) {
if (i % 4 == 0) {
printf("@%-3u ", i);
}
snprintf(tmp, sizeof(tmp), "%u (0x%x)", SWAP32(ib[i]), SWAP32(ib[i]));
printf(" %-16s", tmp);
if (i % 4 == 3) {
printf("\n");
}
}
}
static
uint32_t
traverse_ib(uint32_t fileblock, uint32_t numblocks, uint32_t block,
void (*doblock)(uint32_t, uint32_t))
{
uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)];
unsigned i;
static uint32_t traverse_ib(uint32_t fileblock, uint32_t numblocks,
uint32_t block,
void (*doblock)(uint32_t, uint32_t)) {
uint32_t ib[SFS_BLOCKSIZE / sizeof(uint32_t)];
unsigned i;
if (block == 0) {
memset(ib, 0, sizeof(ib));
}
else {
diskread(ib, block);
}
for (i=0; i<ARRAYCOUNT(ib) && fileblock < numblocks; i++) {
doblock(fileblock++, SWAP32(ib[i]));
}
return fileblock;
if (block == 0) {
memset(ib, 0, sizeof(ib));
} else {
diskread(ib, block);
}
for (i = 0; i < ARRAYCOUNT(ib) && fileblock < numblocks; i++) {
doblock(fileblock++, SWAP32(ib[i]));
}
return fileblock;
}
static
void
traverse(const struct sfs_dinode *sfi, void (*doblock)(uint32_t, uint32_t))
{
uint32_t fileblock;
uint32_t numblocks;
unsigned i;
static void traverse(const struct sfs_dinode *sfi,
void (*doblock)(uint32_t, uint32_t)) {
uint32_t fileblock;
uint32_t numblocks;
unsigned i;
numblocks = DIVROUNDUP(SWAP32(sfi->sfi_size), SFS_BLOCKSIZE);
numblocks = DIVROUNDUP(SWAP32(sfi->sfi_size), SFS_BLOCKSIZE);
fileblock = 0;
for (i=0; i<SFS_NDIRECT && fileblock < numblocks; i++) {
doblock(fileblock++, SWAP32(sfi->sfi_direct[i]));
}
if (fileblock < numblocks) {
fileblock = traverse_ib(fileblock, numblocks,
SWAP32(sfi->sfi_indirect), doblock);
}
assert(fileblock == numblocks);
fileblock = 0;
for (i = 0; i < SFS_NDIRECT && fileblock < numblocks; i++) {
doblock(fileblock++, SWAP32(sfi->sfi_direct[i]));
}
if (fileblock < numblocks) {
fileblock =
traverse_ib(fileblock, numblocks, SWAP32(sfi->sfi_indirect), doblock);
}
assert(fileblock == numblocks);
}
static
void
dumpdirblock(uint32_t fileblock, uint32_t diskblock)
{
struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)];
int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
int i;
static void dumpdirblock(uint32_t fileblock, uint32_t diskblock) {
struct sfs_direntry sds[SFS_BLOCKSIZE / sizeof(struct sfs_direntry)];
int nsds = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
int i;
(void)fileblock;
if (diskblock == 0) {
printf(" [block %u - empty]\n", diskblock);
return;
}
diskread(&sds, diskblock);
(void)fileblock;
if (diskblock == 0) {
printf(" [block %u - empty]\n", diskblock);
return;
}
diskread(&sds, diskblock);
printf(" [block %u]\n", diskblock);
for (i=0; i<nsds; i++) {
uint32_t ino = SWAP32(sds[i].sfd_ino);
if (ino==SFS_NOINO) {
printf(" [free entry]\n");
}
else {
sds[i].sfd_name[SFS_NAMELEN-1] = 0; /* just in case */
printf(" %u %s\n", ino, sds[i].sfd_name);
}
}
printf(" [block %u]\n", diskblock);
for (i = 0; i < nsds; i++) {
uint32_t ino = SWAP32(sds[i].sfd_ino);
if (ino == SFS_NOINO) {
printf(" [free entry]\n");
} else {
sds[i].sfd_name[SFS_NAMELEN - 1] = 0; /* just in case */
printf(" %u %s\n", ino, sds[i].sfd_name);
}
}
}
static
void
dumpdir(uint32_t ino, const struct sfs_dinode *sfi)
{
int nentries;
static void dumpdir(uint32_t ino, const struct sfs_dinode *sfi) {
int nentries;
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
if (SWAP32(sfi->sfi_size) % sizeof(struct sfs_direntry) != 0) {
warnx("Warning: dir size is not a multiple of dir entry size");
}
printf("Directory contents for inode %u: %d entries\n", ino, nentries);
traverse(sfi, dumpdirblock);
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
if (SWAP32(sfi->sfi_size) % sizeof(struct sfs_direntry) != 0) {
warnx("Warning: dir size is not a multiple of dir entry size");
}
printf("Directory contents for inode %u: %d entries\n", ino, nentries);
traverse(sfi, dumpdirblock);
}
static
void
recursedirblock(uint32_t fileblock, uint32_t diskblock)
{
struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)];
int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
int i;
static void recursedirblock(uint32_t fileblock, uint32_t diskblock) {
struct sfs_direntry sds[SFS_BLOCKSIZE / sizeof(struct sfs_direntry)];
int nsds = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
int i;
(void)fileblock;
if (diskblock == 0) {
return;
}
diskread(&sds, diskblock);
(void)fileblock;
if (diskblock == 0) {
return;
}
diskread(&sds, diskblock);
for (i=0; i<nsds; i++) {
uint32_t ino = SWAP32(sds[i].sfd_ino);
if (ino==SFS_NOINO) {
continue;
}
sds[i].sfd_name[SFS_NAMELEN-1] = 0; /* just in case */
dumpinode(ino, sds[i].sfd_name);
}
for (i = 0; i < nsds; i++) {
uint32_t ino = SWAP32(sds[i].sfd_ino);
if (ino == SFS_NOINO) {
continue;
}
sds[i].sfd_name[SFS_NAMELEN - 1] = 0; /* just in case */
dumpinode(ino, sds[i].sfd_name);
}
}
static
void
recursedir(uint32_t ino, const struct sfs_dinode *sfi)
{
int nentries;
static void recursedir(uint32_t ino, const struct sfs_dinode *sfi) {
int nentries;
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
printf("Reading files in directory %u: %d entries\n", ino, nentries);
traverse(sfi, recursedirblock);
printf("Done with directory %u\n", ino);
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
printf("Reading files in directory %u: %d entries\n", ino, nentries);
traverse(sfi, recursedirblock);
printf("Done with directory %u\n", ino);
}
static
void dumpfileblock(uint32_t fileblock, uint32_t diskblock)
{
uint8_t data[SFS_BLOCKSIZE];
unsigned i, j;
char tmp[128];
static void dumpfileblock(uint32_t fileblock, uint32_t diskblock) {
uint8_t data[SFS_BLOCKSIZE];
unsigned i, j;
char tmp[128];
if (diskblock == 0) {
printf(" 0x%6x [sparse]\n", fileblock * SFS_BLOCKSIZE);
return;
}
if (diskblock == 0) {
printf(" 0x%6x [sparse]\n", fileblock * SFS_BLOCKSIZE);
return;
}
diskread(data, diskblock);
for (i=0; i<SFS_BLOCKSIZE; i++) {
if (i % 16 == 0) {
snprintf(tmp, sizeof(tmp), "0x%x",
fileblock * SFS_BLOCKSIZE + i);
printf("%8s", tmp);
}
if (i % 8 == 0) {
printf(" ");
}
else {
printf(" ");
}
printf("%02x", data[i]);
if (i % 16 == 15) {
printf(" ");
for (j = i-15; j<=i; j++) {
if (data[j] < 32 || data[j] > 126) {
putchar('.');
}
else {
putchar(data[j]);
}
}
printf("\n");
}
}
diskread(data, diskblock);
for (i = 0; i < SFS_BLOCKSIZE; i++) {
if (i % 16 == 0) {
snprintf(tmp, sizeof(tmp), "0x%x", fileblock * SFS_BLOCKSIZE + i);
printf("%8s", tmp);
}
if (i % 8 == 0) {
printf(" ");
} else {
printf(" ");
}
printf("%02x", data[i]);
if (i % 16 == 15) {
printf(" ");
for (j = i - 15; j <= i; j++) {
if (data[j] < 32 || data[j] > 126) {
putchar('.');
} else {
putchar(data[j]);
}
}
printf("\n");
}
}
}
static
void
dumpfile(uint32_t ino, const struct sfs_dinode *sfi)
{
printf("File contents for inode %u:\n", ino);
traverse(sfi, dumpfileblock);
static void dumpfile(uint32_t ino, const struct sfs_dinode *sfi) {
printf("File contents for inode %u:\n", ino);
traverse(sfi, dumpfileblock);
}
static
void
dumpinode(uint32_t ino, const char *name)
{
struct sfs_dinode sfi;
const char *typename;
char tmp[128];
unsigned i;
static void dumpinode(uint32_t ino, const char *name) {
struct sfs_dinode sfi;
const char *typename;
char tmp[128];
unsigned i;
diskread(&sfi, ino);
diskread(&sfi, ino);
printf("Inode %u", ino);
if (name != NULL) {
printf(" (%s)", name);
}
printf("\n");
printf("--------------\n");
printf("Inode %u", ino);
if (name != NULL) {
printf(" (%s)", name);
}
printf("\n");
printf("--------------\n");
switch (SWAP16(sfi.sfi_type)) {
case SFS_TYPE_FILE: typename = "regular file"; break;
case SFS_TYPE_DIR: typename = "directory"; break;
default: typename = "invalid"; break;
}
dumpvalf("Type", "%u (%s)", SWAP16(sfi.sfi_type), typename);
dumpvalf("Size", "%u", SWAP32(sfi.sfi_size));
dumpvalf("Link count", "%u", SWAP16(sfi.sfi_linkcount));
printf("\n");
switch (SWAP16(sfi.sfi_type)) {
case SFS_TYPE_FILE:
typename = "regular file";
break;
case SFS_TYPE_DIR:
typename = "directory";
break;
default:
typename = "invalid";
break;
}
dumpvalf("Type", "%u (%s)", SWAP16(sfi.sfi_type), typename);
dumpvalf("Size", "%u", SWAP32(sfi.sfi_size));
dumpvalf("Link count", "%u", SWAP16(sfi.sfi_linkcount));
printf("\n");
printf(" Direct blocks:\n");
for (i=0; i<SFS_NDIRECT; i++) {
if (i % 4 == 0) {
printf("@%-2u ", i);
}
/*
* Assume the disk size might be > 64K sectors (which
* would be 32M) but is < 1024K sectors (512M) so we
* need up to 5 hex digits for a block number. And
* assume it's actually < 1 million sectors so we need
* only up to 6 decimal digits. The complete block
* number print then needs up to 16 digits.
*/
snprintf(tmp, sizeof(tmp), "%u (0x%x)",
SWAP32(sfi.sfi_direct[i]), SWAP32(sfi.sfi_direct[i]));
printf(" %-16s", tmp);
if (i % 4 == 3) {
printf("\n");
}
}
if (i % 4 != 0) {
printf("\n");
}
printf(" Indirect block: %u (0x%x)\n",
SWAP32(sfi.sfi_indirect), SWAP32(sfi.sfi_indirect));
for (i=0; i<ARRAYCOUNT(sfi.sfi_waste); i++) {
if (sfi.sfi_waste[i] != 0) {
printf(" Word %u in waste area: 0x%x\n",
i, SWAP32(sfi.sfi_waste[i]));
}
}
printf(" Direct blocks:\n");
for (i = 0; i < SFS_NDIRECT; i++) {
if (i % 4 == 0) {
printf("@%-2u ", i);
}
/*
* Assume the disk size might be > 64K sectors (which
* would be 32M) but is < 1024K sectors (512M) so we
* need up to 5 hex digits for a block number. And
* assume it's actually < 1 million sectors so we need
* only up to 6 decimal digits. The complete block
* number print then needs up to 16 digits.
*/
snprintf(tmp, sizeof(tmp), "%u (0x%x)", SWAP32(sfi.sfi_direct[i]),
SWAP32(sfi.sfi_direct[i]));
printf(" %-16s", tmp);
if (i % 4 == 3) {
printf("\n");
}
}
if (i % 4 != 0) {
printf("\n");
}
printf(" Indirect block: %u (0x%x)\n", SWAP32(sfi.sfi_indirect),
SWAP32(sfi.sfi_indirect));
for (i = 0; i < ARRAYCOUNT(sfi.sfi_waste); i++) {
if (sfi.sfi_waste[i] != 0) {
printf(" Word %u in waste area: 0x%x\n", i, SWAP32(sfi.sfi_waste[i]));
}
}
if (doindirect) {
dumpindirect(SWAP32(sfi.sfi_indirect));
}
if (doindirect) {
dumpindirect(SWAP32(sfi.sfi_indirect));
}
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && dodirs) {
dumpdir(ino, &sfi);
}
if (SWAP16(sfi.sfi_type) == SFS_TYPE_FILE && dofiles) {
dumpfile(ino, &sfi);
}
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && recurse) {
recursedir(ino, &sfi);
}
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && dodirs) {
dumpdir(ino, &sfi);
}
if (SWAP16(sfi.sfi_type) == SFS_TYPE_FILE && dofiles) {
dumpfile(ino, &sfi);
}
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && recurse) {
recursedir(ino, &sfi);
}
}
////////////////////////////////////////////////////////////
// main
static
void
usage(void)
{
warnx("Usage: dumpsfs [options] device/diskfile");
warnx(" -s: dump superblock");
warnx(" -b: dump free block bitmap");
warnx(" -i ino: dump specified inode");
warnx(" -I: dump indirect blocks");
warnx(" -f: dump file contents");
warnx(" -d: dump directory contents");
warnx(" -r: recurse into directory contents");
warnx(" -a: equivalent to -sbdfr -i 1");
errx(1, " Default is -i 1");
static void usage(void) {
warnx("Usage: dumpsfs [options] device/diskfile");
warnx(" -s: dump superblock");
warnx(" -b: dump free block bitmap");
warnx(" -i ino: dump specified inode");
warnx(" -I: dump indirect blocks");
warnx(" -f: dump file contents");
warnx(" -d: dump directory contents");
warnx(" -r: recurse into directory contents");
warnx(" -a: equivalent to -sbdfr -i 1");
errx(1, " Default is -i 1");
}
int
main(int argc, char **argv)
{
bool dosb = false;
bool dofreemap = false;
uint32_t dumpino = 0;
const char *dumpdisk = NULL;
int main(int argc, char **argv) {
bool dosb = false;
bool dofreemap = false;
uint32_t dumpino = 0;
const char *dumpdisk = NULL;
int i, j;
uint32_t nblocks;
int i, j;
uint32_t nblocks;
#ifdef HOST
/* Don't do this; it frobs the tty and you can't pipe to less */
/*hostcompat_init(argc, argv);*/
hostcompat_progname = argv[0];
/* Don't do this; it frobs the tty and you can't pipe to less */
/*hostcompat_init(argc, argv);*/
hostcompat_progname = argv[0];
#endif
for (i=1; i<argc; i++) {
if (argv[i][0] == '-') {
for (j=1; argv[i][j]; j++) {
switch (argv[i][j]) {
case 's': dosb = true; break;
case 'b': dofreemap = true; break;
case 'i':
if (argv[i][j+1] == 0) {
dumpino = atoi(argv[++i]);
}
else {
dumpino = atoi(argv[i]+j+1);
j = strlen(argv[i]);
}
/* XXX ugly */
goto nextarg;
case 'I': doindirect = true; break;
case 'f': dofiles = true; break;
case 'd': dodirs = true; break;
case 'r': recurse = true; break;
case 'a':
dosb = true;
dofreemap = true;
if (dumpino == 0) {
dumpino = SFS_ROOTDIR_INO;
}
doindirect = true;
dofiles = true;
dodirs = true;
recurse = true;
break;
default:
usage();
break;
}
}
}
else {
if (dumpdisk != NULL) {
usage();
}
dumpdisk = argv[i];
}
nextarg:
;
}
if (dumpdisk == NULL) {
usage();
}
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
for (j = 1; argv[i][j]; j++) {
switch (argv[i][j]) {
case 's':
dosb = true;
break;
case 'b':
dofreemap = true;
break;
case 'i':
if (argv[i][j + 1] == 0) {
dumpino = atoi(argv[++i]);
} else {
dumpino = atoi(argv[i] + j + 1);
j = strlen(argv[i]);
}
/* XXX ugly */
goto nextarg;
case 'I':
doindirect = true;
break;
case 'f':
dofiles = true;
break;
case 'd':
dodirs = true;
break;
case 'r':
recurse = true;
break;
case 'a':
dosb = true;
dofreemap = true;
if (dumpino == 0) {
dumpino = SFS_ROOTDIR_INO;
}
doindirect = true;
dofiles = true;
dodirs = true;
recurse = true;
break;
default:
usage();
break;
}
}
} else {
if (dumpdisk != NULL) {
usage();
}
dumpdisk = argv[i];
}
nextarg:;
}
if (dumpdisk == NULL) {
usage();
}
if (!dosb && !dofreemap && dumpino == 0) {
dumpino = SFS_ROOTDIR_INO;
}
if (!dosb && !dofreemap && dumpino == 0) {
dumpino = SFS_ROOTDIR_INO;
}
opendisk(dumpdisk);
nblocks = readsb();
opendisk(dumpdisk);
nblocks = readsb();
if (dosb) {
dumpsb();
}
if (dofreemap) {
dumpfreemap(nblocks);
}
if (dumpino != 0) {
dumpinode(dumpino, NULL);
}
if (dosb) {
dumpsb();
}
if (dofreemap) {
dumpfreemap(nblocks);
}
if (dumpino != 0) {
dumpinode(dumpino, NULL);
}
closedisk();
closedisk();
return 0;
return 0;
}

View File

@@ -36,9 +36,7 @@
* Just calls reboot() with the RB_HALT flag.
*/
int
main(void)
{
reboot(RB_HALT);
return 0;
int main(void) {
reboot(RB_HALT);
return 0;
}

View File

@@ -41,160 +41,148 @@
#include "disk.h"
#define HOSTSTRING "System/161 Disk Image"
#define BLOCKSIZE 512
#define BLOCKSIZE 512
#ifndef EINTR
#define EINTR 0
#endif
static int fd=-1;
static int fd = -1;
static uint32_t nblocks;
/*
* Open a disk. If we're built for the host OS, check that it's a
* System/161 disk image, and then ignore the header block.
*/
void
opendisk(const char *path)
{
struct stat statbuf;
void opendisk(const char *path) {
struct stat statbuf;
assert(fd<0);
fd = open(path, O_RDWR);
if (fd<0) {
err(1, "%s", path);
}
if (fstat(fd, &statbuf)) {
err(1, "%s: fstat", path);
}
assert(fd < 0);
fd = open(path, O_RDWR);
if (fd < 0) {
err(1, "%s", path);
}
if (fstat(fd, &statbuf)) {
err(1, "%s: fstat", path);
}
nblocks = statbuf.st_size / BLOCKSIZE;
nblocks = statbuf.st_size / BLOCKSIZE;
#ifdef HOST
nblocks--;
nblocks--;
{
char buf[64];
int len;
{
char buf[64];
int len;
do {
len = read(fd, buf, sizeof(buf)-1);
if (len < 0 && (errno==EINTR || errno==EAGAIN)) {
continue;
}
} while (0);
do {
len = read(fd, buf, sizeof(buf) - 1);
if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
continue;
}
} while (0);
buf[len] = 0;
buf[strlen(HOSTSTRING)] = 0;
buf[len] = 0;
buf[strlen(HOSTSTRING)] = 0;
if (strcmp(buf, HOSTSTRING)) {
errx(1, "%s: Not a System/161 disk image", path);
}
}
if (strcmp(buf, HOSTSTRING)) {
errx(1, "%s: Not a System/161 disk image", path);
}
}
#endif
}
/*
* Return the block size. (This is fixed, but still...)
*/
uint32_t
diskblocksize(void)
{
assert(fd>=0);
return BLOCKSIZE;
uint32_t diskblocksize(void) {
assert(fd >= 0);
return BLOCKSIZE;
}
/*
* Return the device/image size in blocks.
*/
uint32_t
diskblocks(void)
{
assert(fd>=0);
return nblocks;
uint32_t diskblocks(void) {
assert(fd >= 0);
return nblocks;
}
/*
* Write a block.
*/
void
diskwrite(const void *data, uint32_t block)
{
const char *cdata = data;
uint32_t tot=0;
int len;
void diskwrite(const void *data, uint32_t block) {
const char *cdata = data;
uint32_t tot = 0;
int len;
assert(fd>=0);
assert(fd >= 0);
#ifdef HOST
// skip over disk file header
block++;
// skip over disk file header
block++;
#endif
if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) {
err(1, "lseek");
}
if (lseek(fd, block * BLOCKSIZE, SEEK_SET) < 0) {
err(1, "lseek");
}
while (tot < BLOCKSIZE) {
len = write(fd, cdata + tot, BLOCKSIZE - tot);
if (len < 0) {
if (errno==EINTR || errno==EAGAIN) {
continue;
}
err(1, "write");
}
if (len==0) {
err(1, "write returned 0?");
}
tot += len;
}
while (tot < BLOCKSIZE) {
len = write(fd, cdata + tot, BLOCKSIZE - tot);
if (len < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
err(1, "write");
}
if (len == 0) {
err(1, "write returned 0?");
}
tot += len;
}
}
/*
* Read a block.
*/
void
diskread(void *data, uint32_t block)
{
char *cdata = data;
uint32_t tot=0;
int len;
void diskread(void *data, uint32_t block) {
char *cdata = data;
uint32_t tot = 0;
int len;
assert(fd>=0);
assert(fd >= 0);
#ifdef HOST
// skip over disk file header
block++;
// skip over disk file header
block++;
#endif
if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) {
err(1, "lseek");
}
if (lseek(fd, block * BLOCKSIZE, SEEK_SET) < 0) {
err(1, "lseek");
}
while (tot < BLOCKSIZE) {
len = read(fd, cdata + tot, BLOCKSIZE - tot);
if (len < 0) {
if (errno==EINTR || errno==EAGAIN) {
continue;
}
err(1, "read");
}
if (len==0) {
err(1, "unexpected EOF in mid-sector");
}
tot += len;
}
while (tot < BLOCKSIZE) {
len = read(fd, cdata + tot, BLOCKSIZE - tot);
if (len < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
err(1, "read");
}
if (len == 0) {
err(1, "unexpected EOF in mid-sector");
}
tot += len;
}
}
/*
* Close the disk.
*/
void
closedisk(void)
{
assert(fd>=0);
if (close(fd)) {
err(1, "close");
}
fd = -1;
void closedisk(void) {
assert(fd >= 0);
if (close(fd)) {
err(1, "close");
}
fd = -1;
}

View File

@@ -37,7 +37,6 @@
#include "support.h"
#include "kern/sfs.h"
#ifdef HOST
#include <netinet/in.h> // for arpa/inet.h
@@ -66,175 +65,155 @@ static char freemapbuf[MAXFREEMAPBLOCKS * SFS_BLOCKSIZE];
/*
* Assert that the on-disk data structures are correctly sized.
*/
static
void
check(void)
{
assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
static void check(void) {
assert(sizeof(struct sfs_superblock) == SFS_BLOCKSIZE);
assert(sizeof(struct sfs_dinode) == SFS_BLOCKSIZE);
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
}
/*
* Mark a block allocated.
*/
static
void
allocblock(uint32_t block)
{
uint32_t mapbyte = block/CHAR_BIT;
unsigned char mask = (1<<(block % CHAR_BIT));
static void allocblock(uint32_t block) {
uint32_t mapbyte = block / CHAR_BIT;
unsigned char mask = (1 << (block % CHAR_BIT));
assert((freemapbuf[mapbyte] & mask) == 0);
freemapbuf[mapbyte] |= mask;
assert((freemapbuf[mapbyte] & mask) == 0);
freemapbuf[mapbyte] |= mask;
}
/*
* Initialize the free block bitmap.
*/
static
void
initfreemap(uint32_t fsblocks)
{
uint32_t freemapbits = SFS_FREEMAPBITS(fsblocks);
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
uint32_t i;
static void initfreemap(uint32_t fsblocks) {
uint32_t freemapbits = SFS_FREEMAPBITS(fsblocks);
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
uint32_t i;
if (freemapblocks > MAXFREEMAPBLOCKS) {
errx(1, "Filesystem too large -- "
"increase MAXFREEMAPBLOCKS and recompile");
}
if (freemapblocks > MAXFREEMAPBLOCKS) {
errx(1, "Filesystem too large -- "
"increase MAXFREEMAPBLOCKS and recompile");
}
/* mark the superblock and root inode in use */
allocblock(SFS_SUPER_BLOCK);
allocblock(SFS_ROOTDIR_INO);
/* mark the superblock and root inode in use */
allocblock(SFS_SUPER_BLOCK);
allocblock(SFS_ROOTDIR_INO);
/* the freemap blocks must be in use */
for (i=0; i<freemapblocks; i++) {
allocblock(SFS_FREEMAP_START + i);
}
/* the freemap blocks must be in use */
for (i = 0; i < freemapblocks; i++) {
allocblock(SFS_FREEMAP_START + i);
}
/* all blocks in the freemap but past the volume end are "in use" */
for (i=fsblocks; i<freemapbits; i++) {
allocblock(i);
}
/* all blocks in the freemap but past the volume end are "in use" */
for (i = fsblocks; i < freemapbits; i++) {
allocblock(i);
}
}
/*
* Initialize and write out the superblock.
*/
static
void
writesuper(const char *volname, uint32_t nblocks)
{
struct sfs_superblock sb;
static void writesuper(const char *volname, uint32_t nblocks) {
struct sfs_superblock sb;
/* The cast is required on some outdated host systems. */
bzero((void *)&sb, sizeof(sb));
/* The cast is required on some outdated host systems. */
bzero((void *)&sb, sizeof(sb));
if (strlen(volname) >= SFS_VOLNAME_SIZE) {
errx(1, "Volume name %s too long", volname);
}
if (strlen(volname) >= SFS_VOLNAME_SIZE) {
errx(1, "Volume name %s too long", volname);
}
/* Initialize the superblock structure */
sb.sb_magic = SWAP32(SFS_MAGIC);
sb.sb_nblocks = SWAP32(nblocks);
strcpy(sb.sb_volname, volname);
/* Initialize the superblock structure */
sb.sb_magic = SWAP32(SFS_MAGIC);
sb.sb_nblocks = SWAP32(nblocks);
strcpy(sb.sb_volname, volname);
/* and write it out. */
diskwrite(&sb, SFS_SUPER_BLOCK);
/* and write it out. */
diskwrite(&sb, SFS_SUPER_BLOCK);
}
/*
* Write out the free block bitmap.
*/
static
void
writefreemap(uint32_t fsblocks)
{
uint32_t freemapblocks;
char *ptr;
uint32_t i;
static void writefreemap(uint32_t fsblocks) {
uint32_t freemapblocks;
char *ptr;
uint32_t i;
/* Write out each of the blocks in the free block bitmap. */
freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
for (i=0; i<freemapblocks; i++) {
ptr = freemapbuf + i*SFS_BLOCKSIZE;
diskwrite(ptr, SFS_FREEMAP_START+i);
}
/* Write out each of the blocks in the free block bitmap. */
freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
for (i = 0; i < freemapblocks; i++) {
ptr = freemapbuf + i * SFS_BLOCKSIZE;
diskwrite(ptr, SFS_FREEMAP_START + i);
}
}
/*
* Write out the root directory inode.
*/
static
void
writerootdir(void)
{
struct sfs_dinode sfi;
static void writerootdir(void) {
struct sfs_dinode sfi;
/* Initialize the dinode */
bzero((void *)&sfi, sizeof(sfi));
sfi.sfi_size = SWAP32(0);
sfi.sfi_type = SWAP16(SFS_TYPE_DIR);
sfi.sfi_linkcount = SWAP16(1);
/* Initialize the dinode */
bzero((void *)&sfi, sizeof(sfi));
sfi.sfi_size = SWAP32(0);
sfi.sfi_type = SWAP16(SFS_TYPE_DIR);
sfi.sfi_linkcount = SWAP16(1);
/* Write it out */
diskwrite(&sfi, SFS_ROOTDIR_INO);
/* Write it out */
diskwrite(&sfi, SFS_ROOTDIR_INO);
}
/*
* Main.
*/
int
main(int argc, char **argv)
{
uint32_t size, blocksize;
char *volname, *s;
int main(int argc, char **argv) {
uint32_t size, blocksize;
char *volname, *s;
#ifdef HOST
hostcompat_init(argc, argv);
hostcompat_init(argc, argv);
#endif
if (argc!=3) {
errx(1, "Usage: mksfs device/diskfile volume-name");
}
if (argc != 3) {
errx(1, "Usage: mksfs device/diskfile volume-name");
}
check();
check();
volname = argv[2];
volname = argv[2];
/* Remove one trailing colon from volname, if present */
s = strchr(volname, ':');
if (s != NULL) {
if (strlen(s)!=1) {
errx(1, "Illegal volume name %s", volname);
}
*s = 0;
}
/* Remove one trailing colon from volname, if present */
s = strchr(volname, ':');
if (s != NULL) {
if (strlen(s) != 1) {
errx(1, "Illegal volume name %s", volname);
}
*s = 0;
}
/* Don't allow slashes */
s = strchr(volname, '/');
if (s != NULL) {
errx(1, "Illegal volume name %s", volname);
}
/* Don't allow slashes */
s = strchr(volname, '/');
if (s != NULL) {
errx(1, "Illegal volume name %s", volname);
}
opendisk(argv[1]);
blocksize = diskblocksize();
opendisk(argv[1]);
blocksize = diskblocksize();
if (blocksize!=SFS_BLOCKSIZE) {
errx(1, "Device has wrong blocksize %u (should be %u)\n",
blocksize, SFS_BLOCKSIZE);
}
size = diskblocks();
if (blocksize != SFS_BLOCKSIZE) {
errx(1, "Device has wrong blocksize %u (should be %u)\n", blocksize,
SFS_BLOCKSIZE);
}
size = diskblocks();
/* Write out the on-disk structures */
initfreemap(size);
writesuper(volname, size);
writefreemap(size);
writerootdir();
/* Write out the on-disk structures */
initfreemap(size);
writesuper(volname, size);
writefreemap(size);
writerootdir();
closedisk();
closedisk();
return 0;
return 0;
}

View File

@@ -27,7 +27,6 @@
* SUCH DAMAGE.
*/
#ifdef __osf__
/* Digital Unix (aka Compaq Tru64) */
#define HAS_NO_SIZED_TYPES

View File

@@ -36,9 +36,7 @@
* Just calls reboot() with the RB_POWEROFF flag.
*/
int
main(void)
{
reboot(RB_POWEROFF);
return 0;
int main(void) {
reboot(RB_POWEROFF);
return 0;
}

View File

@@ -36,9 +36,7 @@
* Just calls reboot() with the RB_REBOOT flag.
*/
int
main(void)
{
reboot(RB_REBOOT);
return 0;
int main(void) {
reboot(RB_REBOOT);
return 0;
}

View File

@@ -27,8 +27,8 @@
* SUCH DAMAGE.
*/
#include <sys/types.h> /* for CHAR_BIT */
#include <limits.h> /* also for CHAR_BIT */
#include <sys/types.h> /* for CHAR_BIT */
#include <limits.h> /* also for CHAR_BIT */
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
@@ -52,69 +52,62 @@ static uint8_t *tofreedata;
* called after the superblock is loaded so we can ask how big the
* volume is.
*/
void
freemap_setup(void)
{
size_t i, mapbytes;
uint32_t fsblocks, mapblocks;
void freemap_setup(void) {
size_t i, mapbytes;
uint32_t fsblocks, mapblocks;
fsblocks = sb_totalblocks();
mapblocks = sb_freemapblocks();
mapbytes = mapblocks * SFS_BLOCKSIZE;
fsblocks = sb_totalblocks();
mapblocks = sb_freemapblocks();
mapbytes = mapblocks * SFS_BLOCKSIZE;
freemapdata = domalloc(mapbytes * sizeof(uint8_t));
tofreedata = domalloc(mapbytes * sizeof(uint8_t));
for (i=0; i<mapbytes; i++) {
freemapdata[i] = tofreedata[i] = 0;
}
freemapdata = domalloc(mapbytes * sizeof(uint8_t));
tofreedata = domalloc(mapbytes * sizeof(uint8_t));
for (i = 0; i < mapbytes; i++) {
freemapdata[i] = tofreedata[i] = 0;
}
/* Mark off what's in the freemap but past the volume end. */
for (i=fsblocks; i < mapblocks*SFS_BITSPERBLOCK; i++) {
freemap_blockinuse(i, B_PASTEND, 0);
}
/* Mark off what's in the freemap but past the volume end. */
for (i = fsblocks; i < mapblocks * SFS_BITSPERBLOCK; i++) {
freemap_blockinuse(i, B_PASTEND, 0);
}
/* Mark the superblock block and the freemap blocks in use */
freemap_blockinuse(SFS_SUPER_BLOCK, B_SUPERBLOCK, 0);
for (i=0; i < mapblocks; i++) {
freemap_blockinuse(SFS_FREEMAP_START+i, B_FREEMAPBLOCK, i);
}
/* Mark the superblock block and the freemap blocks in use */
freemap_blockinuse(SFS_SUPER_BLOCK, B_SUPERBLOCK, 0);
for (i = 0; i < mapblocks; i++) {
freemap_blockinuse(SFS_FREEMAP_START + i, B_FREEMAPBLOCK, i);
}
}
/*
* Return a string for a blockusage; used for printing errors.
*/
static
const char *
blockusagestr(blockusage_t how, uint32_t howdesc)
{
static char rv[256];
switch (how) {
case B_SUPERBLOCK:
return "superblock";
case B_FREEMAPBLOCK:
snprintf(rv, sizeof(rv), "freemap block %lu",
(unsigned long) howdesc);
break;
case B_INODE:
snprintf(rv, sizeof(rv), "inode %lu",
(unsigned long) howdesc);
break;
case B_IBLOCK:
snprintf(rv, sizeof(rv), "indirect block of inode %lu",
(unsigned long) howdesc);
break;
case B_DIRDATA:
snprintf(rv, sizeof(rv), "directory data from inode %lu",
(unsigned long) howdesc);
break;
case B_DATA:
snprintf(rv, sizeof(rv), "file data from inode %lu",
(unsigned long) howdesc);
break;
case B_PASTEND:
return "past the end of the fs";
}
return rv;
static const char *blockusagestr(blockusage_t how, uint32_t howdesc) {
static char rv[256];
switch (how) {
case B_SUPERBLOCK:
return "superblock";
case B_FREEMAPBLOCK:
snprintf(rv, sizeof(rv), "freemap block %lu", (unsigned long)howdesc);
break;
case B_INODE:
snprintf(rv, sizeof(rv), "inode %lu", (unsigned long)howdesc);
break;
case B_IBLOCK:
snprintf(rv, sizeof(rv), "indirect block of inode %lu",
(unsigned long)howdesc);
break;
case B_DIRDATA:
snprintf(rv, sizeof(rv), "directory data from inode %lu",
(unsigned long)howdesc);
break;
case B_DATA:
snprintf(rv, sizeof(rv), "file data from inode %lu",
(unsigned long)howdesc);
break;
case B_PASTEND:
return "past the end of the fs";
}
return rv;
}
/*
@@ -123,28 +116,26 @@ blockusagestr(blockusage_t how, uint32_t howdesc)
*
* FUTURE: this should not produce unrecoverable errors.
*/
void
freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc)
{
unsigned index = block/8;
uint8_t mask = ((uint8_t)1)<<(block%8);
void freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc) {
unsigned index = block / 8;
uint8_t mask = ((uint8_t)1) << (block % 8);
if (tofreedata[index] & mask) {
/* really using the block, don't free it */
tofreedata[index] &= ~mask;
}
if (tofreedata[index] & mask) {
/* really using the block, don't free it */
tofreedata[index] &= ~mask;
}
if (freemapdata[index] & mask) {
warnx("Block %lu (used as %s) already in use! (NOT FIXED)",
(unsigned long) block, blockusagestr(how, howdesc));
setbadness(EXIT_UNRECOV);
}
if (freemapdata[index] & mask) {
warnx("Block %lu (used as %s) already in use! (NOT FIXED)",
(unsigned long)block, blockusagestr(how, howdesc));
setbadness(EXIT_UNRECOV);
}
freemapdata[index] |= mask;
freemapdata[index] |= mask;
if (how != B_PASTEND) {
blocksinuse++;
}
if (how != B_PASTEND) {
blocksinuse++;
}
}
/*
@@ -158,37 +149,33 @@ freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc)
* original usage to be something we are dropping, e.g. if a truncate
* (to a nonzero length > INOMAX_D) got partially completed.
*/
void
freemap_blockfree(uint32_t block)
{
unsigned index = block/8;
uint8_t mask = ((uint8_t)1)<<(block%8);
void freemap_blockfree(uint32_t block) {
unsigned index = block / 8;
uint8_t mask = ((uint8_t)1) << (block % 8);
if (tofreedata[index] & mask) {
/* already marked to free once, ignore */
return;
}
if (freemapdata[index] & mask) {
/* block is used elsewhere, ignore */
return;
}
tofreedata[index] |= mask;
if (tofreedata[index] & mask) {
/* already marked to free once, ignore */
return;
}
if (freemapdata[index] & mask) {
/* block is used elsewhere, ignore */
return;
}
tofreedata[index] |= mask;
}
/*
* Count the number of bits set.
*/
static
int
countbits(uint8_t val)
{
uint8_t x;
int ct=0;
static int countbits(uint8_t val) {
uint8_t x;
int ct = 0;
for (x=1; x; x<<=1) {
if (val & x) ct++;
}
return ct;
for (x = 1; x; x <<= 1) {
if (val & x)
ct++;
}
return ct;
}
/*
@@ -198,21 +185,18 @@ countbits(uint8_t val)
* byte offset within that block; VAL is the byte value; WHAT is a
* string indicating what happened.
*/
static
void
reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val, const char *what)
{
uint8_t x, y;
uint32_t blocknum;
static void reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val,
const char *what) {
uint8_t x, y;
uint32_t blocknum;
for (x=1, y=0; x; x<<=1, y++) {
if (val & x) {
blocknum = mapblock*SFS_BITSPERBLOCK +
byte*CHAR_BIT + y;
warnx("Block %lu erroneously shown %s in freemap",
(unsigned long) blocknum, what);
}
}
for (x = 1, y = 0; x; x <<= 1, y++) {
if (val & x) {
blocknum = mapblock * SFS_BITSPERBLOCK + byte * CHAR_BIT + y;
warnx("Block %lu erroneously shown %s in freemap",
(unsigned long)blocknum, what);
}
}
}
/*
@@ -221,90 +205,84 @@ reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val, const char *what)
* This is called after (at the end of) pass 1, when we've recursively
* found all the reachable blocks and marked them.
*/
void
freemap_check(void)
{
uint8_t actual[SFS_BLOCKSIZE], *expected, *tofree, tmp;
uint32_t alloccount=0, freecount=0, i, j;
int bchanged;
uint32_t bitblocks;
void freemap_check(void) {
uint8_t actual[SFS_BLOCKSIZE], *expected, *tofree, tmp;
uint32_t alloccount = 0, freecount = 0, i, j;
int bchanged;
uint32_t bitblocks;
bitblocks = sb_freemapblocks();
bitblocks = sb_freemapblocks();
for (i=0; i<bitblocks; i++) {
sfs_readfreemapblock(i, actual);
expected = freemapdata + i*SFS_BLOCKSIZE;
tofree = tofreedata + i*SFS_BLOCKSIZE;
bchanged = 0;
for (i = 0; i < bitblocks; i++) {
sfs_readfreemapblock(i, actual);
expected = freemapdata + i * SFS_BLOCKSIZE;
tofree = tofreedata + i * SFS_BLOCKSIZE;
bchanged = 0;
for (j=0; j<SFS_BLOCKSIZE; j++) {
/* we shouldn't have blocks marked both ways */
assert((expected[j] & tofree[j])==0);
for (j = 0; j < SFS_BLOCKSIZE; j++) {
/* we shouldn't have blocks marked both ways */
assert((expected[j] & tofree[j]) == 0);
/* what's there is what should be there */
if (actual[j] == expected[j]) {
continue;
}
/* what's there is what should be there */
if (actual[j] == expected[j]) {
continue;
}
/* what's there is what should be there modulo frees */
if (actual[j] == (expected[j] | tofree[j])) {
actual[j] = expected[j];
bchanged = 1;
continue;
}
/* what's there is what should be there modulo frees */
if (actual[j] == (expected[j] | tofree[j])) {
actual[j] = expected[j];
bchanged = 1;
continue;
}
/* oops, it doesn't match... */
/* oops, it doesn't match... */
/* free the ones we're freeing (don't report these) */
actual[j] &= ~tofree[j];
/* free the ones we're freeing (don't report these) */
actual[j] &= ~tofree[j];
/* are we short any? */
if ((actual[j] & expected[j]) != expected[j]) {
tmp = expected[j] & ~actual[j];
alloccount += countbits(tmp);
if (tmp != 0) {
reportfreemap(i, j, tmp, "free");
}
}
/* are we short any? */
if ((actual[j] & expected[j]) != expected[j]) {
tmp = expected[j] & ~actual[j];
alloccount += countbits(tmp);
if (tmp != 0) {
reportfreemap(i, j, tmp, "free");
}
}
/* do we have any extra? */
if ((actual[j] & expected[j]) != actual[j]) {
tmp = actual[j] & ~expected[j];
freecount += countbits(tmp);
if (tmp != 0) {
reportfreemap(i, j, tmp, "allocated");
}
}
/* do we have any extra? */
if ((actual[j] & expected[j]) != actual[j]) {
tmp = actual[j] & ~expected[j];
freecount += countbits(tmp);
if (tmp != 0) {
reportfreemap(i, j, tmp, "allocated");
}
}
/* set it to what it should be */
actual[j] = expected[j];
bchanged = 1;
}
/* set it to what it should be */
actual[j] = expected[j];
bchanged = 1;
}
/* write the block back if necessary */
if (bchanged) {
sfs_writefreemapblock(i, actual);
}
}
/* write the block back if necessary */
if (bchanged) {
sfs_writefreemapblock(i, actual);
}
}
if (alloccount > 0) {
warnx("%lu blocks erroneously shown free in freemap (fixed)",
(unsigned long) alloccount);
setbadness(EXIT_RECOV);
}
if (freecount > 0) {
warnx("%lu blocks erroneously shown used in freemap (fixed)",
(unsigned long) freecount);
setbadness(EXIT_RECOV);
}
if (alloccount > 0) {
warnx("%lu blocks erroneously shown free in freemap (fixed)",
(unsigned long)alloccount);
setbadness(EXIT_RECOV);
}
if (freecount > 0) {
warnx("%lu blocks erroneously shown used in freemap (fixed)",
(unsigned long)freecount);
setbadness(EXIT_RECOV);
}
}
/*
* Return the total number of blocks in use, which we count during
* pass 1.
*/
unsigned long
freemap_blocksused(void)
{
return blocksinuse;
}
unsigned long freemap_blocksused(void) { return blocksinuse; }

View File

@@ -39,13 +39,13 @@
#include <stdint.h>
typedef enum {
B_SUPERBLOCK, /* Block that is the superblock */
B_FREEMAPBLOCK, /* Block used by free-block bitmap */
B_INODE, /* Block that is an inode */
B_IBLOCK, /* Indirect (or doubly-indirect etc.) block */
B_DIRDATA, /* Data block of a directory */
B_DATA, /* Data block */
B_PASTEND, /* Block off the end of the fs */
B_SUPERBLOCK, /* Block that is the superblock */
B_FREEMAPBLOCK, /* Block used by free-block bitmap */
B_INODE, /* Block that is an inode */
B_IBLOCK, /* Indirect (or doubly-indirect etc.) block */
B_DIRDATA, /* Data block of a directory */
B_DATA, /* Data block */
B_PASTEND, /* Block off the end of the fs */
} blockusage_t;
/* Call this after loading the superblock but before doing any checks. */
@@ -63,5 +63,4 @@ void freemap_check(void);
/* Return the number of blocks in use. Valid after freemap_check(). */
unsigned long freemap_blocksused(void);
#endif /* FREEMAP_H */

View File

@@ -80,80 +80,79 @@
/* numbers */
#define NUM_D SFS_NDIRECT
#define NUM_I SFS_NINDIRECT
#define NUM_II SFS_NDINDIRECT
#define NUM_III SFS_NTINDIRECT
#define NUM_D SFS_NDIRECT
#define NUM_I SFS_NINDIRECT
#define NUM_II SFS_NDINDIRECT
#define NUM_III SFS_NTINDIRECT
/* blocks */
#if NUM_D == 0
#define GET_D(sfi, i) GET0_x(sfi, sfi_direct, i)
#define SET_D(sfi, i) SET0_x(sfi, sfi_direct, i)
#define GET_D(sfi, i) GET0_x(sfi, sfi_direct, i)
#define SET_D(sfi, i) SET0_x(sfi, sfi_direct, i)
#elif NUM_D == 1
#define GET_D(sfi, i) GET1_x(sfi, sfi_direct, i)
#define SET_D(sfi, i) SET1_x(sfi, sfi_direct, i)
#define GET_D(sfi, i) GET1_x(sfi, sfi_direct, i)
#define SET_D(sfi, i) SET1_x(sfi, sfi_direct, i)
#else
#define GET_D(sfi, i) GETN_x(sfi, sfi_direct, i)
#define SET_D(sfi, i) SETN_x(sfi, sfi_direct, i)
#define GET_D(sfi, i) GETN_x(sfi, sfi_direct, i)
#define SET_D(sfi, i) SETN_x(sfi, sfi_direct, i)
#endif
#if NUM_I == 0
#define GET_I(sfi, i) GET0_x(sfi, sfi_indirect, i)
#define SET_I(sfi, i) SET0_x(sfi, sfi_indirect, i)
#define GET_I(sfi, i) GET0_x(sfi, sfi_indirect, i)
#define SET_I(sfi, i) SET0_x(sfi, sfi_indirect, i)
#elif NUM_I == 1
#define GET_I(sfi, i) GET1_x(sfi, sfi_indirect, i)
#define SET_I(sfi, i) SET1_x(sfi, sfi_indirect, i)
#define GET_I(sfi, i) GET1_x(sfi, sfi_indirect, i)
#define SET_I(sfi, i) SET1_x(sfi, sfi_indirect, i)
#else
#define GET_I(sfi, i) GETN_x(sfi, sfi_indirect, i)
#define SET_I(sfi, i) SETN_x(sfi, sfi_indirect, i)
#define GET_I(sfi, i) GETN_x(sfi, sfi_indirect, i)
#define SET_I(sfi, i) SETN_x(sfi, sfi_indirect, i)
#endif
#if NUM_II == 0
#define GET_II(sfi, i) GET0_x(sfi, sfi_dindirect, i)
#define SET_II(sfi, i) SET0_x(sfi, sfi_dindirect, i)
#define GET_II(sfi, i) GET0_x(sfi, sfi_dindirect, i)
#define SET_II(sfi, i) SET0_x(sfi, sfi_dindirect, i)
#elif NUM_II == 1
#define GET_II(sfi, i) GET1_x(sfi, sfi_dindirect, i)
#define SET_II(sfi, i) SET1_x(sfi, sfi_dindirect, i)
#define GET_II(sfi, i) GET1_x(sfi, sfi_dindirect, i)
#define SET_II(sfi, i) SET1_x(sfi, sfi_dindirect, i)
#else
#define GET_II(sfi, i) GETN_x(sfi, sfi_dindirect, i)
#define SET_II(sfi, i) SETN_x(sfi, sfi_dindirect, i)
#define GET_II(sfi, i) GETN_x(sfi, sfi_dindirect, i)
#define SET_II(sfi, i) SETN_x(sfi, sfi_dindirect, i)
#endif
#if NUM_III == 0
#define GET_III(sfi, i) GET0_x(sfi, sfi_tindirect, i)
#define SET_III(sfi, i) SET0_x(sfi, sfi_tindirect, i)
#define GET_III(sfi, i) GET0_x(sfi, sfi_tindirect, i)
#define SET_III(sfi, i) SET0_x(sfi, sfi_tindirect, i)
#elif NUM_III == 1
#define GET_III(sfi, i) GET1_x(sfi, sfi_tindirect, i)
#define SET_III(sfi, i) SET1_x(sfi, sfi_tindirect, i)
#define GET_III(sfi, i) GET1_x(sfi, sfi_tindirect, i)
#define SET_III(sfi, i) SET1_x(sfi, sfi_tindirect, i)
#else
#define GET_III(sfi, i) GETN_x(sfi, sfi_tindirect, i)
#define SET_III(sfi, i) SETN_x(sfi, sfi_tindirect, i)
#define GET_III(sfi, i) GETN_x(sfi, sfi_tindirect, i)
#define SET_III(sfi, i) SETN_x(sfi, sfi_tindirect, i)
#endif
/* the generic forms of the block macros */
#define GET0_x(sfi, field, i) ((void)(i), (void)(sfi), 0)
#define GET1_x(sfi, field, i) ((void)(i), (sfi)->field)
#define GETN_x(sfi, field, i) ((sfi)->field[(i)])
#define GET0_x(sfi, field, i) ((void)(i), (void)(sfi), 0)
#define GET1_x(sfi, field, i) ((void)(i), (sfi)->field)
#define GETN_x(sfi, field, i) ((sfi)->field[(i)])
#define SET0_x(sfi, field, i) (*((void)(i), (void)(sfi), (uint32_t *)NULL))
#define SET1_x(sfi, field, i) (*((void)(i), &(sfi)->field))
#define SETN_x(sfi, field, i) ((sfi)->field[(i)])
#define SET0_x(sfi, field, i) (*((void)(i), (void)(sfi), (uint32_t *)NULL))
#define SET1_x(sfi, field, i) (*((void)(i), &(sfi)->field))
#define SETN_x(sfi, field, i) ((sfi)->field[(i)])
/* region sizes */
#define RANGE_D 1
#define RANGE_I (RANGE_D * SFS_DBPERIDB)
#define RANGE_II (RANGE_I * SFS_DBPERIDB)
#define RANGE_III (RANGE_II * SFS_DBPERIDB)
#define RANGE_D 1
#define RANGE_I (RANGE_D * SFS_DBPERIDB)
#define RANGE_II (RANGE_I * SFS_DBPERIDB)
#define RANGE_III (RANGE_II * SFS_DBPERIDB)
/* max blocks */
#define INOMAX_D NUM_D
#define INOMAX_I (INOMAX_D + SFS_DBPERIDB * NUM_I)
#define INOMAX_II (INOMAX_I + SFS_DBPERIDB * NUM_II)
#define INOMAX_III (INOMAX_II + SFS_DBPERIDB * NUM_III)
#define INOMAX_D NUM_D
#define INOMAX_I (INOMAX_D + SFS_DBPERIDB * NUM_I)
#define INOMAX_II (INOMAX_I + SFS_DBPERIDB * NUM_II)
#define INOMAX_III (INOMAX_II + SFS_DBPERIDB * NUM_III)
#endif /* IBMACROS_H */

View File

@@ -47,10 +47,10 @@
* FUTURE: should count the number of blocks allocated to this inode
*/
struct inodeinfo {
uint32_t ino;
uint32_t linkcount; /* files only */
int visited; /* dirs only */
int type;
uint32_t ino;
uint32_t linkcount; /* files only */
int visited; /* dirs only */
int type;
};
/* Table of inodes found. */
@@ -66,61 +66,53 @@ static int inodes_sorted = 0;
/*
* Add an entry to the inode table, realloc'ing it if needed.
*/
static
void
inode_addtable(uint32_t ino, int type)
{
unsigned newmax;
static void inode_addtable(uint32_t ino, int type) {
unsigned newmax;
assert(ninodes <= maxinodes);
if (ninodes == maxinodes) {
newmax = maxinodes ? maxinodes * 2 : 4;
inodes = dorealloc(inodes, maxinodes * sizeof(inodes[0]),
newmax * sizeof(inodes[0]));
maxinodes = newmax;
}
inodes[ninodes].ino = ino;
inodes[ninodes].linkcount = 0;
inodes[ninodes].visited = 0;
inodes[ninodes].type = type;
ninodes++;
inodes_sorted = 0;
assert(ninodes <= maxinodes);
if (ninodes == maxinodes) {
newmax = maxinodes ? maxinodes * 2 : 4;
inodes = dorealloc(inodes, maxinodes * sizeof(inodes[0]),
newmax * sizeof(inodes[0]));
maxinodes = newmax;
}
inodes[ninodes].ino = ino;
inodes[ninodes].linkcount = 0;
inodes[ninodes].visited = 0;
inodes[ninodes].type = type;
ninodes++;
inodes_sorted = 0;
}
/*
* Compare function for inodes.
*/
static
int
inode_compare(const void *av, const void *bv)
{
const struct inodeinfo *a = av;
const struct inodeinfo *b = bv;
static int inode_compare(const void *av, const void *bv) {
const struct inodeinfo *a = av;
const struct inodeinfo *b = bv;
if (a->ino < b->ino) {
return -1;
}
if (a->ino > b->ino) {
return 1;
}
/*
* There should be no duplicates in the table! But C99 makes
* no guarantees about whether the implementation of qsort can
* ask us to compare an element to itself. Assert that this is
* what happened.
*/
assert(av == bv);
return 0;
if (a->ino < b->ino) {
return -1;
}
if (a->ino > b->ino) {
return 1;
}
/*
* There should be no duplicates in the table! But C99 makes
* no guarantees about whether the implementation of qsort can
* ask us to compare an element to itself. Assert that this is
* what happened.
*/
assert(av == bv);
return 0;
}
/*
* After pass1, we sort the inode table for faster access.
*/
void
inode_sorttable(void)
{
qsort(inodes, ninodes, sizeof(inodes[0]), inode_compare);
inodes_sorted = 1;
void inode_sorttable(void) {
qsort(inodes, ninodes, sizeof(inodes[0]), inode_compare);
inodes_sorted = 1;
}
/*
@@ -132,35 +124,30 @@ inode_sorttable(void)
* pass2.c, we'll need to be able to ask if an inode number is valid
* and names a directory.)
*/
static
struct inodeinfo *
inode_find(uint32_t ino)
{
unsigned min, max, i;
static struct inodeinfo *inode_find(uint32_t ino) {
unsigned min, max, i;
assert(inodes_sorted);
assert(ninodes > 0);
assert(inodes_sorted);
assert(ninodes > 0);
min = 0;
max = ninodes;
while (1) {
assert(min <= max);
if (min == max) {
errx(EXIT_UNRECOV, "FATAL: inode %u wasn't found in my inode table", ino);
}
i = min + (max - min)/2;
if (inodes[i].ino < ino) {
min = i + 1;
}
else if (inodes[i].ino > ino) {
max = i;
}
else {
assert(inodes[i].ino == ino);
return &inodes[i];
}
}
/* NOTREACHED */
min = 0;
max = ninodes;
while (1) {
assert(min <= max);
if (min == max) {
errx(EXIT_UNRECOV, "FATAL: inode %u wasn't found in my inode table", ino);
}
i = min + (max - min) / 2;
if (inodes[i].ino < ino) {
min = i + 1;
} else if (inodes[i].ino > ino) {
max = i;
} else {
assert(inodes[i].ino == ino);
return &inodes[i];
}
}
/* NOTREACHED */
}
////////////////////////////////////////////////////////////
@@ -173,22 +160,20 @@ inode_find(uint32_t ino)
* after all inodes have been added. In the FUTURE this could be
* changed to a better data structure.
*/
int
inode_add(uint32_t ino, int type)
{
unsigned i;
int inode_add(uint32_t ino, int type) {
unsigned i;
for (i=0; i<ninodes; i++) {
if (inodes[i].ino==ino) {
assert(inodes[i].linkcount == 0);
assert(inodes[i].type == type);
return 1;
}
}
for (i = 0; i < ninodes; i++) {
if (inodes[i].ino == ino) {
assert(inodes[i].linkcount == 0);
assert(inodes[i].type == type);
return 1;
}
}
inode_addtable(ino, type);
inode_addtable(ino, type);
return 0;
return 0;
}
/*
@@ -198,19 +183,17 @@ inode_add(uint32_t ino, int type)
* Note that there is no way to clear the visited flag for now because
* it's only used once (by pass2).
*/
int
inode_visitdir(uint32_t ino)
{
struct inodeinfo *inf;
int inode_visitdir(uint32_t ino) {
struct inodeinfo *inf;
inf = inode_find(ino);
assert(inf->type == SFS_TYPE_DIR);
assert(inf->linkcount == 0);
if (inf->visited) {
return 1;
}
inf->visited = 1;
return 0;
inf = inode_find(ino);
assert(inf->type == SFS_TYPE_DIR);
assert(inf->linkcount == 0);
if (inf->visited) {
return 1;
}
inf->visited = 1;
return 0;
}
/*
@@ -218,49 +201,43 @@ inode_visitdir(uint32_t ino)
* does. (And that, in turn, is because the link count of a directory
* is a local property.)
*/
void
inode_addlink(uint32_t ino)
{
struct inodeinfo *inf;
void inode_addlink(uint32_t ino) {
struct inodeinfo *inf;
inf = inode_find(ino);
assert(inf->type == SFS_TYPE_FILE);
assert(inf->visited == 0);
inf->linkcount++;
inf = inode_find(ino);
assert(inf->type == SFS_TYPE_FILE);
assert(inf->visited == 0);
inf->linkcount++;
}
/*
* Correct link counts. This is effectively pass3. (FUTURE: change the
* name accordingly.)
*/
void
inode_adjust_filelinks(void)
{
struct sfs_dinode sfi;
unsigned i;
void inode_adjust_filelinks(void) {
struct sfs_dinode sfi;
unsigned i;
for (i=0; i<ninodes; i++) {
if (inodes[i].type == SFS_TYPE_DIR) {
/* directory */
continue;
}
assert(inodes[i].type == SFS_TYPE_FILE);
for (i = 0; i < ninodes; i++) {
if (inodes[i].type == SFS_TYPE_DIR) {
/* directory */
continue;
}
assert(inodes[i].type == SFS_TYPE_FILE);
/* because we've seen it, there must be at least one link */
assert(inodes[i].linkcount > 0);
/* because we've seen it, there must be at least one link */
assert(inodes[i].linkcount > 0);
sfs_readinode(inodes[i].ino, &sfi);
assert(sfi.sfi_type == SFS_TYPE_FILE);
sfs_readinode(inodes[i].ino, &sfi);
assert(sfi.sfi_type == SFS_TYPE_FILE);
if (sfi.sfi_linkcount != inodes[i].linkcount) {
warnx("File %lu link count %lu should be %lu (fixed)",
(unsigned long) inodes[i].ino,
(unsigned long) sfi.sfi_linkcount,
(unsigned long) inodes[i].linkcount);
sfi.sfi_linkcount = inodes[i].linkcount;
setbadness(EXIT_RECOV);
sfs_writeinode(inodes[i].ino, &sfi);
}
}
if (sfi.sfi_linkcount != inodes[i].linkcount) {
warnx("File %lu link count %lu should be %lu (fixed)",
(unsigned long)inodes[i].ino, (unsigned long)sfi.sfi_linkcount,
(unsigned long)inodes[i].linkcount);
sfi.sfi_linkcount = inodes[i].linkcount;
setbadness(EXIT_RECOV);
sfs_writeinode(inodes[i].ino, &sfi);
}
}
}

View File

@@ -61,5 +61,4 @@ void inode_addlink(uint32_t ino);
*/
void inode_adjust_filelinks(void);
#endif /* INODE_H */

View File

@@ -42,7 +42,7 @@
#include "passes.h"
#include "main.h"
static int badness=0;
static int badness = 0;
/*
* Update the badness state. (codes are in main.h)
@@ -50,69 +50,65 @@ static int badness=0;
* The badness state only gets worse, and is ultimately the process
* exit code.
*/
void
setbadness(int code)
{
if (badness < code) {
badness = code;
}
void setbadness(int code) {
if (badness < code) {
badness = code;
}
}
/*
* Main.
*/
int
main(int argc, char **argv)
{
int main(int argc, char **argv) {
#ifdef HOST
hostcompat_init(argc, argv);
hostcompat_init(argc, argv);
#endif
/* FUTURE: add -n option */
if (argc!=2) {
errx(EXIT_USAGE, "Usage: sfsck device/diskfile");
}
/* FUTURE: add -n option */
if (argc != 2) {
errx(EXIT_USAGE, "Usage: sfsck device/diskfile");
}
opendisk(argv[1]);
opendisk(argv[1]);
sfs_setup();
sb_load();
sb_check();
freemap_setup();
sfs_setup();
sb_load();
sb_check();
freemap_setup();
printf("Phase 1 -- check blocks and sizes\n");
pass1();
freemap_check();
printf("Phase 1 -- check blocks and sizes\n");
pass1();
freemap_check();
printf("Phase 2 -- check directory tree\n");
inode_sorttable();
pass2();
printf("Phase 2 -- check directory tree\n");
inode_sorttable();
pass2();
printf("Phase 3 -- check reference counts\n");
inode_adjust_filelinks();
printf("Phase 3 -- check reference counts\n");
inode_adjust_filelinks();
closedisk();
closedisk();
warnx("%lu blocks used (of %lu); %lu directories; %lu files",
freemap_blocksused(), (unsigned long)sb_totalblocks(),
pass1_founddirs(), pass1_foundfiles());
warnx("%lu blocks used (of %lu); %lu directories; %lu files",
freemap_blocksused(), (unsigned long)sb_totalblocks(),
pass1_founddirs(), pass1_foundfiles());
switch (badness) {
case EXIT_USAGE:
case EXIT_FATAL:
default:
/* not supposed to happen here */
assert(0);
break;
case EXIT_UNRECOV:
warnx("WARNING - unrecoverable errors. Maybe try again?");
break;
case EXIT_RECOV:
warnx("Caution - filesystem modified. Run again for luck.");
break;
case EXIT_CLEAN:
break;
}
switch (badness) {
case EXIT_USAGE:
case EXIT_FATAL:
default:
/* not supposed to happen here */
assert(0);
break;
case EXIT_UNRECOV:
warnx("WARNING - unrecoverable errors. Maybe try again?");
break;
case EXIT_RECOV:
warnx("Caution - filesystem modified. Run again for luck.");
break;
case EXIT_CLEAN:
break;
}
return badness;
return badness;
}

View File

@@ -37,11 +37,11 @@
* the ultimate exit code of sfsck.
*/
#define EXIT_USAGE 4
#define EXIT_FATAL 3
#define EXIT_UNRECOV 2
#define EXIT_RECOV 1
#define EXIT_CLEAN 0
#define EXIT_USAGE 4
#define EXIT_FATAL 3
#define EXIT_UNRECOV 2
#define EXIT_RECOV 1
#define EXIT_CLEAN 0
void setbadness(int code);

View File

@@ -47,18 +47,18 @@
#include "passes.h"
#include "main.h"
static unsigned long count_dirs=0, count_files=0;
static unsigned long count_dirs = 0, count_files = 0;
/*
* State for checking indirect blocks.
*/
struct ibstate {
uint32_t ino; /* inode we're doing (constant) */
uint32_t curfileblock; /* current block offset in the file */
uint32_t fileblocks; /* file size in blocks (constant) */
uint32_t volblocks; /* volume size in blocks (constant) */
unsigned pasteofcount; /* number of blocks found past eof */
blockusage_t usagetype; /* how to call freemap_blockinuse() */
uint32_t ino; /* inode we're doing (constant) */
uint32_t curfileblock; /* current block offset in the file */
uint32_t fileblocks; /* file size in blocks (constant) */
uint32_t volblocks; /* volume size in blocks (constant) */
unsigned pasteofcount; /* number of blocks found past eof */
blockusage_t usagetype; /* how to call freemap_blockinuse() */
};
/*
@@ -76,100 +76,88 @@ struct ibstate {
* scanning. IECHANGEDP should be set to 1 if *IENTRY is changed.
* INDIRECTION is the indirection level of this block (1, 2, or 3).
*/
static
void
check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
int indirection)
{
uint32_t entries[SFS_DBPERIDB];
uint32_t i, ct;
uint32_t coveredblocks;
int localchanged = 0;
int j;
static void check_indirect_block(struct ibstate *ibs, uint32_t *ientry,
int *iechangedp, int indirection) {
uint32_t entries[SFS_DBPERIDB];
uint32_t i, ct;
uint32_t coveredblocks;
int localchanged = 0;
int j;
if (*ientry > 0 && *ientry < ibs->volblocks) {
sfs_readindirect(*ientry, entries);
freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
}
else {
if (*ientry >= ibs->volblocks) {
setbadness(EXIT_RECOV);
warnx("Inode %lu: indirect block pointer (level %d) "
"for block %lu outside of volume: %lu "
"(cleared)\n",
(unsigned long)ibs->ino, indirection,
(unsigned long)ibs->curfileblock,
(unsigned long)*ientry);
*ientry = 0;
*iechangedp = 1;
}
coveredblocks = 1;
for (j=0; j<indirection; j++) {
coveredblocks *= SFS_DBPERIDB;
}
ibs->curfileblock += coveredblocks;
return;
}
if (*ientry > 0 && *ientry < ibs->volblocks) {
sfs_readindirect(*ientry, entries);
freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
} else {
if (*ientry >= ibs->volblocks) {
setbadness(EXIT_RECOV);
warnx("Inode %lu: indirect block pointer (level %d) "
"for block %lu outside of volume: %lu "
"(cleared)\n",
(unsigned long)ibs->ino, indirection,
(unsigned long)ibs->curfileblock, (unsigned long)*ientry);
*ientry = 0;
*iechangedp = 1;
}
coveredblocks = 1;
for (j = 0; j < indirection; j++) {
coveredblocks *= SFS_DBPERIDB;
}
ibs->curfileblock += coveredblocks;
return;
}
if (indirection > 1) {
for (i=0; i<SFS_DBPERIDB; i++) {
check_indirect_block(ibs, &entries[i], &localchanged,
indirection-1);
}
}
else {
assert(indirection==1);
if (indirection > 1) {
for (i = 0; i < SFS_DBPERIDB; i++) {
check_indirect_block(ibs, &entries[i], &localchanged, indirection - 1);
}
} else {
assert(indirection == 1);
for (i=0; i<SFS_DBPERIDB; i++) {
if (entries[i] >= ibs->volblocks) {
setbadness(EXIT_RECOV);
warnx("Inode %lu: direct block pointer for "
"block %lu outside of volume: %lu "
"(cleared)\n",
(unsigned long)ibs->ino,
(unsigned long)ibs->curfileblock,
(unsigned long)entries[i]);
entries[i] = 0;
localchanged = 1;
}
else if (entries[i] != 0) {
if (ibs->curfileblock < ibs->fileblocks) {
freemap_blockinuse(entries[i],
ibs->usagetype,
ibs->ino);
}
else {
setbadness(EXIT_RECOV);
ibs->pasteofcount++;
freemap_blockfree(entries[i]);
entries[i] = 0;
localchanged = 1;
}
}
ibs->curfileblock++;
}
}
for (i = 0; i < SFS_DBPERIDB; i++) {
if (entries[i] >= ibs->volblocks) {
setbadness(EXIT_RECOV);
warnx("Inode %lu: direct block pointer for "
"block %lu outside of volume: %lu "
"(cleared)\n",
(unsigned long)ibs->ino, (unsigned long)ibs->curfileblock,
(unsigned long)entries[i]);
entries[i] = 0;
localchanged = 1;
} else if (entries[i] != 0) {
if (ibs->curfileblock < ibs->fileblocks) {
freemap_blockinuse(entries[i], ibs->usagetype, ibs->ino);
} else {
setbadness(EXIT_RECOV);
ibs->pasteofcount++;
freemap_blockfree(entries[i]);
entries[i] = 0;
localchanged = 1;
}
}
ibs->curfileblock++;
}
}
ct=0;
for (i=ct=0; i<SFS_DBPERIDB; i++) {
if (entries[i]!=0) ct++;
}
if (ct==0) {
if (*ientry != 0) {
setbadness(EXIT_RECOV);
/* this is not necessarily correct */
/*ibs->pasteofcount++;*/
*iechangedp = 1;
freemap_blockfree(*ientry);
*ientry = 0;
}
}
else {
assert(*ientry != 0);
if (localchanged) {
sfs_writeindirect(*ientry, entries);
}
}
ct = 0;
for (i = ct = 0; i < SFS_DBPERIDB; i++) {
if (entries[i] != 0)
ct++;
}
if (ct == 0) {
if (*ientry != 0) {
setbadness(EXIT_RECOV);
/* this is not necessarily correct */
/*ibs->pasteofcount++;*/
*iechangedp = 1;
freemap_blockfree(*ientry);
*ientry = 0;
}
} else {
assert(*ientry != 0);
if (localchanged) {
sfs_writeindirect(*ientry, entries);
}
}
}
/*
@@ -180,71 +168,64 @@ check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
* Returns nonzero if SFI has been modified and needs to be written
* back.
*/
static
int
check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
{
struct ibstate ibs;
uint32_t size, datablock;
int changed;
int i;
static int check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir) {
struct ibstate ibs;
uint32_t size, datablock;
int changed;
int i;
size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
ibs.ino = ino;
/*ibs.curfileblock = 0;*/
ibs.fileblocks = size/SFS_BLOCKSIZE;
ibs.volblocks = sb_totalblocks();
ibs.pasteofcount = 0;
ibs.usagetype = isdir ? B_DIRDATA : B_DATA;
ibs.ino = ino;
/*ibs.curfileblock = 0;*/
ibs.fileblocks = size / SFS_BLOCKSIZE;
ibs.volblocks = sb_totalblocks();
ibs.pasteofcount = 0;
ibs.usagetype = isdir ? B_DIRDATA : B_DATA;
changed = 0;
changed = 0;
for (ibs.curfileblock=0; ibs.curfileblock<NUM_D; ibs.curfileblock++) {
datablock = GET_D(sfi, ibs.curfileblock);
if (datablock >= ibs.volblocks) {
setbadness(EXIT_RECOV);
warnx("Inode %lu: direct block pointer for "
"block %lu outside of volume: %lu "
"(cleared)\n",
(unsigned long)ibs.ino,
(unsigned long)ibs.curfileblock,
(unsigned long)datablock);
SET_D(sfi, ibs.curfileblock) = 0;
changed = 1;
}
else if (datablock > 0) {
if (ibs.curfileblock < ibs.fileblocks) {
freemap_blockinuse(datablock, ibs.usagetype,
ibs.ino);
}
else {
setbadness(EXIT_RECOV);
ibs.pasteofcount++;
changed = 1;
freemap_blockfree(datablock);
SET_D(sfi, ibs.curfileblock) = 0;
}
}
}
for (ibs.curfileblock = 0; ibs.curfileblock < NUM_D; ibs.curfileblock++) {
datablock = GET_D(sfi, ibs.curfileblock);
if (datablock >= ibs.volblocks) {
setbadness(EXIT_RECOV);
warnx("Inode %lu: direct block pointer for "
"block %lu outside of volume: %lu "
"(cleared)\n",
(unsigned long)ibs.ino, (unsigned long)ibs.curfileblock,
(unsigned long)datablock);
SET_D(sfi, ibs.curfileblock) = 0;
changed = 1;
} else if (datablock > 0) {
if (ibs.curfileblock < ibs.fileblocks) {
freemap_blockinuse(datablock, ibs.usagetype, ibs.ino);
} else {
setbadness(EXIT_RECOV);
ibs.pasteofcount++;
changed = 1;
freemap_blockfree(datablock);
SET_D(sfi, ibs.curfileblock) = 0;
}
}
}
for (i=0; i<NUM_I; i++) {
check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
}
for (i=0; i<NUM_II; i++) {
check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
}
for (i=0; i<NUM_III; i++) {
check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
}
for (i = 0; i < NUM_I; i++) {
check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
}
for (i = 0; i < NUM_II; i++) {
check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
}
for (i = 0; i < NUM_III; i++) {
check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
}
if (ibs.pasteofcount > 0) {
warnx("Inode %lu: %u blocks after EOF (freed)",
(unsigned long) ibs.ino, ibs.pasteofcount);
setbadness(EXIT_RECOV);
}
if (ibs.pasteofcount > 0) {
warnx("Inode %lu: %u blocks after EOF (freed)", (unsigned long)ibs.ino,
ibs.pasteofcount);
setbadness(EXIT_RECOV);
}
return changed;
return changed;
}
/*
@@ -255,99 +236,90 @@ check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
* Returns nonzero if SFI has been modified and needs to be written
* back.
*/
static
int
pass1_inode(uint32_t ino, struct sfs_dinode *sfi, int alreadychanged)
{
int changed = alreadychanged;
int isdir = sfi->sfi_type == SFS_TYPE_DIR;
static int pass1_inode(uint32_t ino, struct sfs_dinode *sfi,
int alreadychanged) {
int changed = alreadychanged;
int isdir = sfi->sfi_type == SFS_TYPE_DIR;
if (inode_add(ino, sfi->sfi_type)) {
/* Already been here. */
assert(changed == 0);
return 1;
}
if (inode_add(ino, sfi->sfi_type)) {
/* Already been here. */
assert(changed == 0);
return 1;
}
freemap_blockinuse(ino, B_INODE, ino);
freemap_blockinuse(ino, B_INODE, ino);
if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) {
warnx("Inode %lu: sfi_waste section not zeroed (fixed)",
(unsigned long) ino);
setbadness(EXIT_RECOV);
changed = 1;
}
if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) {
warnx("Inode %lu: sfi_waste section not zeroed (fixed)",
(unsigned long)ino);
setbadness(EXIT_RECOV);
changed = 1;
}
if (check_inode_blocks(ino, sfi, isdir)) {
changed = 1;
}
if (check_inode_blocks(ino, sfi, isdir)) {
changed = 1;
}
if (changed) {
sfs_writeinode(ino, sfi);
}
return 0;
if (changed) {
sfs_writeinode(ino, sfi);
}
return 0;
}
/*
* Check the directory entry in SFD. INDEX is its offset, and PATH is
* its name; these are used for printing messages.
*/
static
int
pass1_direntry(const char *path, uint32_t index, struct sfs_direntry *sfd)
{
int dchanged = 0;
uint32_t nblocks;
static int pass1_direntry(const char *path, uint32_t index,
struct sfs_direntry *sfd) {
int dchanged = 0;
uint32_t nblocks;
nblocks = sb_totalblocks();
nblocks = sb_totalblocks();
if (sfd->sfd_ino == SFS_NOINO) {
if (sfd->sfd_name[0] != 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu has name but no file",
path, (unsigned long) index);
sfd->sfd_name[0] = 0;
dchanged = 1;
}
}
else if (sfd->sfd_ino >= nblocks) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu has out of range "
"inode (cleared)",
path, (unsigned long) index);
sfd->sfd_ino = SFS_NOINO;
sfd->sfd_name[0] = 0;
dchanged = 1;
}
else {
if (sfd->sfd_name[0] == 0) {
/* XXX: what happens if FSCK.n.m already exists? */
snprintf(sfd->sfd_name, sizeof(sfd->sfd_name),
"FSCK.%lu.%lu",
(unsigned long) sfd->sfd_ino,
(unsigned long) uniqueid());
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu has file but "
"no name (fixed: %s)",
path, (unsigned long) index,
sfd->sfd_name);
dchanged = 1;
}
if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu not "
"null-terminated (fixed)",
path, (unsigned long) index);
dchanged = 1;
}
if (checkbadstring(sfd->sfd_name)) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu contains invalid "
"characters (fixed)",
path, (unsigned long) index);
dchanged = 1;
}
}
return dchanged;
if (sfd->sfd_ino == SFS_NOINO) {
if (sfd->sfd_name[0] != 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu has name but no file", path,
(unsigned long)index);
sfd->sfd_name[0] = 0;
dchanged = 1;
}
} else if (sfd->sfd_ino >= nblocks) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu has out of range "
"inode (cleared)",
path, (unsigned long)index);
sfd->sfd_ino = SFS_NOINO;
sfd->sfd_name[0] = 0;
dchanged = 1;
} else {
if (sfd->sfd_name[0] == 0) {
/* XXX: what happens if FSCK.n.m already exists? */
snprintf(sfd->sfd_name, sizeof(sfd->sfd_name), "FSCK.%lu.%lu",
(unsigned long)sfd->sfd_ino, (unsigned long)uniqueid());
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu has file but "
"no name (fixed: %s)",
path, (unsigned long)index, sfd->sfd_name);
dchanged = 1;
}
if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu not "
"null-terminated (fixed)",
path, (unsigned long)index);
dchanged = 1;
}
if (checkbadstring(sfd->sfd_name)) {
setbadness(EXIT_RECOV);
warnx("Directory %s entry %lu contains invalid "
"characters (fixed)",
path, (unsigned long)index);
dchanged = 1;
}
}
return dchanged;
}
/*
@@ -355,142 +327,120 @@ pass1_direntry(const char *path, uint32_t index, struct sfs_direntry *sfd)
* to this directory. This traverses the volume directory tree
* recursively.
*/
static
void
pass1_dir(uint32_t ino, const char *pathsofar)
{
struct sfs_dinode sfi;
struct sfs_direntry *direntries;
uint32_t ndirentries, i;
int ichanged=0, dchanged=0;
static void pass1_dir(uint32_t ino, const char *pathsofar) {
struct sfs_dinode sfi;
struct sfs_direntry *direntries;
uint32_t ndirentries, i;
int ichanged = 0, dchanged = 0;
sfs_readinode(ino, &sfi);
sfs_readinode(ino, &sfi);
if (sfi.sfi_size % sizeof(struct sfs_direntry) != 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s has illegal size %lu (fixed)",
pathsofar, (unsigned long) sfi.sfi_size);
sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
sizeof(struct sfs_direntry));
ichanged = 1;
}
count_dirs++;
if (sfi.sfi_size % sizeof(struct sfs_direntry) != 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s has illegal size %lu (fixed)", pathsofar,
(unsigned long)sfi.sfi_size);
sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size, sizeof(struct sfs_direntry));
ichanged = 1;
}
count_dirs++;
if (pass1_inode(ino, &sfi, ichanged)) {
/* been here before; crosslinked dir, sort it out in pass 2 */
return;
}
if (pass1_inode(ino, &sfi, ichanged)) {
/* been here before; crosslinked dir, sort it out in pass 2 */
return;
}
ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry);
direntries = domalloc(sfi.sfi_size);
ndirentries = sfi.sfi_size / sizeof(struct sfs_direntry);
direntries = domalloc(sfi.sfi_size);
sfs_readdir(&sfi, direntries, ndirentries);
sfs_readdir(&sfi, direntries, ndirentries);
for (i=0; i<ndirentries; i++) {
if (pass1_direntry(pathsofar, i, &direntries[i])) {
dchanged = 1;
}
}
for (i = 0; i < ndirentries; i++) {
if (pass1_direntry(pathsofar, i, &direntries[i])) {
dchanged = 1;
}
}
for (i=0; i<ndirentries; i++) {
if (direntries[i].sfd_ino == SFS_NOINO) {
/* nothing */
}
else if (!strcmp(direntries[i].sfd_name, ".")) {
/* nothing */
}
else if (!strcmp(direntries[i].sfd_name, "..")) {
/* nothing */
}
else {
char path[strlen(pathsofar)+SFS_NAMELEN+1];
struct sfs_dinode subsfi;
uint32_t subino;
for (i = 0; i < ndirentries; i++) {
if (direntries[i].sfd_ino == SFS_NOINO) {
/* nothing */
} else if (!strcmp(direntries[i].sfd_name, ".")) {
/* nothing */
} else if (!strcmp(direntries[i].sfd_name, "..")) {
/* nothing */
} else {
char path[strlen(pathsofar) + SFS_NAMELEN + 1];
struct sfs_dinode subsfi;
uint32_t subino;
subino = direntries[i].sfd_ino;
sfs_readinode(subino, &subsfi);
snprintf(path, sizeof(path), "%s/%s",
pathsofar, direntries[i].sfd_name);
subino = direntries[i].sfd_ino;
sfs_readinode(subino, &subsfi);
snprintf(path, sizeof(path), "%s/%s", pathsofar, direntries[i].sfd_name);
switch (subsfi.sfi_type) {
case SFS_TYPE_FILE:
if (pass1_inode(subino, &subsfi, 0)) {
/* been here before */
break;
}
count_files++;
break;
case SFS_TYPE_DIR:
pass1_dir(subino, path);
break;
default:
setbadness(EXIT_RECOV);
warnx("Object %s: Invalid inode type %u "
"(removed)", path, subsfi.sfi_type);
direntries[i].sfd_ino = SFS_NOINO;
direntries[i].sfd_name[0] = 0;
dchanged = 1;
break;
}
}
}
switch (subsfi.sfi_type) {
case SFS_TYPE_FILE:
if (pass1_inode(subino, &subsfi, 0)) {
/* been here before */
break;
}
count_files++;
break;
case SFS_TYPE_DIR:
pass1_dir(subino, path);
break;
default:
setbadness(EXIT_RECOV);
warnx("Object %s: Invalid inode type %u "
"(removed)",
path, subsfi.sfi_type);
direntries[i].sfd_ino = SFS_NOINO;
direntries[i].sfd_name[0] = 0;
dchanged = 1;
break;
}
}
}
if (dchanged) {
sfs_writedir(&sfi, direntries, ndirentries);
}
if (dchanged) {
sfs_writedir(&sfi, direntries, ndirentries);
}
free(direntries);
free(direntries);
}
/*
* Check the root directory, and implicitly everything under it.
*/
static
void
pass1_rootdir(void)
{
struct sfs_dinode sfi;
char path[SFS_VOLNAME_SIZE + 2];
static void pass1_rootdir(void) {
struct sfs_dinode sfi;
char path[SFS_VOLNAME_SIZE + 2];
sfs_readinode(SFS_ROOTDIR_INO, &sfi);
sfs_readinode(SFS_ROOTDIR_INO, &sfi);
switch (sfi.sfi_type) {
case SFS_TYPE_DIR:
break;
case SFS_TYPE_FILE:
warnx("Root directory inode is a regular file (fixed)");
goto fix;
default:
warnx("Root directory inode has invalid type %lu (fixed)",
(unsigned long) sfi.sfi_type);
fix:
setbadness(EXIT_RECOV);
sfi.sfi_type = SFS_TYPE_DIR;
sfs_writeinode(SFS_ROOTDIR_INO, &sfi);
break;
}
switch (sfi.sfi_type) {
case SFS_TYPE_DIR:
break;
case SFS_TYPE_FILE:
warnx("Root directory inode is a regular file (fixed)");
goto fix;
default:
warnx("Root directory inode has invalid type %lu (fixed)",
(unsigned long)sfi.sfi_type);
fix:
setbadness(EXIT_RECOV);
sfi.sfi_type = SFS_TYPE_DIR;
sfs_writeinode(SFS_ROOTDIR_INO, &sfi);
break;
}
snprintf(path, sizeof(path), "%s:", sb_volname());
pass1_dir(SFS_ROOTDIR_INO, path);
snprintf(path, sizeof(path), "%s:", sb_volname());
pass1_dir(SFS_ROOTDIR_INO, path);
}
////////////////////////////////////////////////////////////
// public interface
void
pass1(void)
{
pass1_rootdir();
}
void pass1(void) { pass1_rootdir(); }
unsigned long
pass1_founddirs(void)
{
return count_dirs;
}
unsigned long pass1_founddirs(void) { return count_dirs; }
unsigned long
pass1_foundfiles(void)
{
return count_files;
}
unsigned long pass1_foundfiles(void) { return count_files; }

View File

@@ -58,268 +58,241 @@
* instead of the first entry we recursively find. Beware of course
* that the .. entry might not point to anywhere valid at all...
*/
static
int
pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
{
struct sfs_dinode sfi;
struct sfs_direntry *direntries;
int *sortvector;
uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;
static int pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar) {
struct sfs_dinode sfi;
struct sfs_direntry *direntries;
int *sortvector;
uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
int ichanged = 0, dchanged = 0, dotseen = 0, dotdotseen = 0;
if (inode_visitdir(ino)) {
/* crosslinked dir; tell parent to remove the entry */
return 1;
}
if (inode_visitdir(ino)) {
/* crosslinked dir; tell parent to remove the entry */
return 1;
}
/* Load the inode. */
sfs_readinode(ino, &sfi);
/* Load the inode. */
sfs_readinode(ino, &sfi);
/*
* Load the directory. If there is any leftover room in the
* last block, allocate space for it in case we want to insert
* entries.
*/
/*
* Load the directory. If there is any leftover room in the
* last block, allocate space for it in case we want to insert
* entries.
*/
ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry);
maxdirentries = SFS_ROUNDUP(ndirentries,
SFS_BLOCKSIZE/sizeof(struct sfs_direntry));
dirsize = maxdirentries * sizeof(struct sfs_direntry);
direntries = domalloc(dirsize);
ndirentries = sfi.sfi_size / sizeof(struct sfs_direntry);
maxdirentries =
SFS_ROUNDUP(ndirentries, SFS_BLOCKSIZE / sizeof(struct sfs_direntry));
dirsize = maxdirentries * sizeof(struct sfs_direntry);
direntries = domalloc(dirsize);
sortvector = domalloc(ndirentries * sizeof(int));
sortvector = domalloc(ndirentries * sizeof(int));
sfs_readdir(&sfi, direntries, ndirentries);
for (i=ndirentries; i<maxdirentries; i++) {
direntries[i].sfd_ino = SFS_NOINO;
bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
}
sfs_readdir(&sfi, direntries, ndirentries);
for (i = ndirentries; i < maxdirentries; i++) {
direntries[i].sfd_ino = SFS_NOINO;
bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
}
/*
* Sort by name and check for duplicate names.
*/
/*
* Sort by name and check for duplicate names.
*/
sfsdir_sort(direntries, ndirentries, sortvector);
sfsdir_sort(direntries, ndirentries, sortvector);
/* don't use ndirentries-1 here, in case ndirentries == 0 */
for (i=0; i+1<ndirentries; i++) {
struct sfs_direntry *d1 = &direntries[sortvector[i]];
struct sfs_direntry *d2 = &direntries[sortvector[i+1]];
assert(d1 != d2);
/* don't use ndirentries-1 here, in case ndirentries == 0 */
for (i = 0; i + 1 < ndirentries; i++) {
struct sfs_direntry *d1 = &direntries[sortvector[i]];
struct sfs_direntry *d2 = &direntries[sortvector[i + 1]];
assert(d1 != d2);
if (d1->sfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) {
/* sfsdir_sort puts these last */
continue;
}
if (d1->sfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) {
/* sfsdir_sort puts these last */
continue;
}
if (!strcmp(d1->sfd_name, d2->sfd_name)) {
if (d1->sfd_ino == d2->sfd_ino) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Duplicate entries for "
"%s (merged)",
pathsofar, d1->sfd_name);
d1->sfd_ino = SFS_NOINO;
d1->sfd_name[0] = 0;
}
else {
/* XXX: what if FSCK.n.m already exists? */
snprintf(d1->sfd_name, sizeof(d1->sfd_name),
"FSCK.%lu.%lu",
(unsigned long) d1->sfd_ino,
(unsigned long) uniqueid());
setbadness(EXIT_RECOV);
warnx("Directory %s: Duplicate names %s "
"(one renamed: %s)",
pathsofar, d2->sfd_name, d1->sfd_name);
}
dchanged = 1;
}
}
if (!strcmp(d1->sfd_name, d2->sfd_name)) {
if (d1->sfd_ino == d2->sfd_ino) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Duplicate entries for "
"%s (merged)",
pathsofar, d1->sfd_name);
d1->sfd_ino = SFS_NOINO;
d1->sfd_name[0] = 0;
} else {
/* XXX: what if FSCK.n.m already exists? */
snprintf(d1->sfd_name, sizeof(d1->sfd_name), "FSCK.%lu.%lu",
(unsigned long)d1->sfd_ino, (unsigned long)uniqueid());
setbadness(EXIT_RECOV);
warnx("Directory %s: Duplicate names %s "
"(one renamed: %s)",
pathsofar, d2->sfd_name, d1->sfd_name);
}
dchanged = 1;
}
}
/*
* Look for the . and .. entries.
*/
/*
* Look for the . and .. entries.
*/
for (i=0; i<ndirentries; i++) {
if (!strcmp(direntries[i].sfd_name, ".")) {
if (direntries[i].sfd_ino != ino) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Incorrect `.' entry "
"(fixed)", pathsofar);
direntries[i].sfd_ino = ino;
dchanged = 1;
}
/* duplicates are checked above -> only one . here */
assert(dotseen==0);
dotseen = 1;
}
else if (!strcmp(direntries[i].sfd_name, "..")) {
if (direntries[i].sfd_ino != parentino) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Incorrect `..' entry "
"(fixed)", pathsofar);
direntries[i].sfd_ino = parentino;
dchanged = 1;
}
/* duplicates are checked above -> only one .. here */
assert(dotdotseen==0);
dotdotseen = 1;
}
}
for (i = 0; i < ndirentries; i++) {
if (!strcmp(direntries[i].sfd_name, ".")) {
if (direntries[i].sfd_ino != ino) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Incorrect `.' entry "
"(fixed)",
pathsofar);
direntries[i].sfd_ino = ino;
dchanged = 1;
}
/* duplicates are checked above -> only one . here */
assert(dotseen == 0);
dotseen = 1;
} else if (!strcmp(direntries[i].sfd_name, "..")) {
if (direntries[i].sfd_ino != parentino) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Incorrect `..' entry "
"(fixed)",
pathsofar);
direntries[i].sfd_ino = parentino;
dchanged = 1;
}
/* duplicates are checked above -> only one .. here */
assert(dotdotseen == 0);
dotdotseen = 1;
}
}
/*
* If no . entry, try to insert one.
*/
/*
* If no . entry, try to insert one.
*/
if (!dotseen) {
if (sfsdir_tryadd(direntries, ndirentries, ".", ino)==0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `.' entry (added)",
pathsofar);
dchanged = 1;
}
else if (sfsdir_tryadd(direntries, maxdirentries, ".",
ino)==0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `.' entry (added)",
pathsofar);
ndirentries++;
dchanged = 1;
sfi.sfi_size += sizeof(struct sfs_direntry);
ichanged = 1;
}
else {
setbadness(EXIT_UNRECOV);
warnx("Directory %s: No `.' entry (NOT FIXED)",
pathsofar);
}
}
if (!dotseen) {
if (sfsdir_tryadd(direntries, ndirentries, ".", ino) == 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `.' entry (added)", pathsofar);
dchanged = 1;
} else if (sfsdir_tryadd(direntries, maxdirentries, ".", ino) == 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `.' entry (added)", pathsofar);
ndirentries++;
dchanged = 1;
sfi.sfi_size += sizeof(struct sfs_direntry);
ichanged = 1;
} else {
setbadness(EXIT_UNRECOV);
warnx("Directory %s: No `.' entry (NOT FIXED)", pathsofar);
}
}
/*
* If no .. entry, try to insert one.
*/
/*
* If no .. entry, try to insert one.
*/
if (!dotdotseen) {
if (sfsdir_tryadd(direntries, ndirentries, "..",
parentino)==0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `..' entry (added)",
pathsofar);
dchanged = 1;
}
else if (sfsdir_tryadd(direntries, maxdirentries, "..",
parentino)==0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `..' entry (added)",
pathsofar);
ndirentries++;
dchanged = 1;
sfi.sfi_size += sizeof(struct sfs_direntry);
ichanged = 1;
}
else {
setbadness(EXIT_UNRECOV);
warnx("Directory %s: No `..' entry (NOT FIXED)",
pathsofar);
}
}
if (!dotdotseen) {
if (sfsdir_tryadd(direntries, ndirentries, "..", parentino) == 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `..' entry (added)", pathsofar);
dchanged = 1;
} else if (sfsdir_tryadd(direntries, maxdirentries, "..", parentino) == 0) {
setbadness(EXIT_RECOV);
warnx("Directory %s: No `..' entry (added)", pathsofar);
ndirentries++;
dchanged = 1;
sfi.sfi_size += sizeof(struct sfs_direntry);
ichanged = 1;
} else {
setbadness(EXIT_UNRECOV);
warnx("Directory %s: No `..' entry (NOT FIXED)", pathsofar);
}
}
/*
* Now load each inode in the directory.
*
* For regular files, count the number of links we see; for
* directories, recurse. Count the number of subdirs seen
* so we can correct our own link count if necessary.
*/
/*
* Now load each inode in the directory.
*
* For regular files, count the number of links we see; for
* directories, recurse. Count the number of subdirs seen
* so we can correct our own link count if necessary.
*/
subdircount=0;
for (i=0; i<ndirentries; i++) {
if (direntries[i].sfd_ino == SFS_NOINO) {
/* nothing */
}
else if (!strcmp(direntries[i].sfd_name, ".")) {
/* nothing */
}
else if (!strcmp(direntries[i].sfd_name, "..")) {
/* nothing */
}
else {
char path[strlen(pathsofar)+SFS_NAMELEN+1];
struct sfs_dinode subsfi;
subdircount = 0;
for (i = 0; i < ndirentries; i++) {
if (direntries[i].sfd_ino == SFS_NOINO) {
/* nothing */
} else if (!strcmp(direntries[i].sfd_name, ".")) {
/* nothing */
} else if (!strcmp(direntries[i].sfd_name, "..")) {
/* nothing */
} else {
char path[strlen(pathsofar) + SFS_NAMELEN + 1];
struct sfs_dinode subsfi;
sfs_readinode(direntries[i].sfd_ino, &subsfi);
snprintf(path, sizeof(path), "%s/%s",
pathsofar, direntries[i].sfd_name);
sfs_readinode(direntries[i].sfd_ino, &subsfi);
snprintf(path, sizeof(path), "%s/%s", pathsofar, direntries[i].sfd_name);
switch (subsfi.sfi_type) {
case SFS_TYPE_FILE:
inode_addlink(direntries[i].sfd_ino);
break;
case SFS_TYPE_DIR:
if (pass2_dir(direntries[i].sfd_ino,
ino,
path)) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Crosslink to "
"other directory (removed)",
path);
direntries[i].sfd_ino = SFS_NOINO;
direntries[i].sfd_name[0] = 0;
dchanged = 1;
}
else {
subdircount++;
}
break;
default:
setbadness(EXIT_RECOV);
warnx("Object %s: Invalid inode type %u "
"(removed)", path, subsfi.sfi_type);
direntries[i].sfd_ino = SFS_NOINO;
direntries[i].sfd_name[0] = 0;
dchanged = 1;
break;
}
}
}
switch (subsfi.sfi_type) {
case SFS_TYPE_FILE:
inode_addlink(direntries[i].sfd_ino);
break;
case SFS_TYPE_DIR:
if (pass2_dir(direntries[i].sfd_ino, ino, path)) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Crosslink to "
"other directory (removed)",
path);
direntries[i].sfd_ino = SFS_NOINO;
direntries[i].sfd_name[0] = 0;
dchanged = 1;
} else {
subdircount++;
}
break;
default:
setbadness(EXIT_RECOV);
warnx("Object %s: Invalid inode type %u "
"(removed)",
path, subsfi.sfi_type);
direntries[i].sfd_ino = SFS_NOINO;
direntries[i].sfd_name[0] = 0;
dchanged = 1;
break;
}
}
}
/*
* Fix up the link count if needed.
*/
/*
* Fix up the link count if needed.
*/
if (sfi.sfi_linkcount != subdircount+2) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Link count %lu should be %lu (fixed)",
pathsofar, (unsigned long) sfi.sfi_linkcount,
(unsigned long) subdircount+2);
sfi.sfi_linkcount = subdircount+2;
ichanged = 1;
}
if (sfi.sfi_linkcount != subdircount + 2) {
setbadness(EXIT_RECOV);
warnx("Directory %s: Link count %lu should be %lu (fixed)", pathsofar,
(unsigned long)sfi.sfi_linkcount, (unsigned long)subdircount + 2);
sfi.sfi_linkcount = subdircount + 2;
ichanged = 1;
}
/*
* Write back anything that changed, clean up, and return.
*/
/*
* Write back anything that changed, clean up, and return.
*/
if (dchanged) {
sfs_writedir(&sfi, direntries, ndirentries);
}
if (dchanged) {
sfs_writedir(&sfi, direntries, ndirentries);
}
if (ichanged) {
sfs_writeinode(ino, &sfi);
}
if (ichanged) {
sfs_writeinode(ino, &sfi);
}
free(direntries);
free(sortvector);
free(direntries);
free(sortvector);
return 0;
return 0;
}
void
pass2(void)
{
char path[SFS_VOLNAME_SIZE + 2];
void pass2(void) {
char path[SFS_VOLNAME_SIZE + 2];
snprintf(path, sizeof(path), "%s:", sb_volname());
pass2_dir(SFS_ROOTDIR_INO, SFS_ROOTDIR_INO, path);
snprintf(path, sizeof(path), "%s:", sb_volname());
pass2_dir(SFS_ROOTDIR_INO, SFS_ROOTDIR_INO, path);
}

View File

@@ -27,8 +27,8 @@
* SUCH DAMAGE.
*/
#include <sys/types.h> /* for CHAR_BIT */
#include <limits.h> /* also for CHAR_BIT */
#include <sys/types.h> /* for CHAR_BIT */
#include <limits.h> /* also for CHAR_BIT */
#include <stdint.h>
#include <assert.h>
#include <err.h>
@@ -47,78 +47,62 @@ static struct sfs_superblock sb;
/*
* Load the superblock.
*/
void
sb_load(void)
{
sfs_readsb(SFS_SUPER_BLOCK, &sb);
if (sb.sb_magic != SFS_MAGIC) {
errx(EXIT_FATAL, "Not an sfs filesystem");
}
void sb_load(void) {
sfs_readsb(SFS_SUPER_BLOCK, &sb);
if (sb.sb_magic != SFS_MAGIC) {
errx(EXIT_FATAL, "Not an sfs filesystem");
}
assert(sb.sb_nblocks > 0);
assert(SFS_FREEMAPBLOCKS(sb.sb_nblocks) > 0);
assert(sb.sb_nblocks > 0);
assert(SFS_FREEMAPBLOCKS(sb.sb_nblocks) > 0);
}
/*
* Validate the superblock.
*/
void
sb_check(void)
{
int schanged=0;
void sb_check(void) {
int schanged = 0;
/*
* FUTURE: should we check sb.sb_nblocks against diskblocks()?
*/
/*
* FUTURE: should we check sb.sb_nblocks against diskblocks()?
*/
/* Check the superblock fields */
/* Check the superblock fields */
if (checknullstring(sb.sb_volname, sizeof(sb.sb_volname))) {
warnx("Volume name not null-terminated (fixed)");
setbadness(EXIT_RECOV);
schanged = 1;
}
if (checkbadstring(sb.sb_volname)) {
warnx("Volume name contains illegal characters (fixed)");
setbadness(EXIT_RECOV);
schanged = 1;
}
if (checkzeroed(sb.reserved, sizeof(sb.reserved))) {
warnx("Reserved section of superblock not zeroed (fixed)");
setbadness(EXIT_RECOV);
schanged = 1;
}
if (checknullstring(sb.sb_volname, sizeof(sb.sb_volname))) {
warnx("Volume name not null-terminated (fixed)");
setbadness(EXIT_RECOV);
schanged = 1;
}
if (checkbadstring(sb.sb_volname)) {
warnx("Volume name contains illegal characters (fixed)");
setbadness(EXIT_RECOV);
schanged = 1;
}
if (checkzeroed(sb.reserved, sizeof(sb.reserved))) {
warnx("Reserved section of superblock not zeroed (fixed)");
setbadness(EXIT_RECOV);
schanged = 1;
}
/* Write the superblock back if necessary */
if (schanged) {
sfs_writesb(SFS_SUPER_BLOCK, &sb);
}
/* Write the superblock back if necessary */
if (schanged) {
sfs_writesb(SFS_SUPER_BLOCK, &sb);
}
}
/*
* Return the total number of blocks in the volume.
*/
uint32_t
sb_totalblocks(void)
{
return sb.sb_nblocks;
}
uint32_t sb_totalblocks(void) { return sb.sb_nblocks; }
/*
* Return the number of freemap blocks.
* (this function probably ought to go away)
*/
uint32_t
sb_freemapblocks(void)
{
return SFS_FREEMAPBLOCKS(sb.sb_nblocks);
}
uint32_t sb_freemapblocks(void) { return SFS_FREEMAPBLOCKS(sb.sb_nblocks); }
/*
* Return the volume name.
*/
const char *
sb_volname(void)
{
return sb.sb_volname;
}
const char *sb_volname(void) { return sb.sb_volname; }

View File

@@ -45,75 +45,58 @@
////////////////////////////////////////////////////////////
// global setup
void
sfs_setup(void)
{
assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
void sfs_setup(void) {
assert(sizeof(struct sfs_superblock) == SFS_BLOCKSIZE);
assert(sizeof(struct sfs_dinode) == SFS_BLOCKSIZE);
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
}
////////////////////////////////////////////////////////////
// byte-swap functions
static
void
swapsb(struct sfs_superblock *sb)
{
sb->sb_magic = SWAP32(sb->sb_magic);
sb->sb_nblocks = SWAP32(sb->sb_nblocks);
static void swapsb(struct sfs_superblock *sb) {
sb->sb_magic = SWAP32(sb->sb_magic);
sb->sb_nblocks = SWAP32(sb->sb_nblocks);
}
static
void
swapbits(uint8_t *bits)
{
/* nothing to do */
(void)bits;
static void swapbits(uint8_t *bits) {
/* nothing to do */
(void)bits;
}
static
void
swapinode(struct sfs_dinode *sfi)
{
int i;
static void swapinode(struct sfs_dinode *sfi) {
int i;
sfi->sfi_size = SWAP32(sfi->sfi_size);
sfi->sfi_type = SWAP16(sfi->sfi_type);
sfi->sfi_linkcount = SWAP16(sfi->sfi_linkcount);
sfi->sfi_size = SWAP32(sfi->sfi_size);
sfi->sfi_type = SWAP16(sfi->sfi_type);
sfi->sfi_linkcount = SWAP16(sfi->sfi_linkcount);
for (i=0; i<NUM_D; i++) {
SET_D(sfi, i) = SWAP32(GET_D(sfi, i));
}
for (i = 0; i < NUM_D; i++) {
SET_D(sfi, i) = SWAP32(GET_D(sfi, i));
}
for (i=0; i<NUM_I; i++) {
SET_I(sfi, i) = SWAP32(GET_I(sfi, i));
}
for (i = 0; i < NUM_I; i++) {
SET_I(sfi, i) = SWAP32(GET_I(sfi, i));
}
for (i=0; i<NUM_II; i++) {
SET_II(sfi, i) = SWAP32(GET_II(sfi, i));
}
for (i = 0; i < NUM_II; i++) {
SET_II(sfi, i) = SWAP32(GET_II(sfi, i));
}
for (i=0; i<NUM_III; i++) {
SET_III(sfi, i) = SWAP32(GET_III(sfi, i));
}
for (i = 0; i < NUM_III; i++) {
SET_III(sfi, i) = SWAP32(GET_III(sfi, i));
}
}
static
void
swapdir(struct sfs_direntry *sfd)
{
sfd->sfd_ino = SWAP32(sfd->sfd_ino);
static void swapdir(struct sfs_direntry *sfd) {
sfd->sfd_ino = SWAP32(sfd->sfd_ino);
}
static
void
swapindir(uint32_t *entries)
{
int i;
for (i=0; i<SFS_DBPERIDB; i++) {
entries[i] = SWAP32(entries[i]);
}
static void swapindir(uint32_t *entries) {
int i;
for (i = 0; i < SFS_DBPERIDB; i++) {
entries[i] = SWAP32(entries[i]);
}
}
////////////////////////////////////////////////////////////
@@ -128,28 +111,24 @@ swapindir(uint32_t *entries)
* singly-indirect block this is 1. For a multiply-indirect block,
* it is more than 1; in this case recurse.
*/
static
uint32_t
ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize)
{
uint32_t entries[SFS_DBPERIDB];
static uint32_t ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize) {
uint32_t entries[SFS_DBPERIDB];
if (iblock == 0) {
return 0;
}
if (iblock == 0) {
return 0;
}
diskread(entries, iblock);
swapindir(entries);
diskread(entries, iblock);
swapindir(entries);
if (entrysize > 1) {
uint32_t index = offset / entrysize;
offset %= entrysize;
return ibmap(entries[index], offset, entrysize/SFS_DBPERIDB);
}
else {
assert(offset < SFS_DBPERIDB);
return entries[offset];
}
if (entrysize > 1) {
uint32_t index = offset / entrysize;
offset %= entrysize;
return ibmap(entries[index], offset, entrysize / SFS_DBPERIDB);
} else {
assert(offset < SFS_DBPERIDB);
return entries[offset];
}
}
/*
@@ -157,31 +136,25 @@ ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize)
*
* Given an inode and a file block, returns a disk block.
*/
static
uint32_t
bmap(const struct sfs_dinode *sfi, uint32_t fileblock)
{
uint32_t iblock, offset;
static uint32_t bmap(const struct sfs_dinode *sfi, uint32_t fileblock) {
uint32_t iblock, offset;
if (fileblock < INOMAX_D) {
return GET_D(sfi, fileblock);
}
else if (fileblock < INOMAX_I) {
iblock = (fileblock - INOMAX_D) / RANGE_I;
offset = (fileblock - INOMAX_D) % RANGE_I;
return ibmap(GET_I(sfi, iblock), offset, RANGE_D);
}
else if (fileblock < INOMAX_II) {
iblock = (fileblock - INOMAX_I) / RANGE_II;
offset = (fileblock - INOMAX_I) % RANGE_II;
return ibmap(GET_II(sfi, iblock), offset, RANGE_I);
}
else if (fileblock < INOMAX_III) {
iblock = (fileblock - INOMAX_II) / RANGE_III;
offset = (fileblock - INOMAX_II) % RANGE_III;
return ibmap(GET_III(sfi, iblock), offset, RANGE_II);
}
return 0;
if (fileblock < INOMAX_D) {
return GET_D(sfi, fileblock);
} else if (fileblock < INOMAX_I) {
iblock = (fileblock - INOMAX_D) / RANGE_I;
offset = (fileblock - INOMAX_D) % RANGE_I;
return ibmap(GET_I(sfi, iblock), offset, RANGE_D);
} else if (fileblock < INOMAX_II) {
iblock = (fileblock - INOMAX_I) / RANGE_II;
offset = (fileblock - INOMAX_I) % RANGE_II;
return ibmap(GET_II(sfi, iblock), offset, RANGE_I);
} else if (fileblock < INOMAX_III) {
iblock = (fileblock - INOMAX_II) / RANGE_III;
offset = (fileblock - INOMAX_II) % RANGE_III;
return ibmap(GET_III(sfi, iblock), offset, RANGE_II);
}
return 0;
}
////////////////////////////////////////////////////////////
@@ -191,19 +164,15 @@ bmap(const struct sfs_dinode *sfi, uint32_t fileblock)
* superblock - blocknum is a disk block number.
*/
void
sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb)
{
diskread(sb, blocknum);
swapsb(sb);
void sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb) {
diskread(sb, blocknum);
swapsb(sb);
}
void
sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb)
{
swapsb(sb);
diskwrite(sb, blocknum);
swapsb(sb);
void sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb) {
swapsb(sb);
diskwrite(sb, blocknum);
swapsb(sb);
}
/*
@@ -211,57 +180,45 @@ sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb)
* bitmap.
*/
void
sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits)
{
diskread(bits, SFS_FREEMAP_START + whichblock);
swapbits(bits);
void sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits) {
diskread(bits, SFS_FREEMAP_START + whichblock);
swapbits(bits);
}
void
sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits)
{
swapbits(bits);
diskwrite(bits, SFS_FREEMAP_START + whichblock);
swapbits(bits);
void sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits) {
swapbits(bits);
diskwrite(bits, SFS_FREEMAP_START + whichblock);
swapbits(bits);
}
/*
* inodes - ino is an inode number, which is a disk block number.
*/
void
sfs_readinode(uint32_t ino, struct sfs_dinode *sfi)
{
diskread(sfi, ino);
swapinode(sfi);
void sfs_readinode(uint32_t ino, struct sfs_dinode *sfi) {
diskread(sfi, ino);
swapinode(sfi);
}
void
sfs_writeinode(uint32_t ino, struct sfs_dinode *sfi)
{
swapinode(sfi);
diskwrite(sfi, ino);
swapinode(sfi);
void sfs_writeinode(uint32_t ino, struct sfs_dinode *sfi) {
swapinode(sfi);
diskwrite(sfi, ino);
swapinode(sfi);
}
/*
* indirect blocks - blocknum is a disk block number.
*/
void
sfs_readindirect(uint32_t blocknum, uint32_t *entries)
{
diskread(entries, blocknum);
swapindir(entries);
void sfs_readindirect(uint32_t blocknum, uint32_t *entries) {
diskread(entries, blocknum);
swapindir(entries);
}
void
sfs_writeindirect(uint32_t blocknum, uint32_t *entries)
{
swapindir(entries);
diskwrite(entries, blocknum);
swapindir(entries);
void sfs_writeindirect(uint32_t blocknum, uint32_t *entries) {
swapindir(entries);
diskwrite(entries, blocknum);
swapindir(entries);
}
////////////////////////////////////////////////////////////
@@ -270,23 +227,19 @@ sfs_writeindirect(uint32_t blocknum, uint32_t *entries)
/*
* Read the directory block at DISKBLOCK into D.
*/
static
void
sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock)
{
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
unsigned j;
static void sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock) {
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
unsigned j;
if (diskblock != 0) {
diskread(d, diskblock);
for (j=0; j<atonce; j++) {
swapdir(&d[j]);
}
}
else {
warnx("Warning: sparse directory found");
bzero(d, SFS_BLOCKSIZE);
}
if (diskblock != 0) {
diskread(d, diskblock);
for (j = 0; j < atonce; j++) {
swapdir(&d[j]);
}
} else {
warnx("Warning: sparse directory found");
bzero(d, SFS_BLOCKSIZE);
}
}
/*
@@ -294,64 +247,56 @@ sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock)
* with ND slots. The caller is assumed to have figured out the right
* number of slots.
*/
void
sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd)
{
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
unsigned i, j;
unsigned left, thismany;
struct sfs_direntry buffer[atonce];
uint32_t diskblock;
void sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd) {
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
unsigned i, j;
unsigned left, thismany;
struct sfs_direntry buffer[atonce];
uint32_t diskblock;
left = nd;
for (i=0; i<nblocks; i++) {
diskblock = bmap(sfi, i);
if (left < atonce) {
thismany = left;
sfs_readdirblock(buffer, diskblock);
for (j=0; j<thismany; j++) {
d[i*atonce + j] = buffer[j];
}
}
else {
thismany = atonce;
sfs_readdirblock(d + i*atonce, diskblock);
}
left -= thismany;
}
assert(left == 0);
left = nd;
for (i = 0; i < nblocks; i++) {
diskblock = bmap(sfi, i);
if (left < atonce) {
thismany = left;
sfs_readdirblock(buffer, diskblock);
for (j = 0; j < thismany; j++) {
d[i * atonce + j] = buffer[j];
}
} else {
thismany = atonce;
sfs_readdirblock(d + i * atonce, diskblock);
}
left -= thismany;
}
assert(left == 0);
}
/*
* Write the directory block D to DISKBLOCK.
*/
static
void
sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock)
{
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
unsigned j, bad;
static void sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock) {
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
unsigned j, bad;
if (diskblock != 0) {
for (j=0; j<atonce; j++) {
swapdir(&d[j]);
}
diskwrite(d, diskblock);
}
else {
for (j=bad=0; j<atonce; j++) {
if (d[j].sfd_ino != SFS_NOINO ||
d[j].sfd_name[0] != 0) {
bad = 1;
}
}
if (bad) {
warnx("Cannot write to missing block in "
"sparse directory (ERROR)");
setbadness(EXIT_UNRECOV);
}
}
if (diskblock != 0) {
for (j = 0; j < atonce; j++) {
swapdir(&d[j]);
}
diskwrite(d, diskblock);
} else {
for (j = bad = 0; j < atonce; j++) {
if (d[j].sfd_ino != SFS_NOINO || d[j].sfd_name[0] != 0) {
bad = 1;
}
}
if (bad) {
warnx("Cannot write to missing block in "
"sparse directory (ERROR)");
setbadness(EXIT_UNRECOV);
}
}
}
/*
@@ -359,36 +304,34 @@ sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock)
* buffer with ND slots. The caller is assumed to have set the inode
* size accordingly.
*/
void
sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd)
{
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
unsigned i, j;
unsigned left, thismany;
struct sfs_direntry buffer[atonce];
uint32_t diskblock;
void sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d,
unsigned nd) {
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
unsigned i, j;
unsigned left, thismany;
struct sfs_direntry buffer[atonce];
uint32_t diskblock;
left = nd;
for (i=0; i<nblocks; i++) {
diskblock = bmap(sfi, i);
if (left < atonce) {
thismany = left;
for (j=0; j<thismany; j++) {
buffer[j] = d[i*atonce + j];
}
for (; j<atonce; j++) {
memset(&buffer[j], 0, sizeof(buffer[j]));
}
sfs_writedirblock(buffer, diskblock);
}
else {
thismany = atonce;
sfs_writedirblock(d + i*atonce, diskblock);
}
left -= thismany;
}
assert(left == 0);
left = nd;
for (i = 0; i < nblocks; i++) {
diskblock = bmap(sfi, i);
if (left < atonce) {
thismany = left;
for (j = 0; j < thismany; j++) {
buffer[j] = d[i * atonce + j];
}
for (; j < atonce; j++) {
memset(&buffer[j], 0, sizeof(buffer[j]));
}
sfs_writedirblock(buffer, diskblock);
} else {
thismany = atonce;
sfs_writedirblock(d + i * atonce, diskblock);
}
left -= thismany;
}
assert(left == 0);
}
////////////////////////////////////////////////////////////
@@ -401,27 +344,24 @@ static struct sfs_direntry *global_sortdirs;
* Compare function for the permutation vector produced by
* sfsdir_sort().
*/
static
int
dirsortfunc(const void *aa, const void *bb)
{
const int *a = (const int *)aa;
const int *b = (const int *)bb;
const struct sfs_direntry *ad = &global_sortdirs[*a];
const struct sfs_direntry *bd = &global_sortdirs[*b];
static int dirsortfunc(const void *aa, const void *bb) {
const int *a = (const int *)aa;
const int *b = (const int *)bb;
const struct sfs_direntry *ad = &global_sortdirs[*a];
const struct sfs_direntry *bd = &global_sortdirs[*b];
/* Sort unallocated entries last */
if (ad->sfd_ino == SFS_NOINO && bd->sfd_ino == SFS_NOINO) {
return 0;
}
if (ad->sfd_ino == SFS_NOINO) {
return 1;
}
if (bd->sfd_ino == SFS_NOINO) {
return -1;
}
/* Sort unallocated entries last */
if (ad->sfd_ino == SFS_NOINO && bd->sfd_ino == SFS_NOINO) {
return 0;
}
if (ad->sfd_ino == SFS_NOINO) {
return 1;
}
if (bd->sfd_ino == SFS_NOINO) {
return -1;
}
return strcmp(ad->sfd_name, bd->sfd_name);
return strcmp(ad->sfd_name, bd->sfd_name);
}
/*
@@ -429,17 +369,15 @@ dirsortfunc(const void *aa, const void *bb)
* permutation vector into VECTOR, which should be allocated to hold
* ND ints.
*/
void
sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector)
{
unsigned i;
void sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector) {
unsigned i;
for (i=0; i<nd; i++) {
vector[i] = i;
}
for (i = 0; i < nd; i++) {
vector[i] = i;
}
global_sortdirs = d;
qsort(vector, nd, sizeof(int), dirsortfunc);
global_sortdirs = d;
qsort(vector, nd, sizeof(int), dirsortfunc);
}
/*
@@ -448,17 +386,16 @@ sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector)
*
* Returns 0 on success and nonzero on failure.
*/
int
sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name, uint32_t ino)
{
int i;
for (i=0; i<nd; i++) {
if (d[i].sfd_ino==SFS_NOINO) {
d[i].sfd_ino = ino;
assert(strlen(name) < sizeof(d[i].sfd_name));
strcpy(d[i].sfd_name, name);
return 0;
}
}
return -1;
int sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name,
uint32_t ino) {
int i;
for (i = 0; i < nd; i++) {
if (d[i].sfd_ino == SFS_NOINO) {
d[i].sfd_ino = ino;
assert(strlen(name) < sizeof(d[i].sfd_name));
strcpy(d[i].sfd_name, name);
return 0;
}
}
return -1;
}

View File

@@ -67,15 +67,14 @@ void sfs_writeindirect(uint32_t blocknum, uint32_t *entries);
/* directory - ND should be the number of directory entries D points to */
void sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd);
void sfs_writedir(const struct sfs_dinode *sfi,
struct sfs_direntry *d, unsigned nd);
void sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d,
unsigned nd);
/* Try to add an entry to a directory. */
int sfsdir_tryadd(struct sfs_direntry *d, int nd,
const char *name, uint32_t ino);
int sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name,
uint32_t ino);
/* Sort a directory by creating a permutation vector. */
void sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector);
#endif /* SFS_H */

View File

@@ -39,106 +39,94 @@
/*
* Wrapper around malloc.
*/
void *
domalloc(size_t len)
{
void *x;
x = malloc(len);
if (x==NULL) {
errx(EXIT_FATAL, "Out of memory");
}
return x;
void *domalloc(size_t len) {
void *x;
x = malloc(len);
if (x == NULL) {
errx(EXIT_FATAL, "Out of memory");
}
return x;
}
/*
* Wrapper around realloc. OSZ is the old block size, which we need if
* we're going to emulate realloc with malloc.
*/
void *
dorealloc(void *op, size_t osz, size_t nsz)
{
void *np;
void *dorealloc(void *op, size_t osz, size_t nsz) {
void *np;
#ifdef NO_REALLOC
size_t copysz;
size_t copysz;
np = domalloc(nsz);
if (op != NULL) {
copysz = osz < nsz ? osz : nsz;
memcpy(np, op, copysz);
free(op);
}
np = domalloc(nsz);
if (op != NULL) {
copysz = osz < nsz ? osz : nsz;
memcpy(np, op, copysz);
free(op);
}
#else
(void)osz;
np = realloc(op, nsz);
if (np == NULL) {
errx(EXIT_FATAL, "Out of memory");
}
(void)osz;
np = realloc(op, nsz);
if (np == NULL) {
errx(EXIT_FATAL, "Out of memory");
}
#endif
return np;
return np;
}
/*
* Get a unique id number. (unique as in for this run of sfsck...)
*/
uint32_t
uniqueid(void)
{
static uint32_t uniquecounter;
uint32_t uniqueid(void) {
static uint32_t uniquecounter;
return uniquecounter++;
return uniquecounter++;
}
/*
* Check if BUF, a string field of length MAXLEN, contains a null
* terminator. If not, slam one in and return 1.
*/
int
checknullstring(char *buf, size_t maxlen)
{
size_t i;
for (i=0; i<maxlen; i++) {
if (buf[i]==0) {
return 0;
}
}
buf[maxlen-1] = 0;
return 1;
int checknullstring(char *buf, size_t maxlen) {
size_t i;
for (i = 0; i < maxlen; i++) {
if (buf[i] == 0) {
return 0;
}
}
buf[maxlen - 1] = 0;
return 1;
}
/*
* Check if BUF contains characters not allowed in file and volume
* names. If so, stomp them and return 1.
*/
int
checkbadstring(char *buf)
{
size_t i;
int rv = 0;
int checkbadstring(char *buf) {
size_t i;
int rv = 0;
for (i=0; buf[i]; i++) {
if (buf[i]==':' || buf[i]=='/') {
buf[i] = '_';
rv = 1;
}
}
return rv;
for (i = 0; buf[i]; i++) {
if (buf[i] == ':' || buf[i] == '/') {
buf[i] = '_';
rv = 1;
}
}
return rv;
}
/*
* Check if BUF, of size LEN, is zeroed. If not, zero it and return 1.
*/
int
checkzeroed(void *vbuf, size_t len)
{
char *buf = vbuf;
size_t i;
int rv = 0;
int checkzeroed(void *vbuf, size_t len) {
char *buf = vbuf;
size_t i;
int rv = 0;
for (i=0; i < len; i++) {
if (buf[i] != 0) {
buf[i] = 0;
rv = 1;
}
}
return rv;
for (i = 0; i < len; i++) {
if (buf[i] != 0) {
buf[i] = 0;
rv = 1;
}
}
return rv;
}

View File

@@ -30,8 +30,8 @@
#ifndef UTILS_H
#define UTILS_H
#include <sys/types.h> /* for size_t */
#include <stdint.h> /* for uint32_t */
#include <sys/types.h> /* for size_t */
#include <stdint.h> /* for uint32_t */
/* non-failing wrapper around malloc */
void *domalloc(size_t len);