#include "dos.h" extern PORT *DosPort; /* Our DOS port... this is slick... */ extern PROC *DosProc; /* Our Process */ extern DEVNODE *DosNode; /* Our DOS node.. created by DOS for us */ extern DEVLIST *DevList; /* Device List structure for our volume node */ extern void *SysBase; /* EXEC library base */ extern DOSLIB *DOSBase; /* DOS library base for debug process */ extern RAMFILE RFRoot; /* Directory/File structure (root node) */ extern LIST FHBase; /* Open Files */ extern LIST LCBase; /* Open Locks */ extern long TotalBytes; /* total bytes of data in filesystem */ extern RAMFILE xpath; /* This is used in case of off device path */ extern char *buf1; /* This holds the translated path names */ RAMFILE * checkoutpath(); RAMFILE * vsearchpath(); void *DeviceProc(); /* * PACKET ROUTINES. Dos Packets are in a rather strange format as you * can see by this and how the PACKET structure is extracted in the * GetMsg() of the main routine. */ void returnpacket(packet) register struct DosPacket *packet; { register struct Message *mess; register struct MsgPort *replyport; replyport = packet->dp_Port; mess = packet->dp_Link; packet->dp_Port = DosPort; mess->mn_Node.ln_Name = (char *)packet; mess->mn_Node.ln_Succ = NULL; mess->mn_Node.ln_Pred = NULL; PutMsg(replyport, mess); } /* * Are there any packets queued to our device? */ packetsqueued() { return ((void *)DosPort->mp_MsgList.lh_Head != (void *)DosPort->mp_MsgList.lh_Tail); } /* * DOS MEMORY ROUTINES * * DOS makes certain assumptions about LOCKS. A lock must minimally be * a FileLock structure, with additional private information after the * FileLock structure. The longword before the beginning of the structure * must contain the length of structure + 4. * * NOTE!!!!! The workbench does not follow the rules and assumes it can * copy lock structures. This means that if you want to be workbench * compatible, your lock structures must be EXACTLY sizeof(struct FileLock). */ void * dosalloc(bytes) register ulong bytes; { register ulong *ptr; bytes += 4; ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR); *ptr = bytes; return(ptr+1); } dosfree(ptr) register ulong *ptr; { --ptr; FreeMem(ptr, *ptr); } /* * Convert a BSTR into a normal string.. copying the string into buf. * I use normal strings for internal storage, and convert back and forth * when required. */ void btos(bstr,buf) ubyte *bstr; ubyte *buf; { bstr = BTOC(bstr); bmov(bstr+1,buf,*bstr); buf[*bstr] = 0; } /* * Some EXEC list handling routines not found in the EXEC library. */ void * NextNode(node) NODE *node; { node = node->mln_Succ; if (node->mln_Succ == NULL) return(NULL); return(node); } void * GetHead(list) LIST *list; { if ((void *)list->mlh_Head != (void *)&list->mlh_Tail) return(list->mlh_Head); return(NULL); } /* * Compare two names which are at least n characters long each, * ignoring case. */ nccmp(p1,p2,n) register ubyte *p1, *p2; register short n; { while (--n >= 0) { if ((p1[n]|0x20) != (p2[n]|0x20)) return(0); } return(1); } /* * Create a file or directory and link it into it's parent directory. */ RAMFILE * createramfile(parentdir, type, name) RAMFILE *parentdir; char *name; { register RAMFILE *ramfile; ramfile = AllocMem(sizeof(RAMFILE), MEMF_CLEAR|MEMF_PUBLIC); AddTail(&parentdir->list, ramfile); ramfile->parent = parentdir; ramfile->name = AllocMem(strlen(name)+1, MEMF_PUBLIC); strcpy(ramfile->name, name); ramfile->type = type; ramfile->protection = 0; NewList(&ramfile->list); DateStamp(&ramfile->date); DateStamp(&ramfile->parent->date); return(ramfile); } /* * Free all data associated with a file */ void freedata(ramfile) RAMFILE *ramfile; { FENTRY *fen; TotalBytes -= ramfile->bytes; while (fen = RemHead(&ramfile->list)) { /*DB*/ dbprintf("FREE FEN: %08lx %08lx %ld\n", fen, fen->buf, fen->bytes); FreeMem(fen->buf, fen->bytes); FreeMem(fen, sizeof(*fen)); } ramfile->bytes = 0; DateStamp(&ramfile->date); DateStamp(&ramfile->parent->date); } /* * Unlink and remove a file. Any data associated with the file or * directory has already been freed up. */ void freeramfile(ramfile) RAMFILE *ramfile; { Remove(ramfile); /* unlink from parent directory */ if (ramfile->name) FreeMem(ramfile->name,strlen(ramfile->name)+1); if (ramfile->comment) FreeMem(ramfile->comment,strlen(ramfile->comment)+1); FreeMem(ramfile,sizeof(*ramfile)); } /* * The lock function. The file has already been checked to see if it * is lockable given the mode. */ LOCK * ramlock(ramfile, mode) RAMFILE *ramfile; { LOCK *lock = dosalloc(sizeof(LOCK)); LOCKLINK *ln; if (mode != ACCESS_WRITE) mode = ACCESS_READ; ln = AllocMem(sizeof(LOCKLINK), MEMF_PUBLIC); AddHead(&LCBase,ln); ln->lock = lock; lock->fl_Link= (long)ln; lock->fl_Key = (long)ramfile; lock->fl_Access = mode; lock->fl_Task = DosPort; lock->fl_Volume = (BPTR)CTOB(DosNode); if (mode == ACCESS_READ) ++ramfile->locks; else ramfile->locks = -1; return(lock); } void ramunlock(lock) LOCK *lock; { RAMFILE *file = (RAMFILE *)lock->fl_Key; Remove(lock->fl_Link); /* unlink from list */ FreeMem(lock->fl_Link, sizeof(LOCKLINK)); /* free link node */ if (lock->fl_Access == ACCESS_READ) /* undo lock effect */ --file->locks; else file->locks = 0; dosfree(lock); /* free lock */ } /* * GETLOCKFILE(bptrlock) * * Return the RAMFILE entry (file or directory) associated with the * given lock, which is passed as a BPTR. * * According to the DOS spec, the only way a NULL lock will ever be * passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure. * In anycase, If a NULL lock is passed to me I simply assume it means * the root directory of the RAM disk. */ RAMFILE * getlockfile(lock) void *lock; /* actually BPTR to LOCK */ { register LOCK *rl = BTOC(lock); if (rl) return((RAMFILE *)rl->fl_Key); return(&RFRoot); } /* * Search the specified path beginning at the specified directory. * The directory pointer is updated to the directory containing the * actual file. Return the file node or NULL if not found. If the * path is illegal (an intermediate directory was not found), set *ppar * to NULL and return NULL. * * *ppar may also be set to NULL if the search path IS the root. * * If pptr not NULL, Set *pptr to the final component in the path. */ char *rindex(); RAMFILE * searchpath(ppar,buf,pptr) RAMFILE **ppar; char *buf; char **pptr; { RAMFILE *file = *ppar; RAMFILE *srch; short len; char *ptr; ptr = rindex(buf,':'); if (ptr) buf = ptr+1; *ppar = NULL; for (;*buf && file;) { ptr = getpathelement(&buf,&len); if (*ptr == '/') { /* go back a directory */ if (!file->parent) { /* no parent directory */ return(NULL); } file = file->parent; continue; } if (file->type == FILE_FILE) return(checkoutpath(file,ptr)); for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) { if (srch->type && strlen(srch->name) == len && nccmp(srch->name, ptr, len)) { file = srch; /* element found */ break; } } if (srch == NULL) { if (*buf == 0) /* Element not found. If it was the final */ *ppar = file; /* element the parent directory is valid */ if (pptr) *pptr = ptr; return(NULL); } } if (pptr) *pptr = ptr; *ppar = file->parent; return(file); } RAMFILE * vsearchpath(ppar,buf,pptr) RAMFILE **ppar; char *buf; char **pptr; { RAMFILE *file = *ppar; RAMFILE *srch; short len; char *ptr; ptr = rindex(buf,':'); /* this fixes up the colon treatment */ if (ptr) buf = ptr+1; *ppar = NULL; for (;*buf && file;) { ptr = getpathelement(&buf,&len); if (*ptr == '/') { /* go back a directory */ if (!file->parent) { /* no parent directory */ return(NULL); } file = file->parent; continue; } if (file->type == FILE_FILE) return(NULL); for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) { if (srch->type && strlen(srch->name) == len && nccmp(srch->name, ptr, len)) { file = srch; /* element found */ break; } } if (srch == NULL) { if (*buf == 0) /* Element not found. If it was the final */ *ppar = file; /* element the parent directory is valid */ if (pptr) *pptr = ptr; return(NULL); } } if (pptr) *pptr = ptr; *ppar = file->parent; return(file); } typedef struct { FENTRY *fentry; long offset; } SFH; /* simple file handle */ RAMFILE * checkoutpath(file,path) RAMFILE *file; char *path; { SFH fh; int lck; fh.fentry = GetHead(&file->list); fh.offset = 0; while (getnexttry(&fh,buf1)) { strcat(buf1,path); if (DeviceProc(buf1) == DosPort) { /* refers to us.. ignore */ continue; } if (!index(buf1,':')) { /* not an absolute path */ continue; } if (lck = Lock(buf1,ACCESS_READ)) { UnLock(lck); return(&xpath); } } return(0); } getnexttry(fh,buf) register SFH *fh; register char *buf; { register int i; register FENTRY *fe; fe = fh->fentry; i = fh->offset; for (fe = fh->fentry; fe ; fe = NextNode(fe)) { for (; ibytes; i++) { *buf = fe->buf[i]; if (*buf == '\n') { *buf = 0; fh->fentry = fe; fh->offset = ++i; return(1); } buf++; } i=0; } return(0); } /* * Return the next path element in the string. The routine effectively * removes any trailing '/'s, but treats ':' as part of the next component * (i.e. ':' is checked and skipped in SEARCHPATH()). */ char * getpathelement(pstr,plen) char **pstr; short *plen; { char *base; register char *ptr = *pstr; register short len = 0; if (*(base = ptr)) { if (*ptr == '/') { ++ptr; ++len; } else { while (*ptr && *ptr != '/') { ++ptr; ++len; } if (*ptr == '/') ++ptr; } } *pstr = ptr; *plen = len; return(base); } char * typetostr(ty) { switch(ty) { case ACTION_DIE: return("DIE"); case ACTION_OPENRW: return("OPEN-RW"); case ACTION_OPENOLD: return("OPEN-OLD"); case ACTION_OPENNEW: return("OPEN-NEW"); case ACTION_READ: return("READ"); case ACTION_WRITE: return("WRITE"); case ACTION_CLOSE: return("CLOSE"); case ACTION_SEEK: return("SEEK"); case ACTION_EXAMINE_NEXT: return("EXAMINE NEXT"); case ACTION_EXAMINE_OBJECT: return("EXAMINE OBJ"); case ACTION_INFO: return("INFO"); case ACTION_DISK_INFO: return("DISK INFO"); case ACTION_PARENT: return("PARENTDIR"); case ACTION_DELETE_OBJECT: return("DELETE"); case ACTION_CREATE_DIR: return("CREATEDIR"); case ACTION_LOCATE_OBJECT: return("LOCK"); case ACTION_COPY_DIR: return("DUPLOCK"); case ACTION_FREE_LOCK: return("FREELOCK"); case ACTION_SET_PROTECT: return("SETPROTECT"); case ACTION_SET_COMMENT: return("SETCOMMENT"); case ACTION_RENAME_OBJECT: return("RENAME"); case ACTION_INHIBIT: return("INHIBIT"); case ACTION_RENAME_DISK: return("RENAME DISK"); case ACTION_MORECACHE: return("MORE CACHE"); case ACTION_WAIT_CHAR: return("WAIT FOR CHAR"); case ACTION_FLUSH: return("FLUSH"); case ACTION_RAWMODE: return("RAWMODE"); default: return("---------UNKNOWN-------"); } }