/* mfile.c - a program to permit arbitrary numbers of concurrently * open files */ #include #include "dequeue.h" /* dequeue package */ #define lruMFS lastNode /* dequeue macros */ #define mruMFS firstNode #define ERROR -1 /* a test for valid internal fd - used to try to catch user errors */ #define validMFS(x,y) ((y->mfdNum) == x) extern long lseek(); #define MAXFILES 60 /* this value can be arbitrarily large */ #define MAXOPEN 12 /* this is the number of files the host handles */ #define OK 1 typedef int EFD; /* host system file descriptor */ typedef int MFD; /* internal file descriptor */ typedef struct mfS { /* dequeue structure */ struct mfS *pMFS, *nMFS; int mfdNum; /* internal file descriptor data */ int status; int efd; /* currency data */ char fname[65]; long lpos; } MFS; /* various file statuses - used in mfS.status to determine validity of element and operations */ #define OPEN 1 #define CLOSED 2 #define UNASSIGNED 0 #define EMPTY -1 /* signals out of internal fd */ #define UNINIT -2 /* signals intialization needed */ /* hide some internal details unless debugging */ #if defined DEBUG #define Static #else #define Static static #endif Static MFS *mFiles[MAXFILES]; /* list of all internal fd */ Static MFD mfdFree = UNINIT; /* empty free list */ Static unsigned numOpen = 0; /* number of currently open files */ /* * (semi) standard low level file primitives */ MFD mOpen(fname, mode) char *fname; int mode; { int temp; obtainEFD(); /* ensure 1 host fd is free */ temp = mfdCreate( open(fname, mode) ); #if defined(DEBUG) printf("open:%s to mfd %d\n",fname,temp); dump(mFiles[temp]); #endif if (temp < 0) return ERROR; numOpen++; strcpy(mFiles[temp]->fname, fname); /* establish currency */ return(temp); } MFD mCreate(fname, mode) char *fname; int mode; { int temp; obtainEFD(); temp = mfdCreate( create(fname, mode, 0) ); #if defined(DEBUG) printf("create: %s to mfd %d\n",fname,temp); dump(mFiles[temp]); #endif if (temp < 0) return ERROR; numOpen++; strcpy(mFiles[temp]->fname, fname); return(temp); } int mClose(mfd) MFD mfd; { MFS *mfs; #if defined(DEBUG) printf("mClose:"); dump(mFiles[mfd]); #endif mfs = mFiles[mfd]; if (validMFS(mfd, mfs)) { if (mfs->status == OPEN) { if (close(mfs->efd) < 0) return ERROR; numOpen--; } mfdDestroy(mfd); return 0; } else return ERROR; } int mRead(mfd,buf,cnt) MFD mfd; char *buf; int cnt; { #if defined(DEBUG) int tmp; printf("mRead(%d,%04x,%d) - %d\n", mfd, buf, cnt, tmp = read(mReopen(mfd), buf, cnt) ); return tmp; #else return read(mReopen(mfd), buf, cnt); #endif } int mWrite(mfd,buf,cnt) MFD mfd; char *buf; int cnt; { #if defined(DEBUG) int tmp; printf("mWrite(%d,%04x,%d) - %d\n", mfd, buf, cnt, tmp = write(mReopen(mfd), buf, cnt) ); return tmp; #else return write(mReopen(mfd), buf, cnt); #endif } long mlseek(mfd, offs, mode) MFD mfd; long offs; int mode; { #if defined(DEBUG) long tmp; printf("mlseek(%d,%ld,%d) - %d\n", mfd, offs, mode, tmp = lseek(mReopen(mfd), offs, mode) ); return tmp; #else return lseek(mReopen(mfd), offs, mode); #endif } /* Low level internal functions */ /* get host file descriptor for file, closing other files if need to. */ EFD mReopen(mfd) MFD mfd; { register MFS *mfs; mfs = mFiles[mfd]; if (validMFS(mfd,mfs)) /* check fd is valid */ { #if defined(DEBUG) printf("mReopen:"); dump(mfs); #endif switch(mfs->status) /* what is current real file status */ { case OPEN: /* file is currently open */ mSplice(mfs); /* make this most recently used */ #if defined(DEBUG) printf("mReopen:"); dump(mfs); #endif return mfs->efd; case CLOSED: /* file needs to be reOpened */ if (obtainEFD()) { mEnQue(mfs); /* put on open list */ mRestore(mfs); /* restore currency */ #if defined(DEBUG) printf("mReopen:"); dump(mfs); #endif return mfs->efd; } else return ERROR; default: return ERROR; } } else return ERROR; } /* routine to ensure at least one host file descriptor is available ie: after x = obtainEFD(), numOpen < MAXOPEN or x == 0; */ Static int obtainEFD() { MFS *oMfs; if (numOpen < MAXOPEN) /* still unused space */ return OK; oMfs = lruMFS; /* get least recently used file */ #if defined(DEBUG) printf("obtainEFD: lruMFD %d\n",oMfs->mfdNum); #endif /* save currency info and close file */ if (mSave(oMfs)) { /* successfully freed up one host fd */ oMfs->status = CLOSED; close(oMfs->efd); mDeQue(oMfs); /* remove lru file from active queue */ return OK; } return 0; /* failed to close file */ } /* mSave() - store currency information prior to temporary file closure ** you will no doubt have a better way to do this on ** your system, but it would make the package non portable. ** changing this to grab lpos and name from low level fd ** would speed it up. */ Static int mSave(mfs) MFS *mfs; { /* save currency information */ sync(); /* flush buffers to disk - optional */ /* >>>NOTE<<< this will not work for non-seekable devices (e.g. keyboards, printers, crts &tc */ mfs->lpos = lseek(mfs->efd, 0L, 1); if (close(mfs->efd) < 0) return 0; numOpen--; return OK; } /* restore currency information */ Static EFD mRestore(mfs) MFS *mfs; { int temp; mfs->efd = open(mfs->fname,0); if (mfs->efd >= 0) { if (mfs->lpos != -1L) /* may be at start of file anyway */ mfs->lpos = lseek(mfs->efd, mfs->lpos, 0); mfs->status = OPEN; numOpen++; } else mfs->status = ERROR; return mfs->efd; } Static MFD mfdCreate(efd) EFD efd; { MFD mfd; register MFS *mfs; char *malloc(); if (efd < 0) return ERROR; if (mfdFree < 0) if (mfdFree == EMPTY) /* out of file slots */ return ERROR; else mInit(); /* initialise fd array */ mfd = mfdFree; mfs = (MFS *) malloc(sizeof(MFS)); if (mfs == NULL) /* out of space for file details */ return ERROR; mfdFree = mFiles[mfdFree]; /* pop free slot stack */ mFiles[mfd] = mfs; /* assoc mfs with mfd */ mfs->mfdNum = mfd; /* assoc mfd with mfs */ mfs->efd = efd; /* assoc eon fd with mfs */ mfs->status = OPEN; /* flag status as open */ (mfs->nMFS) = (mfs->pMFS) = UNINIT; /* not on any queue yet */ mfs->fname[0] = '\0'; /* no file name yet */ mfs->lpos = -1L; /* no position yet */ mEnQue(mfs); /* put mfs as most recently used */ return mfd; /* return file slot number */ } Static int mfdDestroy(mfd) MFD mfd; { MFS *mfs; mfs = mFiles[mfd]; if (validMFS(mfd,mfs)) { if ( (mfs->status) == OPEN ) mDeQue(mfs); free(mfs); mFiles[mfd] = mfdFree; mfdFree = mfd; } else return ERROR; } mInit() { int i; for (i = 0; imfdNum, ( (f->status == 1) ? "OPEN" : (f->status == 2) ? "CLOSED" : (f->status == 0) ? "UNASSIGNED" : (f->status ==-1) ? "ERROR" : "???" ), f->efd, f->pMFS, f->nMFS, f->fname, f->lpos); } #endif /* end of mfile.c */