OpenBSD-4.6/usr.sbin/afs/src/arlad/afsdir_check.c
/*
* Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Check a directory in afs format.
*/
#include "arla_local.h"
#include <getarg.h>
RCSID("$arla: afsdir_check.c,v 1.25 2002/07/24 05:57:41 lha Exp $");
static int help_flag;
static int verbose = 0;
/*
* Hash the filename of one entry.
*/
static unsigned
hashentry (const char *entry)
{
int s = 0, h;
while (*entry)
s = s * 173 + *entry++;
h = s & (ADIRHASHSIZE - 1);
if (h == 0)
return h;
else if( s < 0 )
h = ADIRHASHSIZE - h;
return h;
}
/*
* Return the entry in the directory given the number.
* The directory must be contiounsly in memory after page0.
*/
static const DirEntry *
getentry (DirPage0 *page0,
unsigned short num)
{
DirPage1 *page;
page = (DirPage1 *)((char *)page0 +
AFSDIR_PAGESIZE * (num / ENTRIESPERPAGE));
if (page->header.pg_tag != htons(AFSDIRMAGIC)) {
printf ("Bad magic (%d) != %d in directory\n",
ntohs(page->header.pg_tag), AFSDIRMAGIC);
exit (1);
}
return &page->entry[num % ENTRIESPERPAGE];
}
static int
check_dir (const char *filename)
{
struct stat statbuf;
int fd;
fbuf the_fbuf;
DirPage0 *page0;
unsigned i, j;
unsigned ind;
unsigned len;
int ret = 0;
unsigned npages = 0;
unsigned page_entry_count;
unsigned hash_entry_count;
unsigned noverfill;
uint8_t **my_bitmaps = NULL;
fd = open (filename, O_RDONLY | O_BINARY, 0);
if (fd < 0)
err (1, "open %s", filename);
if (fstat (fd, &statbuf) < 0)
err (1, "stat %s", filename);
len = statbuf.st_size;
if (len == 0)
errx (1, "length == 0");
if (len % AFSDIR_PAGESIZE != 0)
errx (1, "length %% AFSDIR_PAGESIZE != 0");
ret = fbuf_create (&the_fbuf, fd, len, FBUF_READ|FBUF_PRIVATE);
if (ret)
err (1, "fbuf_create");
page0 = (DirPage0 *)(the_fbuf.buf);
printf ("size = %u, pages = %u, pgcount = %u\n",
len, len / AFSDIR_PAGESIZE,
ntohs(page0->header.pg_pgcount));
if (len / AFSDIR_PAGESIZE != ntohs(page0->header.pg_pgcount)) {
ret = 1;
goto out;
}
npages = len / AFSDIR_PAGESIZE;
my_bitmaps = malloc (npages * sizeof(*my_bitmaps));
if (my_bitmaps == NULL)
err (1, "malloc %lu", (unsigned long)npages * sizeof(*my_bitmaps));
printf ("map: ");
for (i = 0; i < min(npages, MAXPAGES); ++i) {
printf ("%u ", page0->dheader.map[i]);
}
printf ("\n");
page_entry_count = 0;
for (i = 0; i < npages; ++i) {
PageHeader *ph = (PageHeader *)((char *)page0 + i * AFSDIR_PAGESIZE);
int start;
size_t sz = ENTRIESPERPAGE / 8 * sizeof(*my_bitmaps[i]);
my_bitmaps[i] = malloc (sz);
if (my_bitmaps[i] == NULL)
err (1, "malloc %lu", (unsigned long)sz);
memset (my_bitmaps[i], 0, sz);
if (ph->pg_tag != htons(AFSDIRMAGIC)) {
printf ("page %d: wrong tag: %u\n", i, htons(ph->pg_tag));
ret = 1;
goto out;
}
printf ("page %d: count = %u, tag = %u, freecount = %u\n",
i, ntohs(ph->pg_pgcount), htons(ph->pg_tag), ph->pg_freecount);
if (i == 0) {
if (ph->pg_freecount != 51) {
printf ("freecount should be 51!\n");
ret = 1;
goto out;
}
if (ntohs(ph->pg_pgcount) != npages) {
printf ("pgcount should be %u!\n", npages);
ret = 1;
goto out;
}
} else {
if (ph->pg_freecount != 63) {
printf ("freecount should be 63!\n");
ret = 1;
goto out;
}
if (ntohs(ph->pg_pgcount) != 0) {
printf ("pgcount should be 0!\n");
ret = 1;
goto out;
}
}
if (i == 0)
start = 13;
else
start = 1;
for (j = start; j < ENTRIESPERPAGE; ++j) {
if (ph->pg_bitmap[j / 8] & (1 << (j % 8)))
++page_entry_count;
}
}
printf ("page entry count = %u\n", page_entry_count);
hash_entry_count = 0;
noverfill = 0;
for (i = 0; i < ADIRHASHSIZE; ++i) {
const DirEntry *entry;
for(ind = ntohs(page0->dheader.hash[i]);
ind;
ind = ntohs(entry->next)) {
DirPage1 *page_n;
int len;
unsigned off;
unsigned pageno;
entry = getentry (page0, ind - 1);
if (verbose)
printf ("%s - %ld.%ld\n",
entry->name,
(long)ntohl(entry->fid.Vnode),
(long)ntohl(entry->fid.Unique));
if (hashentry (entry->name) != i)
printf ("wrong name here? hash = %u, name = *%s*\n",
i, entry->name);
pageno = (ind) / ENTRIESPERPAGE;
off = (ind) % ENTRIESPERPAGE;
page_n = (DirPage1 *)((char *)page0
+ AFSDIR_PAGESIZE * pageno);
if (!(page_n->header.pg_bitmap[off / 8] & (1 << (off % 8)))) {
printf ("page %d: off %u not set\n",
(ind - 1) / ENTRIESPERPAGE, off);
}
my_bitmaps[pageno][off / 8] |= (1 << (off % 8));
len = strlen(entry->name);
while (len > 15) {
len -= sizeof(DirEntry);
++noverfill;
++off;
my_bitmaps[pageno][off / 8] |= (1 << (off % 8));
}
++hash_entry_count;
}
}
for (i = 0; i < npages; ++i) {
DirPage1 *page_n;
int j;
unsigned unused;
if (i == 0)
unused = 13;
else
unused = 1;
for (j = 0; j < unused; ++j)
my_bitmaps[i][j / 8] |= (1 << (j % 8));
page_n = (DirPage1 *)((char *)page0 + AFSDIR_PAGESIZE * i);
if (memcmp (my_bitmaps[i],
page_n->header.pg_bitmap, sizeof(my_bitmaps[i])) != 0) {
printf ("page %i: bitmaps differ\n"
"actual: ", i);
for (j = 0; j < ENTRIESPERPAGE / 8; ++j)
printf ("%02x ", page_n->header.pg_bitmap[j]);
printf ("\n"
"calculated: ");
for (j = 0; j < ENTRIESPERPAGE / 8; ++j)
printf ("%02x ", my_bitmaps[i][j]);
printf ("\n");
}
}
printf ("hash entry count = %u, noverfill = %u, sum = %u\n",
hash_entry_count, noverfill, hash_entry_count + noverfill);
if (hash_entry_count + noverfill != page_entry_count)
ret = 1;
out:
fbuf_end (&the_fbuf);
close (fd);
if (my_bitmaps) {
for (i = 0; i < npages; ++i)
free (my_bitmaps[i]);
free (my_bitmaps);
}
return ret;
}
static struct getargs args[] = {
{"verbose", 'v', arg_flag, &verbose,
"run in test mode", NULL},
{"help", 0, arg_flag, &help_flag,
NULL, NULL},
};
static void
usage (int ret)
{
arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "[file]");
exit (ret);
}
int
main(int argc, char **argv)
{
int optind = 0;
if (getarg (args, sizeof(args)/sizeof(*args), argc, argv, &optind))
usage (1);
argc -= optind;
argv += optind;
if (help_flag)
usage (0);
if (argc != 1)
usage (1);
return check_dir (argv[0]);
}