changeset 44:b26c23331d02

add more function on vdisk
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Thu, 19 Jul 2018 11:31:17 +0900
parents 7a83a6a1685a
children 07c84761da6f
files Makefile io.c v09.h vdisk.c
diffstat 4 files changed, 614 insertions(+), 292 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Tue Jul 17 17:08:09 2018 +0900
+++ b/Makefile	Thu Jul 19 11:31:17 2018 +0900
@@ -22,7 +22,7 @@
 # will be installed to ".."
 BIN=a09 v09 v09c d09 $(SIM_BIN) v09.rom 
 
-TARGETS=$(BIN) $(APPS)
+TARGETS=$(BIN) $(APPS)  vdisk.o
 
 OTHER=monitor.s makerom
 
@@ -58,6 +58,9 @@
 io.o: io.c 
 	$(CC) -c $(CFLAGS) $(V09FLAGS) $<
 
+vdisk.o: vdisk.c v09.h
+	$(CC) -c $(CFLAGS) $(V09FLAGS) $< 
+
 trace.o: trace.c v09.h
 	$(CC) -c $(CFLAGS) $(V09FLAGS) $< 
 
--- a/io.c	Tue Jul 17 17:08:09 2018 +0900
+++ b/io.c	Thu Jul 19 11:31:17 2018 +0900
@@ -71,7 +71,7 @@
  *   IOPAGE + 0x31-  YY/MM/DD/HH/MM/SS
  *
  *   IOPAGE + 0x40   Disk control        0x81 read/0x55 write   0 ... ok / 0xff .. error
- *   IOPAGE + 0x41   drive no
+ *   IOPAGE + 0x41   drive no / ( VDISK  0 for system, 1 for user )
  *   IOPAGE + 0x42   LSN2
  *   IOPAGE + 0x43   LSN1
  *   IOPAGE + 0x44   LSN0
@@ -106,8 +106,12 @@
 #ifdef USE_MMU
 extern char *prog ;   // for disass
 extern Byte * mem0(Byte *iphymem, Word adr, Byte *immu) ;
+#define pmem(a)  mem0(phymem,a,mmu)
+#else
+#define pmem(a)  (&mem[a])
 #endif
 
+
 extern int bpskip ;
 extern int stkskip ;
 extern FILE *logfile;
@@ -307,6 +311,7 @@
    }
 }
 
