📄 dosfs.c
字号:
#include "all.h"#include "io.h"#include "mem.h"#include "dosfs.h"#define GSHORT(p) (((p)[1]<<8)|(p)[0])#define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p))#define GLSHORT(p) (((p)[0]<<8)|(p)[1])#define GLLONG(p) ((GLSHORT(p)<<16)|GLSHORT(p+2))/* * debugging */#define chatty 0#define chat if(chatty)print/* * block io buffers */typedef struct Clustbuf Clustbuf;struct Clustbuf{ int flags; int age; Devsize sector; uchar * iobuf; Dos * dos; int size; int bufsize;};enum{ Nbio= 16, LOCKED= 1, MOD= 2, IMMED= 4,};static void puttime(Dosdir*);static Clustbuf bio[Nbio];/* * write an io buffer and update its flags */static voidwriteclust(Clustbuf *p){ Dos *dos; Off addr; dos = p->dos; addr = (p->sector+dos->start)*dos->sectbytes; chat("writeclust @ %lld addr %lld...", (Wideoff)p->sector, (Wideoff)addr); if((*dos->seek)(dos->dev, addr) < 0) panic("writeclust: seek"); if((*dos->write)(dos->dev, p->iobuf, p->size) != p->size) panic("writeclust: write"); p->flags &= ~(MOD|IMMED); chat("OK\n");}/* * write any dirty buffers */static voidsyncclust(void){ Clustbuf *p; for(p = bio; p < &bio[Nbio]; p++){ if(p->flags & LOCKED) panic("syncclust"); if(p->flags & MOD) writeclust(p); }}/* * get an io buffer, possibly with valid data */static Clustbuf*getclust0(Dos *dos, Off sector){ Clustbuf *p, *oldest; chat("getclust0 @ %lld\n", (Wideoff)sector); /* * if we have it, just return it * otherwise, reuse the oldest unlocked entry */ oldest = 0; for(p = bio; p < &bio[Nbio]; p++){ if(sector == p->sector && dos == p->dos){ if(p->flags & LOCKED) panic("getclust0 locked"); chat("getclust0 %lld in cache\n", (Wideoff)sector); p->flags |= LOCKED; return p; } if(p->flags & LOCKED) continue; if(oldest == 0 || p->age <= oldest->age) oldest = p; } p = oldest; if(p == 0) panic("getclust0 all locked"); p->flags |= LOCKED; if(p->flags & MOD) writeclust(p); /* * make sure the buffer is big enough */ if(p->iobuf==0 || p->bufsize < dos->clustbytes){ p->bufsize = dos->clustbytes; p->iobuf = ialloc(p->bufsize, 0); } if(sector >= dos->dataaddr) p->size = dos->clustbytes; else p->size = dos->sectbytes; p->dos = 0; /* make it invalid */ return p;}/* * get an io block from an io buffer */static Clustbuf*getclust(Dos *dos, Off sector){ Clustbuf *p; Off addr; p = getclust0(dos, sector); if(p->dos){ p->age = MACHP(0)->ticks; return p; } addr = (sector+dos->start)*dos->sectbytes; chat("getclust seek addr %lld\n", (Wideoff)addr); if((*dos->seek)(dos->dev, addr) < 0){ chat("can't seek block\n"); return 0; } chat("getclust read addr %lld\n", (Wideoff)addr); if((*dos->read)(dos->dev, p->iobuf, p->size) != p->size){ chat("can't read block\n"); return 0; } p->age = MACHP(0)->ticks; p->dos = dos; p->sector = sector; chat("getclust %lld read\n", (Wideoff)sector); return p;}/* * get an io block from an io buffer; * any current data is discarded. */static Clustbuf*getclustz(Dos *dos, Off sector){ Clustbuf *p; p = getclust0(dos, sector); p->age = MACHP(0)->ticks; p->dos = dos; p->sector = sector; memset(p->iobuf, 0, p->size); p->flags |= MOD; chat("getclustz %lld\n", (Wideoff)sector); return p;}/* * release an io buffer */static voidputclust(Clustbuf *p){ if(!(p->flags & LOCKED)) panic("putclust lock"); if((p->flags & (MOD|IMMED)) == (MOD|IMMED)) writeclust(p); p->flags &= ~LOCKED; chat("putclust @ sector %lld...", (Wideoff)p->sector);}/* * walk the fat one level ( n is a current cluster number ). * return the new cluster number or -1 if no more. */static longfatwalk(Dos *dos, int n){ ulong k, sect; Clustbuf *p; int o; chat("fatwalk %d\n", n); if(n < 2 || n >= dos->fatclusters) return -1; switch(dos->fatbits){ case 12: k = (3*n)/2; break; case 16: k = 2*n; break; default: return -1; } if(k >= dos->fatbytes) panic("getfat"); sect = k/dos->sectbytes + dos->fataddr; o = k%dos->sectbytes; p = getclust(dos, sect); k = p->iobuf[o++]; if(o >= dos->sectbytes){ putclust(p); p = getclust(dos, sect+1); o = 0; } k |= p->iobuf[o]<<8; putclust(p); if(dos->fatbits == 12){ if(n&1) k >>= 4; else k &= 0xfff; if(k >= 0xff8) k |= 0xf000; } k = k < 0xfff8 ? k : -1; chat("fatwalk %d -> %lud\n", n, k); return k;}/* * write a value into each copy of the fat. */static voidfatwrite(Dos *dos, int n, int val){ Off k, sect; Clustbuf *p; int i, o; chat("fatwrite %d %d...", n, val); if(n < 2 || n >= dos->fatclusters) panic("fatwrite n"); switch(dos->fatbits){ case 12: k = (3*n)/2; break; case 16: k = 2*n; break; default: panic("fatwrite fatbits"); return; } if(k >= dos->fatbytes) panic("fatwrite k"); for(i=0; i<dos->nfats; i++, k+=dos->fatbytes){ sect = k/dos->sectbytes + dos->fataddr; o = k%dos->sectbytes; p = getclust(dos, sect); if(p == 0) panic("fatwrite getclust"); switch(dos->fatbits){ case 12: if(n&1){ p->iobuf[o] &= 0x0f; p->iobuf[o++] |= val<<4; }else p->iobuf[o++] = val; if(o >= dos->sectbytes){ p->flags |= MOD; putclust(p); p = getclust(dos, sect+1); if(p == 0) panic("fatwrite getclust"); o = 0; } if(n&1) p->iobuf[o] = val>>4; else{ p->iobuf[o] &= 0xf0; p->iobuf[o] |= (val>>8)&0x0f; } break; case 16: p->iobuf[o++] = val; p->iobuf[o] = val>>8; break; } p->flags |= MOD; putclust(p); } chat("OK\n");}/* * allocate a free cluster from the fat. */static intfatalloc(Dos *dos){ Clustbuf *p; int n; n = dos->freeptr; for(;;){ if(fatwalk(dos, n) == 0) break; if(++n >= dos->fatclusters) n = 2; if(n == dos->freeptr) return -1; } dos->freeptr = n+1; if(dos->freeptr >= dos->fatclusters) dos->freeptr = 2; fatwrite(dos, n, 0xffff); p = getclustz(dos, dos->dataaddr + (n-2)*dos->clustsize); putclust(p); return n;}/* * map a file's logical sector address to a physical sector address */static longfileaddr(Dosfile *fp, Off ltarget, Clustbuf *pdir){ Dos *dos = fp->dos; Dosdir *dp; Off p; chat("fileaddr %8.8s %lld\n", fp->name, (Wideoff)ltarget); /* * root directory is contiguous and easy */ if(fp->pdir == 0){ if(ltarget*dos->sectbytes >= dos->rootsize*sizeof(Dosdir)) return -1; p = dos->rootaddr + ltarget; chat("fileaddr %lld -> %lld\n", (Wideoff)ltarget, (Wideoff)p); return p; } if(fp->pstart == 0){ /* empty file */ if(!pdir) return -1; p = fatalloc(dos); if(p <= 0) return -1; chat("fileaddr initial alloc %lld\n", (Wideoff)p); dp = (Dosdir *)(pdir->iobuf + fp->odir); puttime(dp); dp->start[0] = p; dp->start[1] = p>>8; pdir->flags |= MOD; fp->pstart = p; fp->pcurrent = p; fp->lcurrent = 0; } /* * anything else requires a walk through the fat * [lp]current will point to the last cluster if we run off the end */ ltarget /= dos->clustsize; if(fp->pcurrent == 0 || fp->lcurrent > ltarget){ /* go back to the beginning */ fp->lcurrent = 0; fp->pcurrent = fp->pstart; } while(fp->lcurrent < ltarget){ /* walk the fat */ p = fatwalk(dos, fp->pcurrent); if(p < 0){ if(!pdir) return -1; p = fatalloc(dos); if(p < 0){ print("file system full\n"); return -1; } fatwrite(dos, fp->pcurrent, p); } fp->pcurrent = p; ++fp->lcurrent; } /* * clusters start at 2 instead of 0 (why? - presotto) */ p = dos->dataaddr + (fp->pcurrent-2)*dos->clustsize; chat("fileaddr %lld -> %lld\n", (Wideoff)ltarget, (Wideoff)p); return p;}/* * set up a dos file name */static voidsetname(char *name, char *ext, char *from){ char *to; memset(name, ' ', 8); memset(ext, ' ', 3); to = name; for(; *from && to-name < 8; from++, to++){ if(*from == '.'){ from++; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -