1
0
Files
irix-657m-src/eoe/cmd/bsd/dump/dumpdir.c
2022-09-29 17:59:04 +03:00

120 lines
3.6 KiB
C

#ident "$Revision: 1.5 $"
/**************************************************************************
* *
* Copyright (C) 1990, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
* static char sccsid[] = "@(#)dumpdir.c 1.1 (SGI) 8/1/90"; *
**************************************************************************/
#include "dump.h"
/*
* Convert EFS directories to Sun/BSD format.
* Problem here is that EFS directories are smaller. The smallest direntry
* for EFS is 8 bytes and for BSD is 12 bytes. So the maximum expansion
* possible is 50%. We throw in an additional 4096 for safety sake.
* We read the directory, one block at a time, translating
* it into bsd format and storing it into dirbuf. Once the entire directory
* is translated, we reflect any change in the di_size, and return
* dirbuf to caller to be dumped.
*/
static char *dirbuf = NULL;
static char *cend, *cptr; /* end marker, current block marker */
static struct direct *cdp; /* current entry */
static int csize; /* # blocks converted */
static int convertdir(void *);
char *
bsd_dumpdir(struct efs_dinode *ip)
{
int allocsize;
if (ip->di_size & EFS_DIRBMASK) {
msg("directory ino %d: size %d is not a multiple of dir block size %d\n",
ino, ip->di_size, EFS_DIRBSIZE);
return NULL;
}
allocsize = (int)BBTOB(BTOBB(ip->di_size + (ip->di_size >> 1) + 4096));
if ((dirbuf = calloc(allocsize, 1)) == NULL) {
perror(" DUMP: no memory to convert efs directories");
dumpabort();
}
cptr = dirbuf;
cend = dirbuf + allocsize;
cdp = (struct direct *)cptr;
csize = 1;
if (walkextents(ip, walkdir, convertdir)) {
free(dirbuf);
return NULL;
}
/*
* Adjust the d_reclen pointer in the last directory block and in one
* additional block which, if used for padding, won't be looked at,
* but we might as well be neat. The d_reclen pointer has to account
* for all the space in a directory.
*/
cdp->d_reclen = (int)((cptr+BBSIZE) - (char *)cdp);
if ((cptr + BBSIZE) < cend) {
cptr += BBSIZE;
cdp = (struct direct *)cptr;
cdp->d_reclen = BBSIZE;
}
/*
* We are done reading the directory blocks into memory. The blocks
* are all in dirbuf. Reflect that change in di_size.
*/
ip->di_size = BBTOB(csize);
return dirbuf;
}
/*
* Convert the given EFS directory entry.
*/
static int
convertdir(void *arg)
{
struct efs_dent *dep = arg;
struct direct cvtbuf, *dp = &cvtbuf;
int spaceleft;
dp->d_ino = EFS_GET_INUM(dep); /* can't be 0 */
dp->d_namlen = dep->d_namelen;
bcopy(dep->d_name, dp->d_name, dp->d_namlen);
dp->d_name[dp->d_namlen] = '\0';
dp->d_reclen = DIRSIZ(dp);
/* Advance to next block if there isn't room in this one. */
spaceleft = (int)((cptr+BBSIZE) - (char *)cdp) - cdp->d_reclen;
if (spaceleft < dp->d_reclen) {
cdp->d_reclen += spaceleft;
cptr += BBSIZE;
if (cptr >= cend) {
msg("Cannot continue because directory is too large!!");
return -1;
}
cdp = (struct direct *)cptr;
csize++;
} else
cdp = (struct direct *) ((char *)cdp + cdp->d_reclen);
/*
* Don't do record copy since d_reclen might be smaller than
* sizeof(struct direct)
*/
cdp->d_ino = dp->d_ino;
cdp->d_namlen = dp->d_namlen;
bcopy(dp->d_name, cdp->d_name, dp->d_namlen);
cdp->d_name[cdp->d_namlen] = '\0';
cdp->d_reclen = dp->d_reclen;
return 0;
}