[OpenAFS] amanda-afs list
Andrej Filipcic
andrej.filipcic@ijs.si
Mon, 29 May 2006 09:24:04 +0200
--Boundary-00=_VGqeE/RZiwo4tQ3
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Hi,
I have troubles with amanda-afs indexer. There is a program "list", which
dumps a contents of an afs volume dump. For most of volumes it works ok, but
for some large volumes (10-20GB), it loops inside vnode linked list at
t->next and never returns.
(line 114)
struct vnodeData *get(Node **List)
{
Node *L = *List;
Node *t, *t1;
struct vnodeData *vdata;
if(L)
{
t = L;
t1 = NULL;
while(t->next)
{
t1 = t;
t = t->next;
}
Could someone take a look at where the problem might be? I am using
openafs-1.4.1. There is no problems with vos dump of the volume and vos
restore.
Thanks,
Andrej
--
_____________________________________________________________
doc. dr. Andrej Filipcic, E-mail: Andrej.Filipcic@ijs.si
Department of Experimental High Energy Physics - F9
Jozef Stefan Institute, Jamova 39, P.o.Box 3000
SI-1001 Ljubljana, Slovenia
Tel.: +386-1-477-3674 Fax: +386-1-477-3166
-------------------------------------------------------------
--Boundary-00=_VGqeE/RZiwo4tQ3
Content-Type: text/x-csrc;
charset="us-ascii";
name="list.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="list.c"
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include <fnmatch.h>
#include <lock.h>
#include <afs/param.h>
#include <afs/afsint.h>
#include <afs/nfs.h>
#include <afs/acl.h>
#include <afs/ihandle.h>
#include <afs/vnode.h>
#include <afs/volume.h>
#include <afs/dir.h>
#include "config.h"
/*
* Sigh. Linux blows it again
*/
#ifdef linux
#include <pty.h>
#endif
/*
* Stuff that is in private AFS header files, unfortunately
*/
#define DUMPVERSION 1
#define DUMPENDMAGIC 0x3A214B6E
#define DUMPBEGINMAGIC 0xB3A11322
#define D_DUMPHEADER 1
#define D_VOLUMEHEADER 2
#define D_VNODE 3
#define D_DUMPEND 4
#define D_MAX 20
#define MAXDUMPTIMES 50
struct DumpHeader {
int32_t version;
VolumeId volumeId;
char volumeName[VNAMESIZE];
int nDumpTimes; /* Number of pairs */
struct {
int32_t from, to;
} dumpTimes[MAXDUMPTIMES];
};
/*
* Our command-line arguments
*/
static int verbose = 0;
static int numNoDirData = 0;
static int termsize = 0;
int Testing = 0;
/*
* We use this structure to hold vnode data in our hash table.
* It's indexed by vnode number.
*/
struct vnodeData {
struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
int vnodeNumber; /* The vnode number */
unsigned char *filedata; /* A pointer to the actual file
data itself (if available) */
unsigned int datalength; /* The length of the data */
};
/*
* This contains the current location when we're doing a scan of a
* directory.
*/
struct DirCursor {
int hashbucket; /* Current hash bucket */
int entry; /* Entry within hash bucket */
};
/*
* Arrays to hold vnode data
*/
typedef struct Node_val Node;
struct Node_val {
struct vnodeData *data;
Node *next;
};
void insert(Node **List, struct vnodeData *vdata)
{
Node *t;
t = (Node *) malloc(sizeof(Node));
t->data = vdata;
t->next = *List;
*List = t;
}
struct vnodeData *get(Node **List)
{
Node *L = *List;
Node *t, *t1;
struct vnodeData *vdata;
if(L)
{
t = L;
t1 = NULL;
while(t->next)
{
t1 = t;
t = t->next;
}
if(t1)
{
t1->next = NULL;
}
else
{
*List = NULL;
}
vdata = t->data;
free(t);
return vdata;
}
return NULL;
}
Node *SmList = NULL;
Node *LgList = NULL;
struct vnodeData **LargeVnodeIndex;
struct vnodeData **SmallVnodeIndex;
int numLargeVnodes = 0;
int numSmallVnodes = 0;
/*
* Crap for the libraries */
int ShutdownInProgress = 0;
/*
* Our local function prototypes
*/
static int ReadDumpHeader(FILE *, struct DumpHeader *);
static int ReadVolumeHeader(FILE *, VolumeDiskData *);
static int ScanVnodes(FILE *, VolumeDiskData *, int);
static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
static struct vnodeData *GetVnode(unsigned int);
static int CompareVnode(const void *, const void *);
static void DirListInternal(struct vnodeData *, VolumeDiskData *, char *);
static int CompareDirEntry(const void *, const void *);
static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
static char *GetToken(char *, char **, char *, char *[]);
static int ReadInt16(FILE *, uint16_t *);
static int ReadInt32(FILE *, uint32_t *);
static int ReadString(FILE *, char *, int);
static int ReadByteString(FILE *, void *, int);
int
main(int argc, char *argv[])
{
int c, errflg = 0, dumpvnodes = 0, force = 0, inode = 0;
unsigned int magic;
struct DumpHeader dheader;
VolumeDiskData vol;
long offset;
int Res, Arg1, Arg2, Arg3, i;
char *p;
char tag;
struct winsize win;
FILE *f;
struct vnodeData *rootvdata;
/*
* Sigh, this is dumb, but we need the terminal window size
* to do intelligent things with "ls" later on.
*/
while ((c = getopt(argc, argv, "hdifr:t:v")) != EOF)
switch (c) {
case 'h':
fprintf(stderr, "%s\nRun this utility as follows:\n\t%s\n", AMANDA_AFS_VERSION, argv[0]);
fprintf(stderr, "It will take its standard input, and, provided it is a vos dump, will print the contents.\n");
return 0;
break;
case 't':
fprintf(stderr, "-t not supported in non-MRAFS "
"dumptool.\n");
errflg++;
break;
case 'r':
fprintf(stderr, "-r not supported in non-MRAFS "
"dumptool.\n");
errflg++;
break;
case 'd':
fprintf(stderr, "-d not supported in non-MRAFS "
"dumptool.\n");
errflg++;
break;
case 'v':
verbose++;
break;
case 'f':
force++;
break;
case 'i':
inode++;
break;
case '?':
default:
errflg++;
}
/* if (errflg || optind == argc) {
fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
"filename\n",
argv[0]);
exit(1);
}
*/
/*
* Try opening the dump file
*/
f = stdin;
printf("/\n");
while(!feof(f))
{
if ((tag = getc(f)) == D_DUMPHEADER)
{
ungetc(tag, f);
}
else
{
break;
}
if (ReadDumpHeader(f, &dheader)) {
fprintf(stderr, "Failed to read dump header!\n");
exit(1);
}
if (verbose)
fprintf(stderr, "Dump is for volume %lu (%s)\n", dheader.volumeId,
dheader.volumeName);
if (getc(f) != D_VOLUMEHEADER) {
fprintf(stderr, "Volume header is missing from dump, aborting\n");
exit(1);
}
if (ReadVolumeHeader(f, &vol)) {
fprintf(stderr, "Unable to read volume header\n");
exit(1);
}
if (verbose) {
printf("Volume information:\n");
printf("\tid = %lu\n", vol.id);
printf("\tparent id = %lu\n", vol.parentId);
printf("\tname = %s\n", vol.name);
printf("\tflags =");
if (vol.inUse)
printf(" inUse");
if (vol.inService)
printf(" inService");
if (vol.blessed)
printf(" blessed");
if (vol.needsSalvaged)
printf(" needsSalvaged");
printf("\n");
printf("\tuniquifier = %lu\n", vol.uniquifier);
printf("\tCreation date = %s", ctime((time_t *) &vol.creationDate));
printf("\tLast access date = %s", ctime((time_t *) &vol.accessDate));
printf("\tLast update date = %s", ctime((time_t *) &vol.updateDate));
printf("\tVolume owner = %lu\n", vol.owner);
}
if (verbose)
printf("Scanning vnodes (this may take a while)\n");
/*
* We need to do two vnode scans; one to get the number of
* vnodes, the other to actually build the index.
*/
if (ScanVnodes(f, &vol, 0)) {
fprintf(stderr, "Second vnode scan failed, aborting\n");
exit(1);
}
if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) ||
magic != DUMPENDMAGIC) {
fprintf(stderr, "Couldn't find dump postamble, ");
if (! force) {
fprintf(stderr, "aborting (use -f to override)\n");
exit(1);
} else {
fprintf(stderr, "continuing anyway\n");
fprintf(stderr, "WARNING: Dump may not be complete!\n");
}
}
/*
* If we wanted to simply dump all vnodes, do it now
*/
if ((rootvdata = GetVnode(1)) == NULL) {
fprintf(stderr, "Can't get vnode data for root "
"vnode! Aborting\n");
exit(1);
}
printf("/%s/\n", vol.name);
p = (char *) malloc((strlen(vol.name)+2)*sizeof(char));
sprintf(p, "/%s", vol.name);
DirListInternal(rootvdata, &vol, p);
if(p)
free(p);
/* Now, to avoid assorted memory leaks, destroy the {Small,Large}VnodeIndex */
/* in two for loops cycle through the Indeces and destroy their entries. */
for(i = 0; i<numLargeVnodes; i++)
{
/* destroy LargeVnodeIndex[i] */
/* LargeVnodeIndex[i] is vnodeData, vnodeData has vnode. */
free(LargeVnodeIndex[i]->vnode);
LargeVnodeIndex[i]->vnode = NULL;
free(LargeVnodeIndex[i]->filedata);
LargeVnodeIndex[i]->filedata = NULL;
free(LargeVnodeIndex[i]);
LargeVnodeIndex[i] = NULL;
}
for(i = 0; i<numSmallVnodes; i++)
{
/* destroy SmallVnodeIndex[i] */
/* SmallVnodeIndex[i] is vnodeData, vnodeData has vnode. */
free(SmallVnodeIndex[i]->vnode);
SmallVnodeIndex[i]->vnode = NULL;
free(SmallVnodeIndex[i]);
SmallVnodeIndex[i] = NULL;
}
/* then destroy the indices themselves */
if(SmallVnodeIndex)
free(SmallVnodeIndex);
if(LargeVnodeIndex)
free(LargeVnodeIndex);
}
}
/*
* Read the dump header, which is at the beginning of every dump
*/
static int
ReadDumpHeader(FILE *f, struct DumpHeader *header)
{
unsigned int magic;
int tag, i;
if (getc(f) != D_DUMPHEADER ||
ReadInt32(f, &magic) || ReadInt32(f, (unsigned int *)
&header->version) ||
magic != DUMPBEGINMAGIC) {
if (verbose)
fprintf(stderr, "Couldn't find dump magic numbers\n");
return -1;
}
header->volumeId = 0;
header->nDumpTimes = 0;
while ((tag = getc(f)) > D_MAX && tag != EOF) {
unsigned short length;
switch (tag) {
case 'v':
if (ReadInt32(f, (uint32_t *)&header->volumeId)) {
if (verbose)
fprintf(stderr, "Failed to read "
"volumeId\n");
return -1;
}
break;
case 'n':
if (ReadString(f, header->volumeName,
sizeof(header->volumeName))) {
if (verbose)
fprintf(stderr, "Failed to read "
"volume name\n");
return -1;
}
break;
case 't':
if (ReadInt16(f, &length)) {
if (verbose)
fprintf(stderr, "Failed to read "
"dump time array length\n");
return -1;
}
header->nDumpTimes = (length >> 1);
for (i = 0; i < header->nDumpTimes; i++)
if (ReadInt32(f, (unsigned int *)
&header->dumpTimes[i].from) ||
ReadInt32(f, (unsigned int *)
&header->dumpTimes[i].to)) {
if (verbose)
fprintf(stderr, "Failed to "
"read dump times\n");
return -1;
}
break;
default:
if (verbose)
fprintf(stderr, "Unknown dump tag \"%c\"\n",
tag);
return -1;
}
}
if (!header->volumeId || !header->nDumpTimes) {
if (verbose)
fprintf(stderr, "We didn't get a volume Id or "
"dump times listing\n");
return 1;
}
ungetc(tag, f);
return 0;
}
/*
* Read the volume header; this is the information stored in VolumeDiskData.
*
* I'm not sure we need all of this, but read it in just in case.
*/
static int
ReadVolumeHeader(FILE *f, VolumeDiskData *vol)
{
int tag;
unsigned int trash;
memset((void *) vol, 0, sizeof(*vol));
while ((tag = getc(f)) > D_MAX && tag != EOF) {
switch (tag) {
case 'i':
if (ReadInt32(f, (uint32_t *)&vol->id))
return -1;
break;
case 'v':
if (ReadInt32(f, (uint32_t *)&trash))
return -1;
break;
case 'n':
if (ReadString(f, vol->name, sizeof(vol->name)))
return -1;
break;
case 's':
vol->inService = getc(f);
break;
case 'b':
vol->blessed = getc(f);
break;
case 'u':
if (ReadInt32(f, (uint32_t *)&vol->uniquifier))
return -1;
break;
case 't':
vol->type = getc(f);
break;
case 'p':
if (ReadInt32(f, (uint32_t *)&vol->parentId))
return -1;
break;
case 'c':
if (ReadInt32(f, (uint32_t *)&vol->cloneId))
return -1;
break;
case 'q':
if (ReadInt32(f, (uint32_t *) &vol->maxquota))
return -1;
break;
case 'm':
if (ReadInt32(f, (uint32_t *) &vol->minquota))
return -1;
break;
case 'd':
if (ReadInt32(f, (uint32_t *) &vol->diskused))
return -1;
break;
case 'f':
if (ReadInt32(f, (uint32_t *) &vol->filecount))
return -1;
break;
case 'a':
if (ReadInt32(f, (uint32_t *)&vol->accountNumber))
return -1;
break;
case 'o':
if (ReadInt32(f, (uint32_t *)&vol->owner))
return -1;
break;
case 'C':
if (ReadInt32(f, (uint32_t *)&vol->creationDate))
return -1;
break;
case 'A':
if (ReadInt32(f, (uint32_t *)&vol->accessDate))
return -1;
break;
case 'U':
if (ReadInt32(f, (uint32_t *)&vol->updateDate))
return -1;
break;
case 'E':
if (ReadInt32(f, (uint32_t *)&vol->expirationDate))
return -1;
break;
case 'B':
if (ReadInt32(f, (uint32_t *)&vol->backupDate))
return -1;
break;
case 'O':
if (ReadString(f, vol->offlineMessage,
sizeof(vol->offlineMessage)))
return -1;
break;
case 'M':
if (ReadString(f, (char *) vol->stat_reads, VMSGSIZE))
return -1;
break;
case 'W': {
unsigned short length;
int i;
unsigned int data;
if (ReadInt16(f, &length))
return -1;
for (i = 0; i < length; i++) {
if (ReadInt32(f, (uint32_t *)&data))
return -1;
if (i < sizeof(vol->weekUse) /
sizeof(vol->weekUse[0]))
vol->weekUse[i] = data;
}
break;
}
case 'D':
if (ReadInt32(f, (uint32_t *)&vol->dayUseDate))
return -1;
break;
case 'Z':
if (ReadInt32(f, (uint32_t *) &vol->dayUse))
return -1;
break;
default:
if (verbose)
fprintf(stderr, "Unknown dump tag \"%c\"\n",
tag);
return -1;
}
}
ungetc(tag, f);
return 0;
}
/*
* Scan all our vnode entries, and build indexing information.
*/
static int
ScanVnodes(FILE *f, VolumeDiskData *vol, int sizescan)
{
int vnodeNumber;
int tag;
int numFileVnodes = 0;
int numDirVnodes = 0;
unsigned char buf[SIZEOF_LARGEDISKVNODE];
struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
struct VnodeDiskObject *nvnode;
long offset, oldoffset;
struct vnodeData *vdata;
unsigned int length;
char *iobuf;
int i;
tag = getc(f);
while (tag == D_VNODE) {
offset = 0;
length = 0;
vnode->type = -1;
vnode->length = -1;
if (ReadInt32(f, (uint32_t *) &vnodeNumber))
{
fprintf(stderr, "failed int32 for 'vnodenum'\n");
return -1;
}
if (ReadInt32(f, (uint32_t *)&vnode->uniquifier))
{
fprintf(stderr, "failed int32 for 'uniquifier'\n");
return -1;
}
if (verbose > 1 && !sizescan)
printf("Got vnode %d\n", vnodeNumber);
while ((tag = getc(f)) > D_MAX && tag != EOF)
switch (tag) {
case 't':
vnode->type = (VnodeType) getc(f);
break;
case 'l':
{
unsigned short tmp;
if (ReadInt16(f, &tmp))
{
fprintf(stderr, "failed int16 for 'l'\n");
return -1;
}
vnode->linkCount = tmp;
}
break;
case 'v':
if (ReadInt32(f, (uint32_t *)&vnode->dataVersion))
{
fprintf(stderr, "failed int32 for 'v'\n");
return -1;
}
break;
case 'm':
if (ReadInt32(f, (uint32_t *) &vnode->unixModifyTime))
{
fprintf(stderr, "failed int32 for 'm'\n");
return -1;
}
break;
case 's':
if (ReadInt32(f, (uint32_t *) &vnode->serverModifyTime))
{
fprintf(stderr, "failed int32 for 's'\n");
return -1;
}
break;
case 'a':
if (ReadInt32(f, (uint32_t *)&vnode->author))
{
fprintf(stderr, "failed int32 for 'a'\n");
return -1;
}
break;
case 'o':
if (ReadInt32(f, (uint32_t *)&vnode->owner))
{
fprintf(stderr, "failed int32 for 'o'\n");
return -1;
}
break;
case 'g':
if (ReadInt32(f, (uint32_t *) &vnode->group))
{
fprintf(stderr, "failed int32 for 'g'\n");
return -1;
}
break;
case 'b': {
unsigned short modeBits;
if (ReadInt16(f, &modeBits))
return -1;
vnode->modeBits = modeBits;
break;
}
case 'p':
if (ReadInt32(f, (uint32_t *)&vnode->parent))
{
fprintf(stderr, "failed int32 for 'p'\n");
return -1;
}
break;
case 'S':
if (ReadInt32(f, (uint32_t *)&vnode->length))
{
fprintf(stderr, "failed int32 for 'S'\n");
return -1;
}
break;
case 'F':
if (ReadInt32(f, (uint32_t *) &vnode->vn_ino_lo))
return -1;
break;
case 'A':
if (ReadByteString(f,
(void *)VVnodeDiskACL(vnode),
VAclDiskSize(vnode)))
{
fprintf(stderr, "failed readbystring for 'A'\n");
return -1;
}
#if 0
acl_NtohACL(VVnodeDiskACL(vnode));
#endif
break;
case 'f':
if (verbose > 1 && ! sizescan)
printf("We have file data!\n");
if (ReadInt32(f, (uint32_t *)&length))
{
fprintf(stderr, "failed int32 for 'f'\n");
return -1;
}
vnode->length = length;
/* stuff */
if (vnode->type == -1)
break;
if (vnode->type == vDirectory)
numDirVnodes++;
else
numFileVnodes++;
nvnode = (struct VnodeDiskObject *) malloc(sizeof(struct VnodeDiskObject));
if (!nvnode) {
if (verbose)
fprintf(stderr, "Unable to allocate space for vnode\n");
return -1;
}
memcpy((void *) nvnode, (void *) vnode, sizeof(struct VnodeDiskObject));
vdata = (struct vnodeData *) malloc(sizeof(struct vnodeData));
vdata->vnode = nvnode;
vdata->vnodeNumber = vnodeNumber;
vdata->filedata = NULL;
vdata->datalength = length;
if (vnodeNumber & 1) {
insert(&LgList, vdata);
} else {
if(vdata == NULL) printf("inserting NULL!\n");
insert(&SmList, vdata);
}
if (vdata == NULL) {
if (verbose)
fprintf(stderr, "Failed to insert "
"vnode into hash table");
return -1;
}
/*
* Save directory data, since we'll need it later.
*/
if (vnode->type == vDirectory && length) {
vdata->filedata = (char *) malloc(length*sizeof(char));
if (!vdata->filedata) {
if (verbose)
fprintf(stderr, "Unable to "
"allocate space for "
"file data (%d)\n",
length);
return -1;
}
if (fread(vdata->filedata, length, 1, f) != 1) {
if (verbose)
fprintf(stderr, "Unable to "
"read in file data!\n");
return -1;
}
} else if (vnode->type == vDirectory) {
/*
* Warn the user we may not have all directory
* vnodes
*/
numNoDirData++;
} else if (length) {
if(fileseek(f, length, SEEK_CUR) == -1)
{
fprintf(stderr, "Error: could not seek the input stream!\n");
break;
}
}
/* end stuff */
break;
default:
if (verbose)
fprintf(stderr, "Unknown dump tag \"%c\"\n",
tag);
return -1;
}
}
ungetc(tag, f);
if (!sizescan) {
numLargeVnodes = numDirVnodes;
numSmallVnodes = numFileVnodes;
/* if there are directories, allocate structure for them, if not, set structure to NULL */
LargeVnodeIndex = numLargeVnodes ? (struct vnodeData **) malloc(numLargeVnodes*sizeof(struct vnodeData)) : NULL;
/* if there are files, allocate structure for them, if not, set structure to NULL */
SmallVnodeIndex = numSmallVnodes ? (struct vnodeData **) malloc(numSmallVnodes*sizeof(struct vnodeData)) : NULL;
/* check, whether memory was allocated */
if ((numLargeVnodes && LargeVnodeIndex == NULL)|| (numSmallVnodes && SmallVnodeIndex == NULL)) {
if (verbose)
fprintf(stderr, "Unable to allocate space "
"for vnode tables\n");
return -1;
}
/* copy from the {Lg,Sm}Lists into the {Large,Small}VnodeIndeces */
for(i = 0; i<numLargeVnodes; i++)
{
LargeVnodeIndex[i] = get(&LgList);
}
for(i = 0; i<numSmallVnodes; i++)
{
SmallVnodeIndex[i] = get(&SmList);
if (SmallVnodeIndex[i] == NULL) printf("D'oh!\n");
}
}
if (verbose)
fprintf(stderr,"%s vnode scan completed\n",
sizescan ? "Primary" : "Secondary");
return 0;
}
/*
* Function that does the REAL work in terms of directory listing
*/
static void
DirListInternal(struct vnodeData *vdata, VolumeDiskData *vol, char *path)
{
struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
struct DirCursor cursor;
struct vnodeData *lvdata;
int i, j, numentries = 0;
char s;
int numrecurse = 0;
if (! vdata->filedata)
{
fprintf(stderr, "There is no vnode data for this "
"directory!\n");
return;
}
ResetDirCursor(&cursor, vdata);
/*
* Scan through the whole directory
*/
while ((ep = ReadNextDir(&cursor, vdata)) != NULL)
{
/*
* If we didn't get any filenames on the command line,
* get them all.
*/
eplist = realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
eplist[numentries - 1] = ep;
if ((lvdata = GetVnode(ntohl(ep->fid.vnode))) &&
lvdata->vnode->type == vDirectory &&
!(strcmp(ep->name, ".") == 0 || strcmp(ep->name, "..") == 0))
{
eprecurse = realloc(eprecurse, sizeof(struct DirEntry *) * ++numrecurse);
eprecurse[numrecurse - 1] = ep;
}
}
/* qsort((void *) eplist, numentries, sizeof(struct DirEntry *), CompareDirEntry);
if (eprecurse)
{
qsort((void *) eprecurse, numrecurse, sizeof(struct DirEntry *), CompareDirEntry);
}
*/
for (i = 0; i < numentries; i++)
{
if(strcmp(eplist[i]->name, ".") != 0 && strcmp(eplist[i]->name, "..") != 0)
{
if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
{
printf("%s\n", eplist[i]->name);
}
else
{
if(lvdata->vnode->type == vDirectory)
if (path)
printf("%s/%s/\n", path, eplist[i]->name);
else
printf("%s/\n", eplist[i]->name);
else
if (path)
printf("%s/%s\n", path, eplist[i]->name);
else
printf("%s\n", eplist[i]->name);
}
}
}
free(eplist);
if (eprecurse)
{
char *lpath;
lpath = NULL;
for (i = 0; i < numrecurse; i++)
{
/* if (verbose)
{
printf("\n%s:\n", eprecurse[i]->name);
}
*/
if (path)
{
lpath = (char *) malloc((strlen(path) + strlen(eprecurse[i]->name) + 2)*sizeof(char));
if (lpath)
{
sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
}
}
DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), vol, lpath);
if (lpath)
{
free(lpath);
lpath = NULL;
}
}
}
if (eprecurse)
free(eprecurse);
return;
}
/*
* Directory name comparison function, used by qsort
*/
static int
CompareDirEntry(const void *e1, const void *e2)
{
struct DirEntry **ep1 = (struct DirEntry **) e1;
struct DirEntry **ep2 = (struct DirEntry **) e2;
return strcmp((*ep1)->name, (*ep2)->name);
}
/*
* Reset a structure containing the current directory scan location
*/
static void
ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
{
struct DirHeader *dhp;
cursor->hashbucket = 0;
dhp = (struct DirHeader *) vdata->filedata;
cursor->entry = ntohs(dhp->hashTable[0]);
}
/*
* Given a cursor and a directory entry, return the next entry in the
* directory.
*/
static struct DirEntry *
ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
{
struct DirHeader *dhp;
struct DirEntry *ep;
dhp = (struct DirHeader *) vdata->filedata;
if (cursor->entry) {
ep = (struct DirEntry *) (vdata->filedata +
(cursor->entry * 32));
cursor->entry = ntohs(ep->next);
return ep;
} else {
while (++(cursor->hashbucket) < NHASHENT) {
cursor->entry =
ntohs(dhp->hashTable[cursor->hashbucket]);
if (cursor->entry) {
ep = (struct DirEntry *) (vdata->filedata +
(cursor->entry * 32));
cursor->entry = ntohs(ep->next);
return ep;
}
}
}
return NULL;
}
/*
* Routine to retrieve a vnode from the hash table.
*/
static struct vnodeData *
GetVnode(unsigned int vnodeNumber)
{
struct vnodeData vnode, *vnodep, **tmp;
vnode.vnodeNumber = vnodeNumber;
vnodep = &vnode;
tmp = (struct vnodeData **)
bsearch((void *) &vnodep,
vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
sizeof(struct vnodeData *), CompareVnode);
return tmp ? *tmp : NULL;
}
/*
* Our comparator function for bsearch
*/
static int
CompareVnode(const void *node1, const void *node2)
{
struct vnodeData **vnode1 = (struct vnodeData **) node1;
struct vnodeData **vnode2 = (struct vnodeData **) node2;
if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
return 0;
else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
return 1;
else
return -1;
}
/*
* Read a 16 bit integer in network order
*/
static int
ReadInt16(FILE *f, unsigned short *s)
{
unsigned short in;
if (fread((void *)&in, sizeof(in), 1, f) != 1) {
if (verbose)
fprintf(stderr, "ReadInt16 failed!\n");
return -1;
}
*s = ntohs(in);
return 0;
}
/*
* Read a 32 bit integer in network order
*/
static int
ReadInt32(FILE *f, unsigned int *i)
{
unsigned int in;
if (fread((void *)&in, sizeof(in), 1, f) != 1) {
if (verbose)
fprintf(stderr, "ReadInt32 failed!\n");
return -1;
}
*i = ntohl((unsigned long) in);
return 0;
}
/*
* Read a string from a dump file
*/
static int
ReadString(FILE *f, char *string, int maxlen)
{
int c;
while (maxlen--) {
if ((*string++ = getc(f)) == 0)
break;
}
/*
* I'm not sure what the _hell_ this is supposed to do ...
* but it was in the original dump code
*/
if (string[-1]) {
while ((c = getc(f)) && c != EOF);
string[-1] = 0;
}
return 0;
}
static int
ReadByteString(FILE *f, void *s, int size)
{
unsigned char *c = (unsigned char *) s;
while (size--)
*c++ = getc(f);
return 0;
}
--Boundary-00=_VGqeE/RZiwo4tQ3--