+
 void do_disk(int a, int c) {
    if (a!=0x40+(IOPAGE&0x1ff)) {
       mem[(IOPAGE&0xfe00)+a]=c;
@@ -316,17 +321,17 @@
    int lsn = (mem[IOPAGE+0x42]<<16) + (mem[IOPAGE+0x43]<<8) + mem[IOPAGE+0x44];
    int buf = (mem[IOPAGE+0x45]<<8) + mem[IOPAGE+0x46];
    if (drv > 1 || disk[drv]==0) goto error;
-#ifdef USE_MMU
-   Byte *phy = mem0(phymem,buf,mmu);
-#else
-   Byte *phy = &mem[buf];
-#endif
+   Byte *phy = pmem(buf);
    if (c==0x81) {
       if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error;
       if (read(fileno(disk[drv]),phy,SECSIZE)==-1) goto error;
    } else if (c==0x55) {
       if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error;
       if (write(fileno(disk[drv]),phy,SECSIZE)==-1) goto error;
+#ifdef VDISK
+   } else  {
+       do_vdisk(c);
+#endif
    }
    mem[IOPAGE+0x40] = 0;
    return;
--- a/v09.h	Tue Jul 17 17:08:09 2018 +0900
+++ b/v09.h	Thu Jul 19 11:31:17 2018 +0900
@@ -7,6 +7,8 @@
 
 */
 
+#include <stdio.h>
+
 typedef unsigned char Byte;
 typedef unsigned short Word;
 
--- a/vdisk.c	Tue Jul 17 17:08:09 2018 +0900
+++ b/vdisk.c	Thu Jul 19 11:31:17 2018 +0900
@@ -5,341 +5,653 @@
 *         GPL v1 license
 */
 
+#define engine extern
+#include "v09.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/select.h>
+#include <dirent.h>
+#include <string.h>
 
 
-/****************************
-*
-* Main entry point for RBF
-*
-         lbra  Open
-         lbra  MakDir
-         lbra  ChgDir
-         lbra  Delete
-         lbra  Seek
-         lbra  Read
-         lbra  Write
-         lbra  ReadLn
-         lbra  WriteLn
-         lbra  GetStat
-         lbra  SetStat
-         lbra  Close
- */
+#ifdef USE_MMU
+extern char *prog ;   // for disass
+extern Byte * mem0(Byte *iphymem, Word adr, Byte *immu) ;
+#define pmem(a)  mem0(phymem,a,mmu)
+#define umem(a)  (mem[0x41+IOPAGE]?mem0(phymem,a,&mem[0x21+IOPAGE]):mem0(phymem,a,&mem[0x20+IOPAGE]))
+#else
+#define pmem(a)  (&mem[a])
+#define umem(a)  (&mem[a])
+#endif
+
+#define MAXPDV 256
+
+typedef struct pathDesc {
+    char *name;
+    FILE *fp;
+    int mode;
+    int inode ;  // lower 24 bit of unix inode, os9 lsn
+    int num ;
+    char use ;
+    char dir;
+    char *fd ;
+    char *dirfp;
+} PathDesc, *PathDescPtr;
 
 
-/*
-* I$Create Entry Point
-*
-* Entry: A = access mode desired
-*        B = file attributes
-*        X = address of the pathlist
-*
-* Exit:  A = pathnum
-*        X = last byte of pathlist address
-*
-* Error: CC Carry set
-*        B = errcode
-*/
+PathDesc pdv[MAXPDV];
+
+PathDesc *findPD() {
+    for(int i=0;i<MAXPDV;i++) {
+        if (!pdv[i].use) {
+            pdv[i].use = 1;
+            pdv[i].num = i;
+            pd[i].mode = 0;
+            pd[i].fp = 0;
+            pd[i].dirfp = 0;
+            pd[i].name = 0;
+            pd[i].fd = 0;
+            return &pdv[i];
+        }
+    }
+    return 0;
+}
+
+void closepd(PathDesc *pd) {
+    int err = fclose(pd->fp) ;
+    pd->use = 0;
+    pd->fp = 0;
+    pd->mode = 0;
+    free(pd->dirfp); pd->dirfp = 0;
+    free(pd->name); pd->name = 0;
+    free(pd->fd); pd->fd = 0;
+}
 
 #define MAXPAHTLEN 256
 
-char * checkFileName(char *path, PathDesc *pd) {
+char *addCurdir(char *name, PathDesc *curdir) {
+    int ns = strlen(name);
+    int ps = ns;
+    int ds=0 ;
+    if (curdir==0 && name[0]!='/') return 0; // no current directory
+    if (name[0]!='/') ps += (ds=strlen(curdir->name))+1;
+    char *path = (char*)malloc(ps+1);
+    int i = 0;
+    if (ds) {
+        for(;i<ds;i++) path[i] = curdir->name[i];
+        path[i++] = '/';
+    }
+    for(int j=0;j<ns;j++,i++) path[i] = name[j];
+    path[i++] = 0;
+    return path;
+}
+
+char * checkFileName(char *path, PathDesc *pd, PathDesc *curdir) {
     char *p = path;
+    char *name = path;
     int maxlen = MAXPAHTLEN;
-    pd->lastChar = p;
     while(*p!=0 && (*p&80)==0 && maxlen-->0) p++;
     if (maxlen==MAXPAHTLEN) return 0;
-    pd->lastChar = p;
     if (*p!=0) {
-        p = (char *)malloc(len+1); 
+        name = (char *)malloc(p-path+1); 
         strncpy(path,p, MAXPAHTLEN-maxlen);
     }
+    char *name1 = addCurdir(name,curdir);
+    if (name1!=name && name1!=path) free(name);
+    pd->name = name1;
     return p;
 }
 
-int os9toUnixAttr(Byte attr) {
-    return "r+";
-}
-
-int vrbf_create(byte mode,Byte attr,char *path,PathDesc *pd) {
-    char *p = pd->unixName  = checkFileName(path,pd);
-    if (p==0) return -1;
-    p->dir = 0;
-    p->fp = fopen(p->unixName,"w+"); // os9toUnixAttr(attr));
-    if  (fd) return 0;
-    return -1;
+void os9setmode(char &os9mode,int mode) {
+    char m = 0;
+    if (mode&S_IFDIR) m|=0x80;
+    if (mode&S_IRUSR) m|=0x01;
+    if (mode&S_IWUSR) m|=0x02;
+    if (mode&S_IXUSR) m|=0x04;
+    if (mode&S_IROTH) m|=0x08;
+    if (mode&S_IWOTH) m|=0x10;
+    if (mode&S_IXOTH) m|=0x20;
+    m|=0x60; // always sharable
+    *os9mode = m;
 }
 
-
-/*
-* I$Open Entry Point
-*
-* Entry: A = access mode desired
-*        X = address of the pathlist
-*
-* Exit:  A = pathnum
-*        X = last byte of pathlist address
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_open(byte mode,char *path, PathDesc *pd) {
-    char *p = pd->unixName = checkFileName(path,pd);
-    if (p==0) return -1;
-    struct stat buf;
-    if (stat(p,&buf)!=0) return -1;
-    if ((buf.st_mode & S_IFMT) == S_IFDIR) {
-        pd->dir = 1;
-        return 0;
-    }
-    pd->dir = 0;
-    pd->fp = fopen(p->unixName,"r"); // os9toUnixAttr(attr));
-    if  (fp) return 0;
-    return -1;
-}
-
-
-/*
-* I$MakDir Entry Point
-*
-* Entry: X = address of the pathlist
-*
-* Exit:  X = last byte of pathlist address
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_mkdir(char **path,PathDesc *pd) {
-    char *p = checkFileName(path,pd);
-    if (p==0) return -1;
-    return mkdir(p,0);
+char * os9toUnixAttr(Byte attr) {
+    if ((attr&0x1) && (attr&0x2)) return "r+";
+    if (!(attr&0x1) && (attr&0x2)) return "w";
+    if ((attr&0x1) && !(attr&0x2)) return "r";
+    return "r";
 }
 
 /*
-* I$ChgDir Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
+ *   os9 file descriptor
+ *   * File Descriptor Format
+ *
+ * The file descriptor is a sector that is present for every file
+ * on an RBF device.  It contains attributes, modification dates,
+ * and segment information on a file.
+ *
+ *               ORG       0
+ *FD.ATT         RMB       1                   Attributes
+ *FD.OWN         RMB       2                   Owner
+ *FD.DAT         RMB       5                   Date last modified
+ *FD.LNK         RMB       1                   Link count
+ *FD.SIZ         RMB       4                   File size
+ *FD.Creat       RMB       3                   File creation date (YY/MM/DD)
+ *FD.SEG         EQU       .                   Beginning of segment list
+ * Segment List Entry Format
+               ORG       0
+ * FDSL.A         RMB       3                   Segment beginning physical sector number
+ * FDSL.B         RMB       2                   Segment size
+ * FDSL.S         EQU       .                   Segment list entry size
+ * FD.LS1         EQU       FD.SEG+((256-FD.SEG)/FDSL.S-1)*FDSL.S
+ * FD.LS2         EQU       (256/FDSL.S-1)*FDSL.S
+ * MINSEC         SET       16
+ */
 
-char * vrbf_chdir(char *path) {
-    cahr *p = checkFileName(path);
-    if (p==0) return -1;
-    struct stat buf;
-    if (stat(p,&buf)!=0) return -1;
-    if ((buf.st_mode & S_IFMT) == S_IFDIR) {
-        chdir(p);
-        return p;
-    } 
-    return -1;
-}
+/*
+ *   os9 directory structure
+ *
+ *               ORG       0
+ *DIR.NM         RMB       29                  File name
+ *DIR.FD         RMB       3                   File descriptor physical sector number
+ *DIR.SZ         EQU       .                   Directory record size
+ */
 
 
-/*
-* I$Delete Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_delete(char *path) {
-    cahr *p = checkFileName(path);
-    if (p==0) return -1;
-    return rmdir(p);
+/* read direcotry entry */
+int os9opendir(PathDesc pd) {
+    DIR *dir;
+    struct dirent *dp;
+    dir = opendir(pd->name);
+    pd->name=fname;
+    int dircount = 0;
+    while ((dp = readdir(dirp)) != NULL) dircout++;   // pass 1 to determine the size
+    if (dircount==0) return 0;  // should contains . and .. at least
+    pd->sz = dircount*DIR_SZ
+    pd->dirfp = (char *)malloc(dircount*DIR_SZ);
+    rewinddir(dir);
+    int i = 0;
+    while ((dp = readdir(dirp)) != NULL) {
+        i += DIR_SZ;
+        if (i>pd->SZ) return 0;
+        int j = 0;
+        for(j = 0; j < DIR_NM ; j++) {
+            if (j< dp->d_namlen) 
+               pd->dirfp[j] = dp->d_name[j];
+            else
+               pd->dirfp[j] = 0;
+        }
+        pd->dirfp[j] = (d_ino&0xff0000)>>16;
+        pd->dirfp[j+1] = (d_ino&0xff00)>>8;
+        pd->dirfp[j+2] = d_ino&0xff;
+    }
+    pd->fp = fmemopen(pd->dirfp,pd->sz,"r");
+    return 0;
 }
 
 
-/*
-* I$Seek Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_seek(PathDesc *p, int seek) {
-    return fseek(p->fp,(off_t)seek,SEEK_SET);
-}
-
-
-*
-* I$ReadLn Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*
-*
-int vrbf_readln(PathDesc *p, byte *buf, int len) {
-    if (p->dir) return -1;
-    if (fgets(buf,len,p->fp)) {
-        int i;
-        for(i=0;i<len && buf[i];i++);
-        if (i>0 && buf[i-1]=='\n') {
-            buf[i-1] = '\r';
-            return i;
-        }
-    } 
-    return -1;
+/* read file descriptor of Path Desc 
+ *    create file descriptor sector if necessary
+ *    if buf!=0, copy it 
+ */
+int filedescriptor(Byte *buf, int len, PathDesc *pd) {
+    struct stat st;
+    if (pd->fd) return 1;
+    pd->fd = (char *)malloc(256);
+    stat((pd->name,&st);
+    os9setmode(pd->fd,st.st_mode);
+    pd->fd+FD_OWN=(st.st_uid&0xff00)>>8;
+    pd->fd+FD_OWN+1=st.st_uid&0xff;
+    os9setdate(pd->fd,st.st_mtimespec);
+    pd->fd+FD_LNK+0=(st.st_uid&0xff000000)>>24;
+    pd->fd+FD_LNK+1=(st.st_uid&0xff0000)>>16;
+    pd->fd+FD_LNK+2=(st.st_uid&0xff00)>>8;
+    pd->fd+FD_LNK+3=st.st_nlink&0xff;
+    os9setdate(pd->fd,st.st_ctimespec);
+    // dummy segment list
+    for(int i=0x10 ; i < 256; i++) pd->fd[i] = 0;
+    return 0;
 }
 
-/*
-* I$Read Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_read(PathDesc *p, byte *buf, int len) {
-    if (p->dir) return dirread(p,buf,len);
-    return fread(buf,len,1,p->fp);
-}
-
-/*
-* I$WritLn Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_writeln(PathDesc *p, byte *buf, int len) {
-    if (p->dir) return -1;
-    int = 0;
-    while(len>0 && *buf !='\r) {
-        fputc(buf[i++],p->fp);
-        len--;
+/* read direcotry entry for any file in the directory 
+ *     we only returns a file descriptor only in the current opened directory
+ *
+ *     inode==0 should return disk id section
+ *     inode==bitmap should return disk sector map for os9 free command
+ */
+int fdinfo(Byte *buf,int len, int inode) {
+    int i;
+    for(i=0;i<MAXPDV;i++) {
+        PathDesc *pd = pdv+i;
+        if (!pd->use || !pd->dir) continue;
+        //  find inode in directory
+        char *dir = (char *)pd->dirfp;
+        while( dir < dir + pd->sz ) {
+            Byte *p = (Byte *)(dir + DIR_NM);
+            int dinode = (p[0]<<16)+(p[1]<<8)+p[2];
+            if (inode == dir) {
+                filedescriptor(buf,len,pd);
+                return 1;
+            }
+        }
     }
-    if (buf[i]=='\r') {
-        fputc('\n',p->fp);
-        i++;
-    }
-    return i;
+    return 0;
 }
 
 /*
-* I$Write Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_write(PathDesc *p, byte *buf, int len) {
-    if (p->dir) return -1;
-    return fwrite(buf,len,1,p->fp);
-}
+ *   each command should have preallocated os9 path descriptor on Y
+ *
+ *   name or buffer, can be in a user map, pmem check that drive number ( mem[0x41+IOPAGE]  0 sys 1 user )
+ *   current directory path number                                        mem[0x42+IOPAGE]  
+ */
+void do_vdisk(Byte cmd) {
+    int err;
+    PathDesc *pd = pdv + *areg;
+    PathDesc *curdir = pdv+mem[0x42+IOPAGE];
+    Byte mode,attr ;
+    char *path,*next,*buf;
 
-/* I$Close Entry Point
-*
-* Entry: A = path number
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*
-*/
-
-int vrbf_close(PathDesc *p, byte *buf) {
-    return fclose(p->fp);
-}
-
-/*
-* I$GetStat Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
-
-int vrbf_getstat(int code,OPathDesc *p, O9Stat *s) {
-    struct stat st;
-
-    switch (code) {
-        case 01: // SS.Ready
-            fstat(fileno(p->fp),&st);
-            if (pos = ftell(fp)) {
-                return st.size - pos;
+    switch(cmd) {
+        /*
+        * I$Create Entry Point
+        *
+        * Entry: A = access mode desired
+        *        B = file attributes
+        *        X = address of the pathlist
+        *
+        * Exit:  A = pathnum
+        *        X = last byte of pathlist address
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd1:
+            pd = findPD();
+            if (pd==0) { *breg = 0xff; break; }
+            mode = *areg;
+            attr = *breg;
+            path = (char *)pmem(xreg);
+            next = pd->name  = checkFileName(path,pd,curdir);
+            pd->dir = 0;
+            pd->fp = fopen(pd->name, os9toUnixAttr(attr));
+            if (next!=0 && pd->fp ) {
+                xreg += ( next - path );
+                pd->use = 1;
+            } else  {
+                *breg = 0xff;
+                free(pd->name);
             }
             break;
-        case 02: // SS.SIZ
-            fstat(fileno(p->fp),&st);
-            return st.size ;
-            break;
-        case 05: // SS.Pos
-            return ftell(s->fp);
+
+        /*
+        * I$Open Entry Point
+        *
+        * Entry: A = access mode desired
+        *        X = address of the pathlist
+        *
+        * Exit:  A = pathnum
+        *        X = last byte of pathlist address
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd2:
+            pd = findPD();
+            *breg = 0xff;
+            if (pd==0) break; 
+            mode = *areg;
+            attr = *breg;
+            pd->fp = 0;
+            path = (char*)pmem(xreg);
+            next = pd->name = checkFileName(path,pd,curdir);
+            if (next!=0) {
+                struct stat buf;
+                if (stat(pd->name,&buf)!=0) break;
+                if ((buf.st_mode & S_IFMT) == S_IFDIR) {
+                    pd->dir = 1;
+                    os9opendir(pd);
+                } else {
+                    char *fname;
+                    pd->dir = 0;
+                    if (curdir==0 && name[0]!='/') return 0; // no current directory
+                    pd->fp = fopen( fname=findfile(pd->name,curdir),"r+");
+                    free(fname);
+                }
+            }
+            if (next!=0 && pd->fp !=0) {
+                *areg = pd->num;
+                xreg += ( next - path );
+            } 
             break;
-        case 15: // SS.FD
-            break;
-        case 0x20: // Pos.FDInf
+
+        /*
+        * I$MakDir Entry Point
+        *
+        * Entry: X = address of the pathlist
+        *        B = directory attributes
+        *
+        * Exit:  X = last byte of pathlist address
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+
+        case 0xd3:
+            pd = findPD();
+            *breg = 0xff;
+            if (pd==0) break; 
+            path = (char*)pmem(xreg);
+            next =  checkFileName(path,pd,curdir);
+            if (next!=0 &&  mkdir(pd->name,0)!= 0 ) {
+                xreg += ( next - path );
+                *breg = 0;
+            } 
+            closepd(pd);
             break;
-        default: return -1;
-    }
-    return -1;
-}
+
+        /*
+        * I$ChgDir Entry Point
+        *
+        *    data dir   P$DIO 3-5     contains open dir Path number 
+        *    exec dir   P$DIO 9-11    contains open dir Path number 
+        *
+        * Entry:
+        *
+        * *areg = access mode
+        *    0 = Use any special device capabilities
+        *    1 = Read only
+        *    2 = Write only
+        *    3 = Update (read and write)
+        * Entry: X = address of the pathlist
+        *
+        * Exit:  X = last byte of pathlist address
+        *        A = open directory Path Number
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd4:
+            pd = findPD();
+            if (pd==0) { *breg = 0xff; break; }
+            path = (char*)pmem(xreg);
+            next = checkFileName(path,pd,curdir);
+            if (next!=0 && os9opendir(pd)) {
+                if (curdir!=pd) closepd(curdir);
+                if (pd->name != path) {
+                    free(path);
+                }
+                xreg += ( next - path );
+                *areg = pd->num;
+                *breg = 0;
+                break;
+            } 
+            *breg = 0xff;
+            break;
+
+        /*
+        * I$Delete Entry Point
+        *
+        * Entry:
+        *
+        * Exit:
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd5: {
+            *breg = 0xff;
+            if (pd==0) break;
+            struct stat st;
+            path = (char*)pmem(xreg);
+            next = checkFileName(path,pd,curdir);
+            if (next!=0 && stat(pd->name,&st)!=0) break;
+            if (next!=0 && ((st->st_mode&S_IFDIR)?rmdir(pd->name):unlink(pd->name)) == 0) {
+                xreg += ( next - path );
+                *breg = 0;
+            } 
+         }
+            break;
 
-/*
-* I$SetStat Entry Point
-*
-* Entry:
-*
-* Exit:
-*
-* Error: CC Carry set
-*        B = errcode
-*/
+        /*
+        * I$Seek Entry Point
+        *
+        * Entry Conditions
+        * A path number
+        * X MS 16 bits of the desired file position
+        * Y LS 16 bits of the desired file position
+        * 
+        * Exit:
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd6: {
+            *breg = 0xff;
+            if (pd==0) break;
+            off_t seek = (xreg<<16)+yreg;
+            *breg = fseek(pd->fp,(off_t)seek,SEEK_SET);
+            break;
+            }
+        /*
+        * I$ReadLn Entry Point
+        *
+        * Entry:
+        * Entry Conditions     in correct mmu map
+        * A path number
+        * X address at which to store data
+        * Y maximum number of bytes to read
+        *
+        * Exit:
+        *
+        * Y number of bytes read
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        *
+        *
+        */
+        case 0xd7:
+            *breg = 0xff;
+            if (pd==0) break;
+            if (pd->dir) break;
+            buf = (char*)pmem(xreg);
+            if (fgets(buf,yreg,pd->fp)) {
+                int len = yreg;
+                int i;
+                for(i=0;i<len && buf[i];i++);
+                if (i>0 && buf[i-1]=='\n') {
+                    buf[i-1] = '\r';
+                    yreg = i;
+                }
+                *breg = 0;
+            } 
+            break;
+
+        /*
+        * I$Read Entry Point
+        *
+        * Entry:
+        *
+        * Exit:
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd8:
+            *breg = 0xff;
+            if (pd==0) break;
+            buf = (char*)pmem(xreg);
+            err =  fread(buf,yreg,1,pd->fp);
+            *breg = err==0?0xff:0 ;
+            yreg = err ;
+            break;
+
+        /*
+        * I$WritLn Entry Point
+        *
+        * Entry:
+        * A path number
+        * X address of the data to write
+        * Y maximum number of bytes to read
+
+        *
+        * Exit:
+        * Y number of bytes written
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xd9:
+            *breg = 0xff;
+            if (pd==0) break;
+            if (pd->dir) break;
+            int len = yreg;
+            int i = 0;
+            Byte *buf = pmem(xreg);
+            while(len>0 && *buf !='\r') {
+                fputc(buf[i++],pd->fp);
+                len--;
+            }
+            if (buf[i]=='\r') {
+                fputc('\n',pd->fp);
+                i++;
+            }
+            *breg = 0;
+            yreg = i;
+            break; 
 
-int vrbf_getstat(int code,OPathDesc *p, O9Stat *s) {
-    switch (code) {
-        case 0: // SS.Opt
+        /*
+        * I$Write Entry Point
+        *
+        * Entry:
+        *
+        * Exit:
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xda :
+            *breg = 0xff;
+            if (!pd->dir) {
+                Byte *buf = pmem(xreg);
+                int len = yreg;
+                int err = fwrite(buf,len,1,pd->fp);
+                *breg = err?0xff:0;
+                yreg = err; 
+            }
             break;
-        case 02: // SS.SIZ
-            break;
-        case 15: // SS.FD
+
+        /* I$Close Entry Point
+        *
+        * Entry: A = path number
+        *
+        * Exit:
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        *
+        */
+        case 0xdb:
+            *breg = 0xff;
+            if (pd==0) break;
+            closepd(pd);
+            *breg = 0;
             break;
-        case 0x11: // SS.Lock
-            break;
-        case 0x10: // SS.Ticks
+
+        /*
+        * I$GetStat Entry Point
+        *
+        * Entry:
+        *
+        * Exit:
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xdc: {
+            struct stat st;
+            off_t pos;
+            switch (*breg) {
+                case 01: // SS.Ready
+                    *breg = 0xff;
+                    if (pd==0) break;
+                    fstat(fileno(pd->fp),&st);
+                    if ((pos = ftell(pd->fp))) {
+                        xreg =  st.st_size - pos;
+                        *breg = 0;
+                    }
+                    break;
+                case 02: // SS.SIZ
+                    *breg = 0xff;
+                    if (pd==0) break;
+                    fstat(fileno(pd->fp),&st);
+                    xreg =  st.st_size ;
+                    *breg = 0;
+                    break;
+                case 05: // SS.Pos
+                    *breg = 0xff;
+                    if (pd==0) break;
+                    xreg =  ftell(pd->fp);
+                    *breg = 0;
+                    break;
+                case 15: // SS.FD
+                /*         SS.FD ($0F) - Returns a file descriptor
+                 *                          Entry: R$A=Path #
+                 *                                 R$B=SS.FD ($0F)
+                 *                                 R$X=Pointer to a 256 byte buffer
+                 *                                 R$Y=# bytes of FD required
+                 *   this should be handled in vrbf
+                 */
+                    *breg = 0xff;
+                    if (pd==0) break;
+                    *breg = filedescriptor(pmem(xreg), yreg,pd) ;
+                    break;
+                case 0x20: // Pos.FDInf    mandatry for dir command
+                /*         SS.FDInf ($20) - Directly reads a file descriptor from anywhere
+                 *                          on drive.
+                 *                          Entry: R$A=Path #
+                 *                                 R$B=SS.FDInf ($20)
+                 *                                 R$X=Pointer to a 256 byte buffer
+                 *                                 R$Y= MSB - Length of read
+                 *                                      LSB - MSB of logical sector #
+                 *                                 R$U= LSW of logical sector #
+                 */
+                    *breg = 0xff;
+                    if (pd==0) break;
+                    *breg  = fdinfo(pmem(xreg),yreg,xreg*0x10000+ureg,pd);
+                    break;
+                default:
+                *breg = 0xff;
+            }
             break;
-        case 0x20: // SS.RsBit
+          }
+
+        /*
+        * I$SetStat Entry Point
+        *
+        * Entry:
+        *
+        * Exit:
+        *
+        *
+        * Error: CC Carry set
+        *        B = errcode
+        */
+        case 0xdd:
+            switch (*breg) {
+                case 0: // SS.Opt
+                case 02: // SS.SIZ
+                case 15: // SS.FD
+                case 0x11: // SS.Lock
+                case 0x10: // SS.Ticks
+                case 0x20: // SS.RsBit
+                case 0x1c: // SS.Attr
+                default: 
+                    *breg = 0xff;
+            }
             break;
-        case 0x1c: // SS.Attr
-            break;
-        default: return -1;
     }
 }