|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 35051 (0x88eb)
Types: TextFile
Notes: UNIX file
Names: »mkfs.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/mkfs.c«
/*
* Make a filesystem.
* Efficiently, rec 84.08.31
*/
#define NDEBUG 1 /* No assertions turned on */
#define ES_SUCCESS 0 /* No problems at all */
#define ES_IGNORED 1 /* Some problems ignored */
#define ES_FORMAT 2 /* Proto file format error */
#define ES_FATAL 4 /* Process aborted */
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#define syserror (sys_errlist[errno])
#include <filsys.h>
#include <ino.h>
#include <fblk.h>
#include <dir.h>
#include <l.out.h>
#include <timeb.h>
#include <canon.h>
#include <stat.h>
#include <access.h>
#include <assert.h>
#define inodeb(i) (INODEI + ((i)-1)/8)
#define inodei(i) (((i)-1)%8)
#define NDLEV 25 /* Maximum directory nesting */
struct protoargs { /* Parameter management */
char *p_bname, *p_fname, *p_fpack;
char *p_fsize, *p_nino, *p_intn, *p_intm;
};
struct entre { /* Directory management */
ino_t e_ino;
char *e_name;
};
struct xnode { /* Minimal inode management */
ino_t x_ino;
int x_mode;
int x_uid;
int x_gid;
dev_t x_dev;
char *x_name;
int x_nlink;
size_t x_size;
daddr_t x_start;
struct ynode *x_y;
struct entre x_ents[];
};
struct ynode { /* Medial inode management */
ino_t y_ino;
size_t y_seek;
daddr_t y_nb; /* Number of blocks total */
daddr_t y_ni; /* Number of indirect blocks total */
int y_niiib; /* Number of triple indirect blocks */
int y_niib; /* Number of double indirect blocks */
daddr_t y_nib; /* Number of single indirect blocks */
daddr_t y_ndb; /* Number of data blocks */
daddr_t *y_db; /* Data block base */
daddr_t *y_ib; /* Single indirect block base */
daddr_t *y_iib; /* Double indirect block base */
daddr_t *y_iiib; /* Triple indirect block base */
daddr_t y_b[]; /* Actual block addresses, indirect first */
};
struct pfp { /* Input parsing */
char *p_fn; /* File name if any */
int p_ln; /* Line number if any */
int p_dln; /* Line number increment if any */
char *p_ip; /* Initial stream pointer */
char *p_cp; /* Current stream pointer */
struct pfp *p_fp; /* Previous stream record */
};
extern char devnull[];
extern char ascii0[];
extern char ascii1[];
extern int nino;
extern char *special;
extern char *proto;
extern struct filsys S;
extern int FS;
extern struct protoargs P;
extern struct protoargs N;
extern ino_t E[NDLEV];
extern int Elevel;
extern struct xnode **X;
extern char pnil[];
extern struct pfp pfp;
extern char *argv0;
extern int estatus;
extern char miscbuf[BSIZE];
extern struct entre *getentre();
extern ino_t getxnode();
extern ino_t getlink();
extern char *gettoken();
extern char *getline();
extern int getopen();
extern int getclose();
#define getch() ((*pfp.p_cp != 0) ? *pfp.p_cp++ : -1)
#define ungetch(c) ((c>=0 && pfp.p_cp>pfp.p_ip) ? (*--pfp.p_cp = c) : -1)
extern daddr_t balloc();
extern ino_t ialloc();
extern char *bcache();
time_t time();
char *xmalloc();
char *xrealloc();
char *strncpy();
char *strcat();
size_t ftell();
long atol();
int atoi();
/* FILE data.c */
char devnull[] = "/dev/null";
char ascii0[] = "0";
char ascii1[] = "1";
int nino; /* Number of inodes on new file system */
char *special; /* Special file specified */
char *proto; /* Proto file specified */
struct filsys S; /* Super block for new file system */
int FS; /* File descriptor of file system */
struct protoargs P; /* File system prototype parameters */
struct protoargs N = { /* Some names */
"bootstrap file", "file system name", "file pack name",
"file system size", "number of inodes", "interleave n", "interleave m"
};
ino_t E[NDLEV]; /* Current nesting of directory inodes */
int Elevel = -1; /* Current nesting level of directory inodes */
struct xnode **X; /* I-list pointers for new file system */
char pnil[] = "";
struct pfp pfp = { pnil, 0, 0, pnil, pnil, NULL }; /* Initial stream */
char *argv0 = "mkfs"; /* Command name */
int estatus = ES_SUCCESS; /* Exit status */
char miscbuf[BSIZE];
/* FILE main.c */
/*
* Magic number of i-nodes as a function of
* filesystem size in blocks.
*/
magic()
{
register char *p;
daddr_t fsize;
int nino;
static char b[8];
fsize = atol(P.p_fsize);
if (fsize > 1000)
nino = fsize / 7;
else
nino = fsize / 5;
p = b+8;
while (nino != 0) {
*--p = nino % 10 + '0';
nino /= 10;
}
P.p_nino = p;
}
main(argc, argv)
char *argv[];
{
int anyopts = 0;
if (argc < 1)
return eusage();
argv0 = argv[0];
/*
* Collect options.
*/
while (argc>2 && *argv[1]=='-') {
anyopts += 1;
switch (argv[1][1]) {
case 'b': P.p_bname = argv[2]; break;
case 'f': P.p_fname = argv[2]; break;
case 'i': P.p_nino = argv[2]; break;
case 'm': P.p_intm = argv[2]; break;
case 'n': P.p_intn = argv[2]; break;
case 'p': P.p_fpack = argv[2]; break;
default: return eusage();
}
argc -= 2;
argv += 2;
}
/*
* Parse primary arguments and read or construct
* prototype description.
*/
if (argc != 3)
return eusage();
special = argv[1];
if ( ! unnatural(argv[2])) {
P.p_fsize = argv[2];
if (mkproto() < 0)
return estatus;
} else {
proto = argv[2];
if (rdproto() < 0)
return estatus;
else if (anyopts)
eignore("superfluous command line options");
}
/*
* Scan real or imaginary proto file.
*/
if (getboot() < 0
|| getsuper() < 0
|| getdir() < 0
|| (estatus&ES_FORMAT))
return estatus;
/*
* Scan in core i list and allocate blocks.
*/
if (scanilist() < 0)
return (estatus);
/*
* Write the new file system.
*/
if (putboot() < 0
|| putsuper() < 0
|| putilist() < 0
|| putdata() < 0
|| putfree() < 0)
return (estatus);
return (estatus);
}
/*
* Prepare proto file for input.
* rdproto copies file into memory,
* mkproto constructs proto file in memory,
* each sets up gettoken() to read tokens.
*/
rdproto()
{
register char *p;
register int n;
register int fd;
register int nb;
if ((fd = open(proto, 0)) < 0)
return badopen("descriptor file", proto);
nb = 0;
n = BSIZE;
p = xmalloc(n);
while ((n = read(fd, p+nb, BSIZE)) == BSIZE) {
nb += BSIZE;
p = xrealloc(p, nb+BSIZE);
}
p[nb+n] = 0;
getopen(p, proto, 1);
return (0);
}
mkproto()
{
register char *p, *p1, *p0;
p0 = p = xmalloc(BSIZE);
if ((p1 = P.p_bname) != NULL) {
while (*p = *p1++) ++p;
if ((p1 = P.p_fname) != NULL) {
*p++ = ' ';
while (*p = *p1++) ++p;
if ((p1 = P.p_fpack) != NULL) {
*p++ = ' ';
while (*p = *p1++) ++p;
}
}
}
*p++ = '\n';
if (unnatural((p1 = P.p_fsize)))
return badvalue(N.p_fsize, p1), -1;
while (*p = *p1++) ++p;
if (P.p_nino == NULL)
magic();
if (unnatural((p1 = P.p_nino)))
return badvalue(N.p_nino, p1), -1;
*p++ = ' ';
while (*p = *p1++) ++p;
if ((p1 = P.p_intn) != NULL) {
if (unnatural(p1))
return badvalue(N.p_intn, p1), -1;
*p++ = ' ';
while (*p = *p1++) ++p;
if ((p1 = P.p_intm) != NULL) {
if (unnatural(p1))
return badvalue(N.p_intm, p1), -1;
*p++ = ' ';
while (*p = *p1++) ++p;
}
}
p1 = "\nd--755 0 0\n$\n";
while (*p = *p1++) ++p;
getopen(p0, NULL, 0);
return (0);
}
/* FILE get.c */
/*
* First pass activity -- scan proto file
* getboot() reads the boot file name.
* getsuper() reads the super block parameters and initializes
* the in memory file system structure.
* getbad() reads and actuates the bad block specification.
* getdir() reads the remainder of the proto file and constructs
* a directory tree and xnode list for the file system.
*/
getboot()
{
P.p_bname = gettoken();
if (P.p_bname == NULL)
P.p_bname = devnull;
}
getsuper()
{
if ((FS = open(special, 2)) < 0)
return badopen("special file", special);
if ((P.p_fname = gettoken()) == NULL)
P.p_fname = "noname";
strncpy(S.s_fname, P.p_fname, 6);
if ((P.p_fpack = gettoken()) == NULL)
P.p_fpack = "nopack";
strncpy(S.s_fpack, P.p_fpack, 6);
if (getline() == NULL)
return earlyeof();
if ((P.p_fsize = gettoken()) == NULL)
return efatal("no value for %s", N.p_fsize);
else if (unnatural(P.p_fsize))
return badvalue(N.p_fsize, P.p_fsize), -1;
S.s_fsize = atol(P.p_fsize);
if ((P.p_nino = gettoken()) == NULL)
magic();
else if (unnatural(P.p_nino))
return badvalue(N.p_nino, P.p_nino), -1;
S.s_isize = (atoi(P.p_nino)+INOPB-1)/INOPB + INODEI;
if ((P.p_intn = gettoken()) == NULL)
P.p_intn = ascii1;
else if (unnatural(P.p_intn))
return badvalue(N.p_intn, P.p_intn), -1;
S.s_n = atoi(P.p_intn);
if ((P.p_intm = gettoken()) == NULL)
P.p_intm = ascii1;
else if (unnatural(P.p_intm))
return badvalue(N.p_intm, P.p_intm), -1;
S.s_m = atoi(P.p_intm);
if (getline() == NULL)
return earlyeof();
/* Set the initial ifree list so that bad file can be initialized */
S.s_ninode = 0;
S.s_tinode = (S.s_isize - INODEI) * INOPB;
S.s_inode[S.s_ninode++] = BADFIN+1;
S.s_inode[S.s_ninode++] = BADFIN;
nino = S.s_tinode;
/* Allocate memory i list */
X = xmalloc(S.s_tinode * sizeof(*X));
clear(X, S.s_tinode * sizeof(*X));
/* Read the bad block list */
if (getbad() < 0)
return (-1);
/* Initialize the free block list */
bbegin();
/* Fixup the bad block file, ie allocate indirects */
xfixup(X[BADFIN-1]);
/* Set the time of construction */
time(&S.s_time);
return (0);
}
getbad()
{
register int c;
register daddr_t b;
register char *tp;
static char mymsg1[] = "illegal bad block number '%s'";
static char mymsg2[] = "out of bounds bad block number '%s'";
if (getxnode("B----- 0 0\n") != BADFIN)
return efatal("bad block file != inode %d", BADFIN);
xexpand(X[BADFIN-1]);
for (;;) {
if ((c = getch()) != '%') {
ungetch(c);
break;
}
if ((c = getch()) != 'b') {
ungetch(c);
c = '%';
ungetch(c);
break;
}
while ((tp = gettoken()) != NULL) {
if (unnatural(tp)) {
eformat(mymsg1, tp);
continue;
}
b = atol(tp);
if (b >= S.s_fsize) {
eformat(mymsg2, tp);
continue;
}
xextend(X[BADFIN-1], b);
}
getline();
}
return (0);
}
getdir()
{
char *cp1, *cp2;
struct entre *ep;
struct xnode *xp;
int inum;
for (;;) {
if (Elevel < 0) {
cp1 = getline();
} else {
cp1 = gettoken();
cp2 = getline();
}
if (cp1 == NULL)
return earlyeof();
if (*cp1 == '$') {
if (Elevel-- < 0) {
assert(proto != NULL);
efatal("misplaced '$' in '%s'", proto);
}
if (Elevel < 0)
break;
continue;
}
if (Elevel >= 0) {
ep = getentre(cp1);
} else
cp2 = cp1;
inum = getxnode(cp2);
if (Elevel >= 0)
ep->e_ino = inum;
if (inum == 0)
continue;
assert(inum > BADFIN);
assert(inum <= nino);
xp = X[inum-1];
xp->x_nlink += 1;
assert(xp != NULL);
if ((xp->x_mode&IFMT) == IFDIR) {
if (++Elevel >= NDLEV)
return efatal("directories too deep");
E[Elevel] = inum;
ep = getentre(".");
ep->e_ino = inum;
xp = X[inum-1];
xp->x_nlink += 1;
ep = getentre("..");
if (Elevel != 0)
inum = E[Elevel-1];
ep->e_ino = inum;
xp = X[inum-1];
xp->x_nlink += 1;
}
}
return (0);
}
struct entre *
getentre(cp)
char *cp;
{
register struct xnode *xp;
register struct entre *ep;
register int inum;
int nent;
assert(Elevel >= 0);
inum = E[Elevel];
assert(inum > BADFIN);
assert(inum <= nino);
xp = X[inum-1];
assert(xp != NULL);
assert((xp->x_mode&IFMT) == IFDIR);
xp->x_size += sizeof(struct direct);
nent = xp->x_size / sizeof(struct direct);
xp = xrealloc(xp, sizeof(*xp) + nent*sizeof(*ep));
X[inum-1] = xp;
ep = &xp->x_ents[nent-1];
ep->e_ino = 0;
ep->e_name = cp;
return (ep);
}
ino_t
getxnode(cp)
char *cp;
{
register struct xnode *xp;
register ino_t inum;
char *type, *uid, *gid, *name;
int mode;
dev_t dev;
struct stat sbuf;
if (cp == NULL)
missing_spec:
return eformat("missing file specification");
getopen(cp, NULL, 0);
type = gettoken();
uid = gettoken();
gid = gettoken();
name = gettoken();
getclose();
if (type == NULL)
goto missing_spec;
inum = 0;
sbuf.st_size = 0;
dev = 0;
if (*type == 'l') { /* Link to previously defined file */
if (name == NULL)
return eformat("missing link name '%s'", cp);
inum = getlink((*name=='/' ? E[0] : E[Elevel]), name);
if (inum == 0)
return eformat("unknown link name '%s'", name);
return (inum);
}
switch (type[0]) {
case 'b':
case 'c':
if (name == NULL)
return eformat("missing device specification");
else
dev = getdev(name);
goto common;
case 'd':
case 'p':
goto common;
case 'B':
goto common;
case '-':
if (name == NULL)
return eformat("missing source for regular file");
else if (access(name, AREAD) < 0)
return eignore("access to '%s' failed: %s", name, syserror);
else if (stat(name, &sbuf) < 0)
return eignore("stat of '%s' failed: %s", name, syserror);
else if ((sbuf.st_mode&IFMT) != IFREG)
return eformat("'%s' is not a regular file", name);
common:
if ((mode = getmode(type)) == 0)
return (0);
if (uid == NULL || unnatural(uid))
return eformat("bad user id '%s'", uid);
if (gid == NULL || unnatural(gid))
return eformat("bad or missing group id '%s'", gid);
break;
default:
return eformat("bad file specification '%s'", cp);
}
xp = xmalloc(sizeof(*xp));
xp->x_size = sbuf.st_size;
xp->x_nlink = 0;
xp->x_y = NULL;
xp->x_start = 0;
xp->x_ino = inum = ialloc();
xp->x_mode = mode;
xp->x_dev = dev;
xp->x_uid = atoi(uid);
xp->x_gid = atoi(gid);
xp->x_name = name;
X[inum-1] = xp;
return (inum);
}
/* Translate proto mode specification into mode word */
getmode(cp)
char *cp;
{
register char *p;
register int mode;
register int i;
static char mymessage[] = "mode format: %s char should be one of %s";
p = cp;
assert(p != NULL);
mode = 0;
switch (*p++) {
case 'b': mode |= IFBLK; break;
case 'c': mode |= IFCHR; break;
case 'd': mode |= IFDIR; break;
case 'p': mode |= IFPIPE; break;
case '-': mode |= IFREG; break;
case 'B': mode |= IFREG; return (mode);
case 'l': assert(p[-1] != 'l'); break;
default: return eformat(mymessage, "1st", "[bcdlp-]");
}
switch (*p++) {
case 'u': mode |= ISUID; break;
case '-': break;
default: return eformat(mymessage, "2nd", "[u-]");
}
switch (*p++) {
case 'g': mode |= ISGID; break;
case '-': break;
default: return eformat(mymessage, "3rd", "[g-]");
}
for (i = 1<<6; i > 0; i >>= 3) switch (*p++) {
case '7': mode += i;
case '6': mode += i;
case '5': mode += i;
case '4': mode += i;
case '3': mode += i;
case '2': mode += i;
case '1': mode += i;
case '0':
case '-': break;
default: return eformat(mymessage, "4th, 5th, or 6th", "[01234567-]");
}
return (mode);
}
getdev(cp)
char *cp;
{
char *majp, *minp;
getopen(cp, NULL, 0);
majp = gettoken();
minp = gettoken();
getclose();
if (majp == NULL || unnatural(majp))
return badvalue("major number", cp);
if (minp == NULL || unnatural(minp))
return badvalue("minor number", cp);
return makedev(atoi(majp), atoi(minp));
}
/*
* Lookup a name in our directory tree.
*/
ino_t
getlink(inum, name)
ino_t inum;
char *name;
{
int i, nent;
struct entre *ep;
struct xnode *xp;
assert(inum > BADFIN);
assert(inum <= nino);
xp = X[inum-1];
nextname:
assert(xp != NULL);
ep = xp->x_ents;
nent = xp->x_size / sizeof(struct direct);
while (*name == '/')
name += 1;
if (*name == 0)
return (inum);
while (--nent >= 0) {
if (ep->e_ino == 0) {
ep += 1;
continue;
}
for (i = 0; ; i += 1) {
if (i == DIRSIZ
|| ep->e_name[i] == 0) {
inum = ep->e_ino;
assert(inum > BADFIN);
assert(inum <= nino);
if (name[i] == 0)
return (inum);
if (name[i] == '/') {
name += i;
xp = X[inum-1];
assert(xp != NULL);
if ((xp->x_mode&IFMT) != IFDIR)
return (0);
goto nextname;
}
return (0);
}
if (name[i] != ep->e_name[i])
break;
}
ep += 1;
}
return (0);
}
/*
* Intermediate pass, prepare for writing.
* scanilist() scans the xnode list and allocates data blocks
* and indirect mapping blocks.
*/
scanilist()
{
register int i;
register struct xnode *xp;
for (i = BADFIN+1; i <= nino; i += 1) {
if ((xp = X[i-1]) == NULL)
continue;
xexpand(xp);
xcontract(xp);
}
}
/* FILE put.c */
/*
* Second pass --
* we write everything in the order it appears
* without intervening reads.
* putboot() writes the boot block.
* putsuper() writes the super block.
* putilist() writes the ilist.
* putdata() writes the files.
* putfree() fills in the free block list.
*/
putboot()
{
register int fd;
register struct ldheader *ldp;
char *bp;
size_t fsize;
if ((fd = open(P.p_bname, 0)) < 0) {
eignore("open %s '%s': %s\n", N.p_bname, P.p_bname, syserror);
return (0);
}
bp = bcache((daddr_t)BOOTBI);
if (read(fd, bp, BSIZE) == BSIZE) {
ldp = (struct ldheader *)bp;
canint(ldp->l_magic);
if (ldp->l_magic == L_MAGIC) {
cansize(ldp->l_ssize[L_PRVD]);
cansize(ldp->l_ssize[L_SHRD]);
cansize(ldp->l_ssize[L_PRVI]);
cansize(ldp->l_ssize[L_SHRI]);
fsize = ldp->l_ssize[L_PRVD] + ldp->l_ssize[L_SHRD]
+ ldp->l_ssize[L_PRVI] + ldp->l_ssize[L_SHRI];
if (fsize > BSIZE)
eignore("%s '%s' truncated to %d",
N.p_bname, P.p_bname, BSIZE);
lseek(fd, 44L, 0);
read(fd, bp, BSIZE);
} else
canint(ldp->l_magic);
}
close(fd);
return (0);
}
putsuper()
{
register char *bp;
bp = bcache((daddr_t)SUPERI);
copy(bp, &S, BSIZE);
cansuper(bp);
return (0);
}
/*
* Canonicalize the super block.
*/
cansuper(sbp)
register struct filsys *sbp;
{
canshort(sbp->s_isize);
candaddr(sbp->s_fsize);
canshort(sbp->s_nfree);
{
register daddr_t *dp;
register int i;
i = NICFREE;
dp = &sbp->s_free[NICFREE];
while (--i >= 0) {
dp -= 1; /* Watch for side effects */
candaddr(*dp);
}
}
canshort(sbp->s_ninode);
{
register ino_t *ip;
register int i;
i = NICINOD;
ip = &sbp->s_inode[NICINOD];
while (--i >= 0) {
ip -= 1;
canino(*ip);
}
}
cantime(sbp->s_time);
candaddr(sbp->s_tfree);
canino(sbp->s_tinode);
canshort(sbp->s_m);
canshort(sbp->s_n);
canlong(sbp->s_unique);
}
putilist()
{
register struct xnode *xp;
struct dinode din;
ino_t inum;
clear(&din, sizeof(din));
for (inum = BADFIN; inum <= nino; inum += 1) {
if (bad(inodeb(inum))) {
inum += INOPB;
continue;
}
xp = X[inum-1];
if (xp == NULL) {
iput(inum, &din);
continue;
}
din.di_mode = xp->x_mode;
din.di_mtime = S.s_time;
din.di_ctime = S.s_time;
din.di_atime = S.s_time;
din.di_size = xp->x_size;
din.di_nlink = xp->x_nlink;
din.di_uid = xp->x_uid;
din.di_gid = xp->x_gid;
switch (xp->x_mode&IFMT) {
case IFBLK:
case IFCHR:
din.di_a.di_rdev = xp->x_dev;
break;
case IFDIR:
case IFREG:
if (inum != BADFIN)
xexpand(xp);
xymerge(xp, &din);
if (inum != BADFIN)
xcontract(xp);
break;
}
iput(inum, &din);
clear(&din, sizeof(din));
}
return (0);
}
putdata()
{
register int i;
register struct xnode *xp;
putbad();
for (i = BADFIN+1; i <= nino; i += 1) {
if ((xp = X[i-1]) == NULL)
continue;
if ((xp->x_mode&IFMT) == IFDIR)
putdir(xp);
else if ((xp->x_mode&IFMT) == IFREG)
putreg(xp);
}
return (0);
}
putbad()
{
register struct ynode *yp;
assert(X[BADFIN-1] != NULL);
yp = X[BADFIN-1]->x_y;
assert(yp != NULL);
if (yp->y_ni)
xindir(yp);
}
putdir(xp)
struct xnode *xp;
{
struct direct dir;
register struct entre *ep;
int i, nent;
xexpand(xp);
nent = xp->x_size / sizeof(struct direct);
for (i = 0; i < nent; i += 1) {
ep = xp->x_ents + i;
dir.d_ino = ep->e_ino;
strncpy(dir.d_name, ep->e_name, DIRSIZ);
if (strlen(ep->e_name) > DIRSIZ)
eignore("directory name '%s' truncated to %d chars",
ep->e_name, DIRSIZ);
canino(dir.d_ino);
xwrite(xp, &dir, sizeof(struct direct));
}
xcontract(xp);
}
putreg(xp)
struct xnode *xp;
{
int fd, nb;
size_t size;
struct stat sbuf;
if (stat(xp->x_name, &sbuf) < 0)
return eignore("stat of %s failed: %s", xp->x_name, syserror);
if (sbuf.st_size != xp->x_size)
return eignore("size of %s has changed", xp->x_name);
if ((fd = open(xp->x_name, 0)) < 0)
return eignore("open %s failed: %s", xp->x_name, syserror);
xexpand(xp);
size = xp->x_size;
while (size > 0) {
nb = read(fd, miscbuf, BSIZE);
if (nb < 0) {
eignore("read %s failed: %s", xp->x_name, syserror);
break;
}
xwrite(xp, miscbuf, BSIZE);
size -= nb;
}
xcontract(xp);
close(fd);
}
putfree()
{
daddr_t b;
register daddr_t *dp;
register int n;
while (S.s_nfree > 0) {
while (S.s_nfree > 1)
b = balloc();
b = balloc(); /* Forces load of next free block */
dp = bcache(b);
((struct fblk *)dp)->df_nfree = n = S.s_nfree;
canint(((struct flbk *)dp)->df_nfree);
dp = &((struct fblk *)dp)->df_free[0];
copy(dp, S.s_free, n * sizeof(daddr_t));
while (--n >= 0) {
candaddr(*dp);
dp += 1;
}
}
bcache((daddr_t)-1); /* Flush */
return (0);
}
/* FILE misc.c */
/*
* Allocation with fatal errors.
*/
char *
xmalloc(nb)
{
char *p;
p = malloc(nb);
if (p != NULL)
return (p);
efatal("memory allocation failed");
}
char *
xrealloc(p, nb)
char *p;
{
p = realloc(p, nb);
if (p != NULL)
return (p);
efatal("memory reallocation failed");
}
/*
* Errors.
*/
char usage[] = "\
Usage: %s special proto\n\
%s [-m n] [-n n] [-b boot] [-f fname] [-p pack] [-i n] special n\n\
";
eusage()
{
fprintf(stderr, usage, argv0, argv0);
estatus |= ES_FATAL;
exit(estatus);
}
eerror(es, fs, ap)
int es;
char *fs;
char **ap;
{
fprintf(stderr, "%s: ", argv0);
if (pfp.p_fn) fprintf(stderr, "in %s: ", pfp.p_fn);
if (pfp.p_ln) fprintf(stderr, "at %d: ", pfp.p_ln);
fprintf(stderr, fs, ap);
estatus |= es;
if (estatus & ES_FATAL)
exit(estatus);
return (0);
}
efatal(a1)
char *a1;
{
return eerror(ES_FATAL, "%r\n", &a1);
}
eignore(a1)
char *a1;
{
return eerror(ES_IGNORED, "%r (ignored)\n", &a1);
}
eformat(a1)
char *a1;
{
return eerror(ES_FORMAT, "%r\n", &a1);
}
badvalue(np, vp)
char *np, *vp;
{
return eformat("bad value for %s: %s", np, vp);
}
badopen(np, cp)
char *cp;
{
return efatal("open '%s' as %s failed: %s", cp, np, syserror);
}
earlyeof()
{
assert(proto != NULL);
return efatal("unexpected end of descriptor file: %s", proto);
}
/*
* Token and line input.
* getopen() pushes the current input string,
* getclose() pops the previous input string,
* gettoken() returns a pointer to the beginning of the next token,
* getline() returns pointer to the same and advances to next line.
* both return NULL on unexpected end of file.
*/
getopen(cp, fn, dln)
char *cp;
char *fn;
int dln;
{
struct pfp *tp;
tp = xmalloc(sizeof(*tp));
*tp = pfp;
pfp.p_fn = fn;
pfp.p_ln = 0;
pfp.p_dln = dln;
pfp.p_ip = pfp.p_cp = cp;
pfp.p_fp = tp;
}
getclose()
{
struct pfp *tp;
assert(pfp.p_fp != NULL);
tp = pfp.p_fp;
pfp = *tp;
free(tp);
}
char *
gettoken()
{
register int c;
register char *p, *tp;
pfp.p_ln += pfp.p_dln;
pfp.p_dln = 0;
p = pfp.p_cp;
while ((c = *p) == ' ' || c == '\t')
*p++ = 0;
pfp.p_cp = tp = p;
if (c == 0 || c == '\n')
return (NULL);
do
c = *p++;
while (c != 0 && c != ' ' && c != '\t' && c != '\n');
pfp.p_cp = p - 1;
return (tp);
}
char *
getline()
{
register int c;
register char *p, *tp;
pfp.p_ln += pfp.p_dln;
pfp.p_dln = 0;
p = pfp.p_cp;
while ((c = *p) == ' ' || c == '\t')
*p++ = 0;
pfp.p_cp = tp = p;
if (c == 0)
return earlyeof();
if (c == '\n') {
*p++ = 0;
pfp.p_cp += 1;
if (pfp.p_ln) pfp.p_dln = 1;
return (tp);
}
do
c = *p++;
while (c != 0 && c != '\n');
if (c == 0)
return earlyeof();
pfp.p_cp = p;
p[-1] = 0;
return (tp);
}
/*
* Miscellaneous.
*/
unnatural(cp)
char *cp;
{
register char *p;
p = cp;
while (isdigit(*p)) p += 1;
switch (*p) {
case 0:
case ' ':
case '\t':
case '\n':
return (0);
default:
return (-1);
}
}
clear(bp, n)
register char *bp;
register unsigned n;
{
if (n) do {
*bp++ = 0;
} while (--n);
}
copy(bp1, bp2, n)
register char *bp1;
register char *bp2;
register unsigned n;
{
if (n) do {
*bp1++ = *bp2++;
} while (--n);
}
iszero(bp, n)
register char *bp;
register unsigned n;
{
if (n) do
if (*bp++ != 0) return (0);
while (--n);
return (1);
}
/* FILE xmisc.c */
/*
* xexpand() - creates a block map for the inode.
* indirect blocks are allocated sequentially, followed by data blocks
* also sequentially.
* xcontract() - discards the block map.
* xextend() - appends a specified data block to the bad inode.
* xymerge() - merges block addresses into disk inode structure.
* xwrite() - writes data and necessary indirect blocks into filesystem.
*/
int xwatch = 0;
xexpand(xp)
struct xnode *xp;
{
register struct ynode *yp;
register daddr_t *dp;
register daddr_t nb;
daddr_t b;
assert(xp != NULL);
assert(xp->x_ino >= BADFIN);
assert(xp->x_ino <= nino);
yp = xp->x_y;
assert(yp == NULL);
xp->x_y = yp = xmalloc(sizeof(*yp) + NADDR * sizeof(daddr_t));
clear(yp, sizeof(*yp) + NADDR * sizeof(daddr_t));
yp->y_ino = xp->x_ino;
yp->y_seek = 0;
xblkuse(xp);
nb = yp->y_nb;
if (nb > NADDR) {
xp->x_y = yp = xrealloc(yp, sizeof(*yp)
+ ((unsigned)nb) * sizeof(daddr_t));
clear(yp->y_b, ((unsigned)nb) * sizeof(daddr_t));
}
/* Set up pointers */
yp->y_iiib = yp->y_b;
yp->y_iib = yp->y_iiib + yp->y_niiib;
yp->y_ib = yp->y_iib + yp->y_niib;
yp->y_db = yp->y_ib + yp->y_nib;
/* Resynchronize the allocator */
if (b = xp->x_start)
bstart(xp->x_start);
/* Allocate blocks */
dp = yp->y_b;
nb = yp->y_nb;
while (--nb >= 0)
*dp++ = balloc();
if (xp->x_start == 0)
xp->x_start = yp->y_b[0];
}
xblkuse(xp)
struct xnode *xp;
{
register struct ynode *yp;
register daddr_t nb;
yp = xp->x_y;
nb = xp->x_size + BSIZE - 1;
nb /= BSIZE;
yp->y_niiib = 0;
yp->y_niib = 0;
yp->y_nib = 0;
yp->y_ndb = 0;
yp->y_ni = 0;
if (nb > ND) {
if (nb > ND+NBN) {
if (nb > ND+NBN+NBN*NBN) {
nb -= ND+NBN+NBN*NBN;
assert(nb > 0 && nb < NBN*NBN*(long)NBN);
yp->y_ndb += nb;
nb += NBN-1;
nb /= NBN;
yp->y_nib += nb;
nb += NBN-1;
nb /= NBN;
yp->y_niib += nb;
assert(((nb+NBN-1)/NBN) == 1);
yp->y_niiib += 1;
nb = ND+NBN+NBN*NBN;
}
nb -= ND+NBN;
assert(nb > 0 && nb < NBN*NBN);
yp->y_ndb += nb;
nb += NBN-1;
nb /= NBN;
yp->y_nib += nb;
assert(((nb+NBN-1)/NBN) == 1);
yp->y_niib += 1;
nb = ND+NBN;
}
nb -= ND;
assert(nb > 0 && nb < NBN);
yp->y_ndb += nb;
assert(((nb+NBN-1)/NBN) == 1);
yp->y_nib += 1;
nb = ND;
}
assert(nb >= 0 && nb <= ND);
yp->y_ndb += nb;
yp->y_ni = yp->y_nib + yp->y_niib + yp->y_niiib;
yp->y_nb = yp->y_ndb + yp->y_ni;
}
xcontract(xp)
register struct xnode *xp;
{
register struct ynode *yp;
assert(xp != NULL);
assert(xp->x_ino >= BADFIN);
assert(xp->x_ino <= nino);
yp = xp->x_y;
assert(yp != NULL);
assert(yp->y_ino == xp->x_ino);
xp->x_y = NULL;
free(yp);
}
xymerge(xp, dip)
struct xnode *xp;
struct dinode *dip;
{
register struct ynode *yp;
char *l3p;
assert(xp != NULL);
assert(xp->x_ino >= BADFIN);
assert(xp->x_ino <= nino);
yp = xp->x_y;
assert(yp != NULL);
assert(yp->y_ino == xp->x_ino);
l3p = dip->di_addr;
ltol3(l3p, yp->y_db, ND);
l3p += 3*ND;
if (yp->y_nib)
ltol3(l3p, yp->y_ib, 1);
l3p += 3;
if (yp->y_niib)
ltol3(l3p, yp->y_iib, 1);
l3p += 3;
if (yp->y_niiib)
ltol3(l3p, yp->y_iiib, 1);
}
xwrite(xp, cp, nb)
struct xnode *xp;
char *cp;
int nb;
{
register struct ynode *yp;
daddr_t bn;
int bo;
char *bp;
assert(xp != NULL);
assert(xp->x_ino > BADFIN);
assert(xp->x_ino <= nino);
yp = xp->x_y;
assert(yp != NULL);
assert(yp->y_ino == xp->x_ino);
if (yp->y_seek == 0 && yp->y_ni != 0)
xindir(yp); /* Write indirect blocks */
bn = yp->y_seek / BSIZE;
assert(bn < yp->y_ndb);
bo = yp->y_seek % BSIZE;
assert(bo+nb <= BSIZE);
bp = bcache(yp->y_db[(int)bn]);
copy(bp+bo, cp, nb);
yp->y_seek += nb;
}
xindir(yp)
register struct ynode *yp;
{
/* Triple indirect block */
if (yp->y_niiib)
xindblks(yp->y_iiib, yp->y_iib+1, (daddr_t)yp->y_niib-1);
/* Double indirect blocks */
if (yp->y_niib)
xindblks(yp->y_iib, yp->y_ib+1, (daddr_t)yp->y_nib-1);
/* Single indirect blocks */
if (yp->y_nib)
xindblks(yp->y_ib, yp->y_db+ND, (daddr_t)yp->y_ndb-ND);
}
xindblks(dp, sp, nb)
register daddr_t *dp, *sp, nb;
{
register int n;
while (nb > 0) {
if (nb >= NBN)
n = NBN;
else
n = nb;
xindblk(*dp, sp, n);
dp += 1;
sp += n;
nb -= n;
}
}
xindblk(b, bp, nd)
daddr_t b, *bp;
register int nd;
{
register daddr_t *dp;
dp = bcache(b);
copy(dp, bp, nd * sizeof(daddr_t));
while (--nd >= 0) {
candaddr(*dp);
dp += 1;
}
}
/*
* Extend the bad block file.
*/
xextend(xp, b)
struct xnode *xp;
daddr_t b;
{
register struct ynode *yp;
int nd;
assert(xp != NULL);
assert(xp->x_ino == BADFIN);
yp = xp->x_y;
assert(yp != NULL);
assert(yp->y_ino == BADFIN);
assert(b < S.s_fsize);
if (bad(b))
return eignore("duplicated bad block %D", b);
else if (b == BOOTBI)
return eignore("boot block (%D) is bad", b);
else if (b == SUPERI)
return efatal("super block (%D) is bad", b);
else if (b == inodeb(BADFIN))
return efatal("first inode block (%D) is bad", b);
else if (b < S.s_isize)
S.s_tinode -= INOPB;
else
S.s_tfree -= 1;
xp->x_size += BSIZE;
nd = yp->y_ndb += 1;
if (nd > NADDR)
xp->x_y = yp = xrealloc(yp, sizeof(*yp) + nd * sizeof(daddr_t));
yp->y_b[nd-1] = b;
}
bad(b)
daddr_t b;
{
struct ynode *yp;
register daddr_t *dp;
register int i;
assert(X[BADFIN-1] != NULL);
yp = X[BADFIN-1]->x_y;
assert(yp != NULL);
assert(yp->y_ino == BADFIN);
i = yp->y_ndb;
dp = yp->y_db;
while (--i >= 0)
if (b == *dp)
return (1);
else
dp += 1;
return (0);
}
xfixup(xp)
struct xnode *xp;
{
struct ynode *yp;
register daddr_t *dp1, *dp2;
register int i;
assert(xp != NULL);
assert(xp->x_ino == BADFIN);
yp = xp->x_y;
assert(yp != NULL);
xblkuse(xp);
if (yp->y_ni) {
yp = xrealloc(yp, sizeof(*yp) + yp->y_nb * sizeof(daddr_t));
xp->x_y = yp;
yp->y_iiib = yp->y_b;
yp->y_iib = yp->y_iiib + yp->y_niiib;
yp->y_ib = yp->y_iib + yp->y_niib;
yp->y_db = yp->y_ib + yp->y_nib;
dp1 = yp->y_db + yp->y_ndb;
dp2 = yp->y_b + yp->y_ndb;
i = yp->y_ndb;
while (--i >= 0)
*--dp1 = *--dp2;
dp1 = yp->y_b;
i = yp->y_ni;
while (--i >= 0)
*dp1++ = balloc();
}
}
xdump(xp)
register struct xnode *xp;
{
register struct ynode *yp;
yp = xp->x_y;
fprintf(stderr, "%d %x %D\n", xp->x_ino, xp->x_mode, xp->x_size);
if (yp->y_niiib)
xlist("indir^3", yp->y_iiib, (daddr_t)yp->y_niiib);
if (yp->y_niib)
xlist("indir^2", yp->y_iib, (daddr_t)yp->y_niib);
if (yp->y_nib)
xlist("indir^1", yp->y_ib, (daddr_t)yp->y_nib);
if (yp->y_ndb)
xlist("data", yp->y_db, (daddr_t)yp->y_ndb);
}
xlist(cp, dp, n)
char *cp;
daddr_t *dp;
daddr_t n;
{
fprintf(stderr, " %d %s: ", n, cp);
for (;;) {
fprintf(stderr, "%D", dp[0]);
dp += 1;
n -= 1;
if (n == 0)
break;
if (dp[0] == dp[-1]+1) {
fprintf(stderr, "..");
while (dp[0] == dp[-1]+1) {
dp += 1;
n -= 1;
if (n == 0)
break;
}
fprintf(stderr, "%D", dp[-1]);
if (n == 0)
break;
}
fprintf(stderr, ", ");
}
fprintf(stderr, "\n");
}
/* FILE imisc.c */
/*
* Inode cache management.
* iput() - writes an inode to disk.
*/
/*
* Write the inode `ip' containing the inode `i' onto the
* filesystem in canonical form.
*/
iput(i, dip1)
ino_t i;
register struct dinode *dip1;
{
register struct dinode *dip2;
dip2 = bcache((daddr_t)inodeb(i));
dip2 += inodei(i);
*dip2 = *dip1;
canshort(dip2->di_mode);
canshort(dip2->di_nlink);
canshort(dip2->di_uid);
canshort(dip2->di_gid);
cansize(dip2->di_size);
cantime(dip2->di_atime);
cantime(dip2->di_mtime);
cantime(dip2->di_ctime);
switch (dip1->di_mode&IFMT) {
case IFCHR:
case IFBLK:
candev(dip2->di_a.di_rdev);
break;
}
}
/*
* Return a free inode number.
*/
ino_t
ialloc()
{
ino_t inum;
ino_t in;
ino_t *ip;
daddr_t b;
if (S.s_ninode == 0)
return efatal("out of inodes");
inum = S.s_inode[--S.s_ninode];
if (S.s_ninode == 0) {
ip = &S.s_inode[NICINOD];
in = inum + 1;
while ((b = inodeb(in)) < S.s_isize && ip >S.s_inode) {
if (bad(b)) {
in += INOPB;
continue;
}
*--ip = in++;
}
S.s_ninode = NICINOD;
if (ip != S.s_inode) {
S.s_ninode -= ip - S.s_inode;
copy(S.s_inode, ip, S.s_ninode * sizeof(ino_t));
}
}
--S.s_tinode;
return (inum);
}
/* FILE bmisc.c */
/*
* Block management.
* bbegin() - set the seed of the block allocator.
* balloc() - allocate a block.
* bstart() - resynchronize the allocation.
* bmap() - implement interleave mapping.
* bcache() - single block buffer cache.
*/
int bwatch = 0;
static daddr_t bseed;
static daddr_t bmap();
bbegin()
{
/* Must be called after the bad block list is initialized */
assert(X != NULL);
assert(X[BADFIN-1] != NULL);
assert(X[BADFIN-1]->x_y != NULL);
bseed = S.s_isize;
S.s_tfree = S.s_fsize - S.s_isize;
S.s_tfree -= X[BADFIN-1]->x_size / BSIZE;
clear(S.s_free, NICFREE*sizeof(daddr_t));
S.s_nfree = 1;
while (bad(S.s_free[0] = bmap(bseed)))
++bseed;
}
daddr_t
balloc()
{
register daddr_t *dp;
register daddr_t b, b1;
if (S.s_nfree == 0)
return 0;
b = S.s_free[--S.s_nfree];
if (S.s_nfree == 0) {
clear(S.s_free, sizeof S.s_free);
dp = &S.s_free[NICFREE];
while (dp > S.s_free && ++bseed < S.s_fsize) {
b1 = bmap(bseed);
if (bad(b1))
continue;
*--dp = b1;
}
S.s_nfree = NICFREE - (dp - S.s_free);
if (dp != S.s_free)
copy(S.s_free, dp, S.s_nfree * sizeof(daddr_t));
}
--S.s_tfree;
return (b);
}
bstart(b)
daddr_t b;
{
if (S.s_nfree && S.s_free[S.s_nfree-1] == b)
return;
bbegin();
while (S.s_nfree && S.s_free[S.s_nfree-1] != b)
balloc();
assert(S.s_nfree != 0);
}
#define MAXINTN 500 /* maptab must be int * if > 255 */
static unsigned int *maptab; /* Interleave table */
static daddr_t mapbot;
static daddr_t maptop;
/*
* Return a mapped block number with interleaving.
*/
static daddr_t
bmap(b)
daddr_t b;
{
register int i;
register int ints;
if (maptab == NULL) {
if (S.s_n > MAXINTN
|| S.s_m > S.s_n
|| S.s_n%S.s_m != 0)
efatal("%d/%d: bad interleave factor", S.s_m, S.s_n);
maptab = xmalloc(S.s_n*sizeof(maptab[0]));
mapbot = (S.s_isize+S.s_n-1)/S.s_n*S.s_n;
maptop = S.s_fsize/S.s_n*S.s_n;
ints = S.s_n/S.s_m;
for (i=0; i<S.s_n; i++)
maptab[i] = (i/ints) + (i%ints)*S.s_m;
}
if (b>=mapbot && b<maptop) {
i = ((unsigned)b)%S.s_n;
b -= i;
b += maptab[i];
}
return (b);
}
char *
bcache(b)
daddr_t b;
{
static daddr_t bcacheb = -1;
static char buffer[BSIZE];
if (bcacheb != b) {
if (bcacheb >= 0) {
lseek(FS, (long)bcacheb*BSIZE, 0);
if (bwatch) bdump(b, bcacheb, buffer);
if (write(FS, buffer, BSIZE) != BSIZE)
eignore("filesystem write error at block %D", b);
}
clear(buffer, BSIZE);
}
bcacheb = b;
return (buffer);
}
bdump(b1, b2, bp)
daddr_t b1, b2;
char *bp;
{
int i, j;
fprintf(stderr, "bcache(%D) writes(%D) = {", b1, b2);
if (iszero(bp, BSIZE))
fprintf(stderr, " 0 ");
else {
fprintf(stderr, "\n");
for (i = 0; i < 32; i += 1) {
for (j = 0; j < 16; j += 1)
fprintf(stderr, " %02x", *bp++ & 0377);
fprintf(stderr, "\n");
}
}
fprintf(stderr, "}\n");
}