Mercurial > hg > Members > kono > os9 > sbc09
diff src/vdisk.c @ 57:2088fd998865
sbc09 directry clean up
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 23 Jul 2018 16:07:12 +0900 |
parents | vdisk.c@4fa2bdb0c457 |
children | 7c6dc25c2b05 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vdisk.c Mon Jul 23 16:07:12 2018 +0900 @@ -0,0 +1,844 @@ +/******************************************************************** +* Virtual RBF - Random Block File Manager +* +* Shinji KONO (kono@ie.u-ryukyu.ac.jp) 2018/7/17 +* 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> +#include <time.h> +#include <arpa/inet.h> + +static int vdiskdebug = 0; // bit 1 trace, bit 2 filename + + +Byte pmmu[8]; // process dat mmu + +extern char *prog ; // for disass +#ifdef USE_MMU +extern Byte * mem0(Byte *iphymem, Word adr, Byte *immu) ; +// smem physical address using system mmu +// pmem physical address using caller's mmu +#define smem(a) mem0(phymem,a,&mem[0x20+IOPAGE]) +#define pmem(a) mem0(phymem,a,pmmu) +#else +#define smem(a) (&mem[a]) +#define pmem(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 ; + int sz ; // used only for directory + char drv ; + char use ; + char dir; + char *fd ; + char *dirfp; +} PathDesc, *PathDescPtr; + +static void +vdisklog(Word u,PathDesc *pd, Word pdptr, int curdir,FILE *fp) ; + +#define MAXVDRV 4 + +static char *drvRoot[] = { ".",".",".","."}; +static PathDesc pdv[MAXPDV]; + +/* + * us 0 system + * 1 caller + */ +static inline Word +getword(Byte *adr) { + Word *padr = (Word*)adr; + return ntohs(*padr); +} + +static inline void +setword(Byte *adr,Word value) { + Word *padr = (Word*)adr; + *padr = htons(value); +} + +static int +setVdisk(int drv,char *name) { + if (drv<0 || drv>=MAXVDRV) return -1; + drvRoot[drv] = name; + return 0; +} + +static void +closepd(PathDesc *pd) { + if(pd->fp) fclose(pd->fp) ; + pd->dir = 0; + pd->use = 0; + pd->fp = 0; + pd->mode = 0; + free(pd->dirfp); pd->dirfp = 0; + free(pd->name); pd->name = 0; +} + +/* + * keep track current directory ( most recently 256 entry ) + * too easy approach + */ +char *cdt[512]; +static int cdtptr = 0; + +Byte +setcd(char *name) { + int len; + for(int i=0;i<512;i++) { + if (cdt[i] && strcmp(name,cdt[i])==0) return i; + } + cdtptr &= 0x1ff; + if (cdt[cdtptr]) free(cdt[cdtptr]); + cdt[cdtptr] = (char*)malloc(len=strlen(name)+1); + strcpy(cdt[cdtptr],name); + return cdtptr++; +} + +#define MAXPAHTLEN 256 + +static void +putOs9str(char *s,int max) { + if (s==0) { + printf("(null)"); + return; + } + while(*s && (*s&0x7f)>=' ' && ((*s&0x80)==0) && --max !=0) { + putchar(*s); s++; + } + if (*s&0x80) putchar(*s&0x7f); +} + +static void +err(int error) { + printf("err %d\n",error); +} + +static char * +addCurdir(char *name, PathDesc *pd, int curdir) { + int ns =0 ; + char *n = name; +if(vdiskdebug&0x2) { printf("addcur \""); putOs9str(name,0); printf("\" cur \""); putOs9str( cdt[curdir],0); printf("\"\n"); } + if (name[0]=='/') { + name++; while(*name !='/' && *name!=0) name ++ ; // skip /d0 + while(name[ns]!=0) ns++; + } else if (!cdt[curdir] ) return 0; // no current directory + else ns = strlen(name); + int ps = ns; + char *base ; + if (name[0]=='/') { + base = drvRoot[pd->drv]; ps += strlen(drvRoot[pd->drv])+1; name++; + } else if (name[0]==0) { + base = drvRoot[pd->drv]; + char *path = (char*)malloc(strlen(base)+1); // we'll free this, malloc it. + int i = 0; + for(;base[i];i++) path[i] = base[i]; + path[i]=0; + return path; + } else { + base = cdt[curdir]; ps += strlen(cdt[curdir])+2; + } + char *path = (char*)malloc(ps); + int i = 0; + for(;base[i];i++) path[i] = base[i]; + path[i++] = '/'; + for(int j=0;i<ps;j++,i++) path[i] = name[j]; + path[i] = 0; + if (i>ps) + printf("overrun i=%d ps=%d\n",i,ps); // err(__LINE__); + return path; +} + +static char * +checkFileName(char *path, PathDesc *pd, int curdir) { + char *p = path; + char *name = path; + int maxlen = MAXPAHTLEN; +if(vdiskdebug&2) { printf("checkf \""); putOs9str(name,0); printf("\"\n"); } + while(*p!=0 && (*p&0x80)==0 && (*p&0x7f)>' ' && maxlen-->0) p++; + if (maxlen==MAXPAHTLEN) return 0; + if (*p) { // 8th bit termination or non ascii termination + int eighth = ((*p&0x80)!=0); + name = (char *)malloc(p-path+1+eighth); + int i; + for(i=0;i<p-path;i++) name[i] = path[i]; + if (eighth) { name[i] = path[i]&0x7f; p++ ; i++; } + name[i] = 0; + } + char *name1 = addCurdir(name,pd,curdir); + if (name1!=name && name1!=path) free(name); + if (name1==0) return 0; + pd->name = name1; +if(vdiskdebug&2) { + printf(" remain = \""); + char *p1 = p; int max=31; + while(*p1 && (*p1&0x80)==0 && max-->0) { if (*p1<0x20) printf("(0x%02x)",*p1); else putchar(*p1); p1++; } + if (*p1) { if ((*p1&0x7f)<0x20) printf("(0x%02x)",*p1); else putchar(*p1&0x7f); } + printf("\" checkname result \""); putOs9str(pd->name,0); printf("\"\n"); +} + return p; +} + +static void +os9setmode(Byte *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; +} + +static 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"; +} + +/* + * 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 + */ + +#define FD_ATT 0 +#define FD_OWN 1 +#define FD_DAT 3 +#define FD_LNK 8 +#define FD_SIZ 9 +#define FD_Creat 13 +#define FD_SEG 16 + + +/* + * 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 + */ +#define DIR_SZ 32 +#define DIR_NM 29 + + +/* read direcotry entry */ +static int +os9opendir(PathDesc *pd) { + DIR *dir; + struct dirent *dp; + if (pd->dirfp) return 0; // already opened + dir = opendir(pd->name); + if (dir==0) return -1; + int dircount = 0; + while ((dp = readdir(dir)) != NULL) dircount++; // 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(dir)) != NULL && dircount-->=0) { + int j = 0; + for(j = 0; j < DIR_NM ; j++) { + if (j< dp->d_namlen) { + pd->dirfp[i+j] = dp->d_name[j]&0x7f; + if (j== dp->d_namlen-1) + pd->dirfp[i+j] |= 0x80; // os9 EOL + } else + pd->dirfp[i+j] = 0; + } + pd->dirfp[i+j] = (dp->d_ino&0xff0000)>>16; + pd->dirfp[i+j+1] = (dp->d_ino&0xff00)>>8; + pd->dirfp[i+j+2] = dp->d_ino&0xff; + i += DIR_SZ; + if (i>pd->sz) + return 0; + } + pd->fp = fmemopen(pd->dirfp,pd->sz,"r"); + return 0; +} + +static void +os9setdate(Byte *d,struct timespec * unixtime) { + // yymmddhhss + struct tm r; + localtime_r(&unixtime->tv_sec,&r); + d[0] = r.tm_year-2048; + d[1] = r.tm_mon + 1; + d[2] = r.tm_mday; + d[3] = r.tm_hour; + d[4] = r.tm_min; + d[5] = r.tm_sec; +} + +/* read file descriptor of Path Desc + * create file descriptor sector if necessary + * if buf!=0, copy it + */ +static int +filedescriptor(Byte *buf, int len, Byte *name,int curdir) { + int err = 0x255; + PathDesc pd; + if (len<13) return -1; + checkFileName((char*)name,&pd,curdir); + struct stat st; + if (stat(pd.name,&st)!=0) goto err1; + os9setmode(buf+FD_ATT,st.st_mode); + buf[FD_OWN]=(st.st_uid&0xff00)>>8; + buf[FD_OWN+1]=st.st_uid&0xff; + os9setdate(buf+ FD_DAT,&st.st_mtimespec); + buf[FD_LNK]=st.st_nlink&0xff; + buf[FD_SIZ+0]=(st.st_size&0xff000000)>>24; + buf[FD_SIZ+1]=(st.st_size&0xff0000)>>16; + buf[FD_SIZ+2]=(st.st_size&0xff00)>>8; + buf[FD_SIZ+3]=st.st_size&0xff; + os9setdate(buf+FD_Creat,&st.st_ctimespec); + err = 0; +err1: + free(pd.name); + return err; +} + +/* 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 + */ +static int +fdinfo(Byte *buf,int len, int inode, PathDesc *pd,int curdir) { + int i; + for(i=0;i<MAXPDV;i++) { + PathDesc *pd = pdv+i; + if (!pd->use || !pd->dir) continue; + // find inode in directory + Byte *dir = (Byte*)pd->dirfp; + Byte *end = (Byte*)pd->dirfp + pd->sz; + while( dir < end ) { + Byte *p = (dir + DIR_NM); + int dinode = (p[0]<<16)+(p[1]<<8)+p[2]; + if (inode == dinode) { + return filedescriptor(buf,len,dir,curdir); + } + dir += 0x20; + } + } + return 255; +} + +void +getDAT() { + Word ps = getword(smem(0x50)); // process structure + Byte *dat = smem(ps+0x40); // process dat (dynamic address translation) + for(int i=0; i<8; i++) { + pmmu[i] = dat[i*2+1]; + } +} + +/* + * each command should have preallocated os9 path descriptor on Y + * + * name or buffer, can be in a user map, check that drive number ( mem[0x41+IOPAGE] 0 sys 1 user ) + * current directory path number mem[0x42+IOPAGE] + * yreg has pd number + */ +void +do_vdisk(Byte cmd) { + int err; + int curdir = mem[0x44+IOPAGE]; // garbage until set + Byte attr ; + Word u = getword(&mem[0x45+IOPAGE]); // caller's stack in system segment + Byte *frame = smem(u); + xreg = getword(frame+4); + yreg = getword(frame+6); + *areg = *smem(u+1); + *breg = *smem(u+2); + Byte mode = 0; + Byte *os9pd = smem(getword(&mem[0x47+IOPAGE])); + PathDesc *pd = pdv+*os9pd; + + getDAT(); + pd->num = *os9pd; + pd->drv = mem[0x41+IOPAGE]; + char *path,*next,*buf; + if (vdiskdebug&1) vdisklog(u,pd,getword(&mem[0x47+IOPAGE]),curdir,stdout); + + 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: + 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); + pd->use = 0; + } + break; + + /* + * 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: + *breg = 0xff; + mode = *areg; + attr = *breg; + pd->fp = 0; + path = (char*)pmem(xreg); + next = checkFileName(path,pd,curdir); + *breg = 0xff; + 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 { + pd->dir = 0; + pd->fp = fopen( pd->name,os9toUnixAttr(mode)); + } + pd->use = 1; + } + if (next!=0 && pd->fp !=0) { + *breg = 0; + *areg = pd->num; + *smem(u+1) = *areg ; + xreg += ( next - path ); + pd->use = 1; + } else { + pd->use = 0; + } + break; + + /* + * 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: + *breg = 0xff; + 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; + + /* + * 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 + * + * + * we keep track a cwd and a cxd for a process using 8bit id + */ + case 0xd4: + path = (char*)pmem(xreg); + next = 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) break; + xreg += ( next - path ); + *areg = setcd(pd->name); + *smem(u+1) = *areg ; + pd->use = 1; + pd->dir = 1; + *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); + pd->use = 0; + 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$Seek Entry Point + * + * Entry Conditions + * A path number + * X MS 16 bits of the desired file position + * U LS 16 bits of the desired file position + * + * Exit: + * + * Error: CC Carry set + * B = errcode + */ + case 0xd6: { + *breg = 0xff; + ureg = (*smem(u+8)<<8)+*smem(u+9); + off_t seek = (xreg<<16)+ureg; + *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; + buf = (char*)pmem(xreg); + char *b; + if ((b=fgets(buf,yreg,pd->fp))) { + if (b==0) { + *breg = 0xd3; + break; + } + int i; + for(i=0;i<yreg && buf[i];i++); + if (i>0 && buf[i-1]=='\n') { + buf[i-1] = '\r'; + yreg = i; + } + // set y + setword(smem(u+6),yreg); + *breg = 0; + } + break; + + /* + * I$Read Entry Point + * + * Entry: + * + * Exit: + * + * Error: CC Carry set + * B = errcode + */ + case 0xd8: + *breg = 0xff; + buf = (char*)pmem(xreg); + int i = fread(buf,1,yreg,pd->fp); + // set y + setword(smem(u+6),i); + *breg = (i==0?0xd3:0) ; + 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->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; + // set y + setword(smem(u+6),i); + break; + } + + /* + * 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,1,len,pd->fp); + *breg = err?0:0xff; + // set y + setword(smem(u+6),err); + } + break; + + /* 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; + + /* + * 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 + */ + *breg = 0xff; + if (pd==0) break; + *breg = filedescriptor(pmem(xreg), yreg,(Byte*)pd->name,curdir) ; + 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; + ureg = getword(smem(u+8)); + *breg = fdinfo(pmem(xreg),(yreg&0xff),((yreg&0xff00)>>8)*0x10000+ureg,pd,curdir); + break; + default: + *breg = 0xff; + } + break; + } + + /* + * 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; + } + if (vdiskdebug && *breg) printf(" vdisk call error %x\n",*breg); + // return value + mem[0x40+IOPAGE] = *breg; + *smem(u+2) = *breg ; + setword(smem(u+4),xreg); +} + +static void +vdisklog(Word u,PathDesc *pd, Word pdptr, int curdir, FILE *fp) { + char *cd = cdt[curdir]?cdt[curdir]:"(null)"; + fprintf(fp,"pd %d 0x%x cd[%d]=%s ",pd->num, pdptr, curdir,cd); + Byte *frame = smem(u); + sreg = u; + ccreg = frame[0]; + *areg = frame[1]; + *breg = frame[2]; + xreg = getword(frame+4); + yreg = getword(frame+6); + ureg = getword(frame+8); + pcreg = getword(frame+10)-3; + prog = (char*)(pmem(pcreg) - pcreg); + do_trace(fp); +} + + +/* end */