home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
lan
/
soss.arj
/
SRC
/
INODES.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-22
|
21KB
|
743 lines
/*
* inodes.c --
* Index node implementation for PC NFS file server. The server
* builds its view of the filesystem everytime a lookup call is
* generated for a file, and initially when the file system export
* list is parsed. This package handles DOS and UNIX style pathnames.
*
* Author:
* See-Mong Tan
* Modified by:
* Rich Braun @ Kronos
*/
#include "common.h"
/* forward declaration of local procedures */
static void getcomp();
static u_long insertapath();
static u_long newinodeno();
static bool_t _inremnode();
/* the inode dump file */
#define INODEFILE "inode.dmp"
/* Number of inodes and attributes entries to store in memory */
#define NUMINODES 12000
#define NUMACACHE 400
/* the global inode file pointer */
static FILE *inodefp;
/* last inode number assigned - starting from 2, 1 is root directory of all */
static u_long lastinodeno = 2;
/* The attributes cache. Each inode is optionally associated */
/* with a cache entry containing its file attributes (owner UID, */
/* size, creation date, etc.) The cache is fixed in size and is */
/* stored in the form of a doubly-linked list, with the most recently */
/* accessed item at the head and the oldest at the tail. If the */
/* cache is full, the oldest item is disassociated with its inode */
/* and it is moved to the had and associated with a new inode. */
typedef struct _acache {
struct _acache far *next;
struct _acache far *prev;
u_short inode;
struct nfsfattr fattr;
} Acache_t;
static Acache_t far *attrcache; /* Head and tail pointers */
static Acache_t far *attrfree;
/* The inode cache. */
typedef struct DIRNODE {
char name[MAXFILENAMELEN]; /* dos file name */
u_char fsid; /* drive of file (1 = A:) */
u_short inode; /* its inode number */
u_short top : 1, /* Flag indicating top of filesystem*/
gen : 14; /* generation count */
struct DIRNODE far *next; /* next file in same directory */
struct DIRNODE far *subdir; /* ptr to subdirectory entries */
struct DIRNODE far *parent; /* ptr to parent directory */
Acache_t far *attr; /* file attributes, if known */
} Dir_t;
/* the directory structure begins here */
static Dir_t far *RootDir = NULL;
/* the inode table - list of directory node pointers */
/* allocated on initialization */
typedef Dir_t far *Inode_t;
Inode_t far *InodeTable;
static u_short gencount = 1;
/*
* bool_t inode_init() --
* Initializes the inode module. Reads the previous (if any) inodes
* created and adds them to the directory tree. Has a very simple
* minded export file parser.
*/
bool_t inode_init()
{
FILE *fp;
char line[300];
char path[MAXPATHNAMELEN];
int i;
/* Initialize inode table */
if ((InodeTable = (Inode_t far *) _fmalloc (NUMINODES * 4)) == NULL)
return FALSE;
/* Initialize attributes cache */
if ((attrcache = (Acache_t far *) _fmalloc (NUMACACHE *
sizeof (Acache_t))) == NULL)
return FALSE;
/* The 0th entry is the list head; the free list starts at */
/* entry 1. */
attrcache->next = attrcache->prev = attrcache;
attrcache->inode = -1;
attrfree = &attrcache[1];
for (i = 0; i < NUMACACHE-2; i++)
attrfree[i].next = &attrfree[i+1];
attrfree[i].next = NULL;
/* Read export list to build initial inode tree */
if ((fp = fopen(EXPORTS, "r")) == NULL)
return FALSE;
while(fgets(line, MAXPATHNAMELEN -1, fp) == line) {
u_long nodeid;
/* get the pathname alone */
sscanf (line, "%s", path);
/* Truncate trailing backslash for root directory */
if (path[1] == ':' && path[3] == '\0')
path[2] = '\0';
/* Skip if shorter than 2 characters */
if (strlen(path) < 2)
break;
nodeid = insertapath(path, (Dir_t far *) NULL,
(Dir_t far * far *) &RootDir);
/* Set the top-of-filesystem flag */
InodeTable[nodeid]->top = TRUE;
}
(void) fclose(fp);
/* rebuild old filesystem tree */
/* open for reading and appending */
if ((fp = fopen(INODEFILE, "a+")) == NULL)
return FALSE;
while(fscanf(fp, "%s", path) != EOF) {
if (path[0] != '-')
(void) insertapath(path, (Dir_t far *) NULL,
(Dir_t far * far *) &RootDir);
else {
u_long nodeid;
sscanf (path+1, "%ld", &nodeid);
(void) _inremnode (nodeid);
}
}
(void) fclose(fp);
return TRUE;
}
/*
* void getcomp(char *comp, char **path) --
* Gets component name of *path and puts it in comp, and advances
* *path to beginning of next component. Handles UNIX or DOS style
* pathnames.
*/
/* Valid characters in a DOS name are: ! #$%&'() -. @ ^_` {}~ */
u_char inchvalid[95] = { 1, 0, 1, 1, 1, 1, 1, /* ! thru ' */
1, 1, 0, 0, 0, 1, 1, 0, /* ( thru / */
1, 1, 1, 1, 1, 1, 1, 1, /* 0 thru 7 */
1, 1, 0, 0, 0, 0, 0, 0, /* 8 thru ? */
1, 1, 1, 1, 1, 1, 1, 1, /* @ thru G */
1, 1, 1, 1, 1, 1, 1, 1, /* H thru O */
1, 1, 1, 1, 1, 1, 1, 1, /* P thru W */
1, 1, 1, 0, 0, 0, 1, 1, /* X thru _ */
1, 1, 1, 1, 1, 1, 1, 1, /* ` thru g */
1, 1, 1, 1, 1, 1, 1, 1, /* h thru o */
1, 1, 1, 1, 1, 1, 1, 1, /* p thru w */
1, 1, 1, 1, 0, 1, 1, 0}; /* x thru DEL */
static void getcomp(comp, path)
char *comp;
char **path;
{
if (! (**path > ' ' && !(**path & 0x80) && inchvalid[**path - '!']))
(*path)++;
while(**path > ' ' && !(**path & 0x80) && inchvalid[**path - '!']) {
*comp++ = **path;
(*path)++;
}
if (**path == ':')
(*path)++;
*comp = '\0';
}
/*
* Dir_t *makenewdirnode(char *name, Dir_t far *parent) --
* Returns new directory node initialized with name.
*/
Dir_t far *makenewdirnode(name, parent)
char *name;
Dir_t far *parent;
{
Dir_t far *new;
new = (Dir_t far *) _fmalloc(sizeof(Dir_t));
if (new == (Dir_t far *) NULL) {
(void) fprintf(stderr, "nfs: out of memory\n");
abort();
}
(void) bcopy_nf(name, new->name, MAXFILENAMELEN);
new->inode = (u_short) newinodeno();
new->parent = parent;
new->next = new->subdir = (Dir_t far *) NULL;
new->attr = (struct nfsfattr far *) NULL;
new->top = FALSE;
new->gen = gencount++;
if (parent == (Dir_t far *) NULL)
new->fsid = *name - (islower(*name) ? 'a' : 'A') + 1;
else
new->fsid = parent->fsid;
InodeTable[new->inode] = new;
return new;
}
/*
* void inremnode(u_long inode) --
* Removes the indicated node.
*/
void inremnode (inode)
u_long inode;
{
Dir_t far *dirp;
if (_inremnode (inode)) {
if (inodefp == (FILE *) NULL)
inodefp = fopen(INODEFILE, "a");
(void) fprintf(inodefp, "-%ld\n", inode); /* add to inode file */
}
/* else {
* DBGPRT1 (nfserr, "inremnode %ld failed", inode);
* }
*/
}
/*
* bool_t _inremnode(u_long inode) --
* Prunes an inode from the tree.
*/
static bool_t _inremnode (inode)
u_long inode;
{
Dir_t far *dirp, far *p, far *q;
if (inode > NUMINODES || (dirp = InodeTable[inode]) == (Dir_t far *) NULL)
return FALSE;
if (dirp->subdir != (Dir_t far *) NULL)
return FALSE;
/* If this is the first node in the list, simply point the parent */
/* to the next item. */
if (dirp->parent->subdir->inode == (u_short) inode) {
dirp->parent->subdir = dirp->next;
}
else {
/* Scan the list looking for inode */
p = dirp->parent->subdir->next; q = dirp->parent->subdir;
while(p != (Dir_t far *) NULL && p->inode != (u_short) inode) {
q = p; p = p->next;
}
/* Unlink this node from the list */
if (p == (Dir_t far *) NULL)
return FALSE;
q->next = p->next;
}
/* Free up the memory used by this inode and its attributes */
if (dirp->attr != (Acache_t far *) NULL) {
dirp->attr->prev->next = dirp->attr->next;
dirp->attr->next->prev = dirp->attr->prev;
dirp->attr->next = attrfree;
attrfree = dirp->attr;
}
(void) _ffree (dirp);
return TRUE;
}
/*
* Dir_t far *findindirlist(name, Dir_t far *parent, Dir_t far **dirlist) --
* Finds the node with name in dirlist and returns a ptr to it, or makes
* a new node if none is found, and returns a pointer to the new node.
*/
Dir_t far *findindirlist(name, parent, dirlist)
char *name;
Dir_t far *parent;
Dir_t far * far *dirlist;
{
int lexico; /* lexicographic comparator */
Dir_t far *new;
Dir_t far *p;
Dir_t far *q; /* for inserting down the list */
char str[MAXFILENAMELEN];
if (*dirlist == (Dir_t far *) NULL) { /* NULL entry */
*dirlist = makenewdirnode(name, parent);
return *dirlist;
}
bcopy_fn((*dirlist)->name, str, MAXFILENAMELEN);
if ((lexico = strcmp(name, str)) < 0) {
Dir_t far *tmp;
/* must insert in front */
new = makenewdirnode(name, parent);
tmp = *dirlist;
*dirlist = new;
new->next = tmp;
return new;
}
else if (lexico == 0) /* found the node */
return *dirlist;
/* cdr down the list and find node or find place to insert */
p = (*dirlist)->next; q = *dirlist;
while(p != (Dir_t far *) NULL) {
bcopy_fn((p)->name, str, MAXFILENAMELEN);
if ((lexico = strcmp(name, str)) == 0)
return p; /* found it */
else if (lexico < 0)
break; /* should insert here */
q = p; p = p->next; /* go on to next elt */
}
/* this is where we insert */
new = makenewdirnode(name, parent);
q->next = new;
new->next = p;
return new;
}
/*
* u_long insertapath(char *path, Dir_t far *parent, Dir_t far **dirlist)
* Inserts path into dirlist and returns final inode number.
*/
static u_long insertapath(path, parent, dirlist)
char *path;
Dir_t far *parent;
Dir_t far * far *dirlist;
{
char comp[MAXFILENAMELEN]; /* 11 is max length of one component */
Dir_t far *compnode; /* the component node */
getcomp(comp, &path); /* get component */
compnode = findindirlist(comp, parent, (Dir_t far * far *) dirlist);
if (*path == '\0') {
return (u_long) compnode->inode; /* no more descents needed */
} else
return insertapath(path, compnode, (Dir_t far * far *) &
(compnode->subdir));
}
/*
* u_long addpathtodirtree(char *path) --
* Adds a path to the directory tree and return it's inode number.
*/
u_long addpathtodirtree(path)
char *path;
{
u_long inode;
if (inodefp == (FILE *) NULL)
inodefp = fopen(INODEFILE, "a");
(void) fprintf(inodefp, "%s\n", path); /* add to inode file */
return insertapath(path, (Dir_t far *) NULL, (Dir_t far * far *) &RootDir);
return inode;
}
/*
* u_long ingetentry (u_long inode, u_long offset, char *name) --
* Finds the node at a given offset in dirlist and returns
* its name. Returns -1 if the node is invalid or the offset
* is too large.
*/
u_long ingetentry (inode, offset, name)
u_long inode;
u_long offset;
char *name;
{
Dir_t far *p, far *q; /* for scanning the list */
u_long x = offset;
if (inode > NUMINODES || InodeTable[inode] == (Dir_t far *) NULL)
return -1;
/* Handle first two entries specially. */
if (offset == 0) {
strcpy (name, ".");
return inode;
}
else if (offset == 1) {
strcpy (name, "..");
return InodeTable[inode]->top ? inode :
InodeTable[inode]->parent->inode;
}
offset -= 2;
if ((q = InodeTable[inode]->subdir) == NULL)
return -1;
p = q->next;
/* cdr down the list */
while (offset--) {
if (p != (Dir_t far *) NULL) {
q = p; p = p->next; /* go on to next elt */
}
else
return -1;
}
bcopy_fn (q->name, name, MAXFILENAMELEN);
/* DBGPRT3 (inode, "%ld offs %ld %s", inode, x, name); */
return (u_long) q->inode;
}
#if INODE_DEBUG
/*
* void shownode(Dir_t far *dirt) --
* Debugging aid. Dumps the node.
*/
static void shownode(dirt)
Dir_t far *dirt;
{
(void) printf("Name: %s;\t Inode #: %d\n", dirt->name, dirt->inode);
}
/*
* void showtree(Dir_t far *dirt) --
* Debugging aid. Dumps the tree.
*/
void showtree(dirt)
Dir_t far *dirt;
{
while(dirt != (Dir_t far *) NULL) {
shownode(dirt);
if (dirt->subdir != (Dir_t far *) NULL) {
(void) printf("And in this directory... \n");
showtree(dirt->subdir);
}
dirt = dirt->next;
}
}
#endif /* INODE_DEBUG */
/*
* u_long pntoin(char *path) --
* Returns inode number corresponding to path. Path should already
* exist. Returns -1 for error.
*/
#define isdot(path, len) (*((path) + (len) -1) == '.')
#define isdotdot(path, len) (isdot(path,len) && (*((path) + (len) - 2)) == '.')
u_long pntoin(path)
char *path;
{
char comp[MAXFILENAMELEN]; /* component of filename */
Dir_t far *p;
int len;
char str[MAXFILENAMELEN];
len = strlen(path);
if (isdotdot(path, len))
*(path + len -3) = '\0';
else if (isdot(path, len))
*(path + len -2) = '\0';
p = RootDir; /* start search from root */
while(p != (Dir_t far *) NULL) { /* search down the tree */
int lex;
getcomp(comp, &path); /* search across the tree */
while(p != (Dir_t far *) NULL) {
bcopy_fn((p)->name, str, MAXFILENAMELEN);
if ((lex = strcmp(comp, str)) == 0)
break;
else if (lex < 0) /* overshot - not found */
return -1;
p = p->next; /* across on this level */
}
if (p == (Dir_t far *) NULL)
return -1;
else if (*path == '\0')
return (u_long) p->inode;
else
p = p->subdir; /* down one level */
}
return -1;
}
/*
* char *intopn(u_long inode, char *path) --
* Converts inode to path name in dos format. DOS style path name
* is returned. A NULL is returned if there is no such inode.
*/
char *intopn(inode, path)
u_long inode;
char *path;
{
Dir_t far *dirp;
char *ptr;
u_short stack[30]; /* room for 30 nested directories */
u_short *stackptr;
if ((dirp = InodeTable[inode]) == (Dir_t far *) NULL)
return NULL;
/* move upwards and set parents to point to this child */
stackptr = stack;
while(dirp->parent != (Dir_t far *) NULL) {
*stackptr++ = dirp->inode;
dirp = dirp->parent; /* go to parent */
}
/* first get the drive name set up in path */
bcopy_fn((dirp->name), path, MAXFILENAMELEN);
ptr = path+1;
*ptr++ = ':';
while (--stackptr >= stack) {
*ptr++ = '\\';
bcopy_fn(InodeTable[*stackptr]->name, ptr, MAXFILENAMELEN);
while (*ptr) ptr++;
}
*ptr++ = '\0';
return path;
}
/*
* char *intoname(u_long inode) --
* Converts inode to name of file.
*/
char *intoname(inode)
u_long inode;
{
static char temname[MAXFILENAMELEN];
if (inode > NUMINODES)
return NULL;
bcopy_fn((InodeTable[inode])->name, temname, MAXFILENAMELEN);
return temname;
}
/*
* u_long parentinode(u_long inode)
* Returns inode number of parent.
*/
u_long parentinode(inode)
u_long inode;
{
Dir_t far *parent;
Dir_t far *dirp;
if (inode < NUMINODES && (dirp = InodeTable[inode])!=(Dir_t far *) NULL) {
if (dirp->top)
return inode;
else if ((parent = dirp->parent) != (Dir_t far *) NULL)
return (u_long) parent->inode;
}
return 0;
}
/*
* inattrset (u_long inode, struct nfsfattr *)
* Saves file attributes for a given inode.
*/
struct nfsfattr *inattrset (inode, attr)
u_long inode;
struct nfsfattr *attr;
{
Dir_t far *dirp;
if (inode > NUMINODES)
return (struct nfsfattr *) NULL;
if ((dirp = InodeTable[inode]) != (Dir_t far *) NULL) {
if (dirp->attr == (Acache_t far *) NULL) {
/* Allocate an attributes entry */
dirp->attr = attrfree;
if (dirp->attr == (struct nfsfattr far *) NULL) {
/* List is full: unlink the tail entry from its */
/* previously associated inode. */
dirp->attr = attrcache->prev;
InodeTable[dirp->attr->inode]->attr = NULL;
dirp->attr->prev->next = attrcache;
attrcache->prev = dirp->attr->prev;
}
else {
/* Unlink the entry from the free list. */
attrfree = attrfree->next;
}
/* Add the entry to the head of the active list. */
dirp->attr->next = attrcache->next;
dirp->attr->prev = attrcache;
attrcache->next->prev = dirp->attr;
attrcache->next = dirp->attr;
}
dirp->attr->inode = (u_short) inode;
(void) bcopy_nf(attr, &dirp->attr->fattr, sizeof (struct nfsfattr));
}
else
return (struct nfsfattr *) NULL;
}
/*
* inattrget (u_long inode, struct nfsfattr *)
* Fetches the attributes previously saved within a given inode.
*/
struct nfsfattr *inattrget (inode, attr)
u_long inode;
struct nfsfattr *attr;
{
Dir_t far *dirp;
if (inode > NUMINODES)
return (struct nfsfattr *) NULL;
if ((dirp = InodeTable[inode]) != (Dir_t far *) NULL) {
if (dirp->attr == (Acache_t far *) NULL)
return (struct nfsfattr *) NULL;
(void) bcopy_fn(&dirp->attr->fattr, attr, sizeof (struct nfsfattr));
/* Move entry to head of attributes cache */
if (dirp->attr != attrcache->next) {
dirp->attr->prev->next = dirp->attr->next;
dirp->attr->next->prev = dirp->attr->prev;
dirp->attr->next = attrcache->next;
attrcache->next->prev = dirp->attr;
attrcache->next = dirp->attr;
dirp->attr->prev = attrcache;
}
return (attr);
}
else
return (struct nfsfattr *) NULL;
}
/*
* ingetfsid (u_long inode)
* Fetches the filesystem ID (drive number) of an inode.
* Returns -1 if inode is undefined.
*/
int ingetfsid (inode)
u_long inode;
{
Dir_t far *dirp;
if (inode > NUMINODES || (dirp = InodeTable[inode]) == (Dir_t far *) NULL)
return -1;
return dirp->fsid;
}
/*
* u_long newinodeno() --
* Returns a new inode number, or aborts if we run out of inodes.
* A system cleanup must then occur.
*/
static u_long newinodeno()
{
if (lastinodeno > NUMINODES) {
DBGPRT0 (nfserr, "ran out of inodes");
(void) fprintf(stderr, "server err: out of inodes\n");
abort();
}
return lastinodeno++;
}
/*
* fhandle_t pntofh(char *path) --
* Converts path name to file handle. DOS or UNIX style paths.
*/
fhandle_t pntofh(path)
char *path;
{
u_long inodeno;
fhandle_t fh;
Dir_t far *dirp;
(void) bzero(&fh, sizeof(fhandle_t));
if ((inodeno = pntoin(path)) == -1)
inodeno = addpathtodirtree(path);
dirp = InodeTable[inodeno];
fh.f.fh_fno = inodeno;
fh.p.fh_fno = (dirp->top ? inodeno : dirp->parent->inode);
fh.f.fh_fsid = fh.p.fh_fsid = (dev_t) dirp->fsid;
fh.f.fh_fgen = (time_t) dirp->gen;
(void) bcopy_fn(dirp->name, fh.fh_pn, MAXFILENAMELEN);
return fh;
}
/*
* bool_t checkfh (fhandle_t *fhp) --
* Checks whether the given fhandle is still valid (it may not
* be if the inode number has been recycled).
*/
bool_t checkfh (fhp)
fhandle_t *fhp;
{
u_long inode;
Dir_t far *dirp;
inode = fhp->f.fh_fno;
if (inode > NUMINODES || (dirp = InodeTable[inode]) == NULL)
return FALSE;
if (fhp->p.fh_fno != (dirp->top ? inode : dirp->parent->inode) ||
dirp->fsid != (u_char) fhp->f.fh_fsid ||
dirp->gen != (u_short) fhp->f.fh_fgen) {
DBGPRT3 (nfserr, "checkfh: node %ld gen %d/%d", inode,
(int) fhp->f.fh_fgen, dirp->gen);
return FALSE;
}
else
return TRUE;
}
#ifdef INODE_DEBUG
main()
{
char *s, path[MAXPATHNAMELEN];
addpathtodirtree("/c/bin/test");
addpathtodirtree("/d/stan/src/unfsd");
addpathtodirtree("/c/bin/testee");
addpathtodirtree("/d/stan/src/unfsd");
addpathtodirtree("/d/stan/src/unfsd/tester");
showtree(RootDir);
(void) printf("pntoin /d/stan/src is %ld\n", pntoin("/d/stan/src"));
s = intopn(7, path);
(void) printf("intopn 7 : %s\n", s);
(void) free(s);
s = intopn(7, path);
(void) printf("intopn 7 : %s\n", s);
}
#endif