home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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
-