📄 dossubs.c
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include "iotrack.h"#include "dat.h"#include "fns.h"static uchar isdos[256];intisdosfs(uchar *buf){ /* * When dynamic disc managers move the disc partition, * they make it start with 0xE9. */ if(buf[0] == 0xE9) return 1; /* * Check if the jump displacement (magic[1]) is too short for a FAT. */ if(buf[0] == 0xEB && buf[2] == 0x90 && buf[1] >= 0x30) return 1; return 0;}intdosfs(Xfs *xf){ Iosect *p, *p1; Dosboot *b; Fatinfo *fi; Dosboot32 *b32; Dosbpb *bp; long fisec, extflags; int i; if(!isdos['a']){ for(i = 'a'; i <= 'z'; i++) isdos[i] = 1; for(i = 'A'; i <= 'Z'; i++) isdos[i] = 1; for(i = '0'; i <= '9'; i++) isdos[i] = 1; isdos['$'] = 1; isdos['%'] = 1; isdos['''] = 1; isdos['-'] = 1; isdos['_'] = 1; isdos['@'] = 1; isdos['~'] = 1; isdos['`'] = 1; isdos['!'] = 1; isdos['('] = 1; isdos[')'] = 1; isdos['{'] = 1; isdos['}'] = 1; isdos['^'] = 1; isdos['#'] = 1; isdos['&'] = 1; } p = getsect(xf, 0); if(p == 0) return -1; b = (Dosboot*)p->iobuf; if(b->clustsize == 0 || isdosfs(p->iobuf) == 0){ putsect(p); return -1; } bp = malloc(sizeof(Dosbpb)); memset(bp, 0, sizeof(Dosbpb)); /* clear lock */ xf->ptr = bp; xf->fmt = 1; bp->sectsize = GSHORT(b->sectsize); bp->clustsize = b->clustsize; bp->nresrv = GSHORT(b->nresrv); bp->nfats = b->nfats; bp->rootsize = GSHORT(b->rootsize); bp->volsize = GSHORT(b->volsize); if(bp->volsize == 0) bp->volsize = GLONG(b->bigvolsize); bp->mediadesc = b->mediadesc; bp->fatsize = GSHORT(b->fatsize); bp->fataddr = GSHORT(b->nresrv); bp->fatinfo = 0; if(bp->fatsize == 0){ /* is FAT32 */ if(chatty) bootsecdump32(2, xf, (Dosboot32*)b); xf->isfat32 = 1; b32 = (Dosboot32*)b; bp->fatsize = GLONG(b32->fatsize32); if(bp->fatsize == 0){ putsect(p); return -1; } bp->dataaddr = bp->fataddr + bp->nfats*bp->fatsize; bp->rootaddr = 0; bp->rootstart = GLONG(b32->rootstart); /* * disable fat mirroring? */ extflags = GSHORT(b32->extflags); if(extflags & 0x0080){ for(i = 0; i < 4; i++){ if(extflags & (1 << i)){ bp->fataddr += i * bp->fatsize; bp->nfats = 1; break; } } } /* * fat free list info */ bp->freeptr = FATRESRV; fisec = GSHORT(b32->infospec); if(fisec != 0 && fisec < GSHORT(b32->nresrv)){ p1 = getsect(xf, fisec); if(p1 != nil){ fi = (Fatinfo*)p1->iobuf; if(GLONG(fi->sig1) == FATINFOSIG1 && GLONG(fi->sig) == FATINFOSIG){ bp->fatinfo = fisec; bp->freeptr = GLONG(fi->nextfree); bp->freeclusters = GLONG(fi->freeclust); chat("fat info: %ld free clusters, next free %ld\n", bp->freeclusters, bp->freeptr); } putsect(p1); } } }else{ if(chatty) bootdump(2, b); bp->rootaddr = bp->fataddr + bp->nfats*bp->fatsize; bp->rootstart = 0; i = bp->rootsize*DOSDIRSIZE + bp->sectsize-1; i /= bp->sectsize; bp->dataaddr = bp->rootaddr + i; bp->freeptr = FATRESRV; } bp->fatclusters = FATRESRV+(bp->volsize - bp->dataaddr)/bp->clustsize; if(xf->isfat32) bp->fatbits = 32; else if(bp->fatclusters < 4087) bp->fatbits = 12; else bp->fatbits = 16; chat("fatbits=%d (%d clusters)...", bp->fatbits, bp->fatclusters); for(i=0; i<b->nfats; i++) chat("fat %d: %ld...", i, bp->fataddr+i*bp->fatsize); chat("root: %ld...", bp->rootaddr); chat("data: %ld...", bp->dataaddr); putsect(p); return 0;}/* * initialize f to the root directory * this file has no Dosdir entry, * so we special case it all over. */voidrootfile(Xfile *f){ Dosptr *dp; dp = f->ptr; memset(dp, 0, sizeof(Dosptr)); dp->prevaddr = -1;}intisroot(ulong addr){ return addr == 0;}intgetfile(Xfile *f){ Dosptr *dp; Iosect *p; dp = f->ptr; if(dp->p) panic("getfile"); p = getsect(f->xf, dp->addr); if(p == nil) return -1; /* * we could also make up a Dosdir for the root */ dp->d = nil; if(!isroot(dp->addr)){ if(f->qid.path != QIDPATH(dp)){ chat("qid mismatch f=%#llux d=%#lux...", f->qid.path, QIDPATH(dp)); putsect(p); errno = Enonexist; return -1; } dp->d = (Dosdir *)&p->iobuf[dp->offset]; } dp->p = p; return 0;}voidputfile(Xfile *f){ Dosptr *dp; dp = f->ptr; if(!dp->p) panic("putfile"); putsect(dp->p); dp->p = nil; dp->d = nil;}longgetstart(Xfs *xf, Dosdir *d){ long start; start = GSHORT(d->start); if(xf->isfat32) start |= GSHORT(d->hstart)<<16; return start;}voidputstart(Xfs *xf, Dosdir *d, long start){ PSHORT(d->start, start); if(xf->isfat32) PSHORT(d->hstart, start>>16);}/* * return the disk cluster for the iclust cluster in f */longfileclust(Xfile *f, long iclust, int cflag){ Dosbpb *bp; Dosptr *dp; Dosdir *d; long start, clust, nskip, next; bp = f->xf->ptr; dp = f->ptr; d = dp->d; next = 0; /* * asking for the cluster of the root directory * is not a well-formed question, since the root directory * does not begin on a cluster boundary. */ if(!f->xf->isfat32 && isroot(dp->addr)) return -1; if(f->xf->isfat32 && isroot(dp->addr)){ start = bp->rootstart; }else{ start = getstart(f->xf, d); if(start == 0){ if(!cflag) return -1; mlock(bp); start = falloc(f->xf); unmlock(bp); if(start <= 0) return -1; puttime(d, 0); putstart(f->xf, d, start); dp->p->flags |= BMOD; dp->clust = 0; } } if(dp->clust == 0 || iclust < dp->iclust){ clust = start; nskip = iclust; }else{ clust = dp->clust; nskip = iclust - dp->iclust; } if(chatty > 1 && nskip > 0) chat("clust %#lx, skip %ld...", clust, nskip); if(clust <= 0) return -1; if(nskip > 0){ mlock(bp); while(--nskip >= 0){ next = getfat(f->xf, clust); if(chatty > 1) chat("->%#lx", next); if(next > 0){ clust = next; continue; }else if(!cflag) break; if(d && (d->attr&DSYSTEM)){ next = cfalloc(f); if(next < 0) break; /* cfalloc will call putfat for us, since clust may change */ } else { next = falloc(f->xf); if(next < 0) break; putfat(f->xf, clust, next); } clust = next; } unmlock(bp); if(next <= 0) return -1; dp->clust = clust; dp->iclust = iclust; } if(chatty > 1) chat(" clust(%#lx)=%#lx...", iclust, clust); return clust;}/* * return the disk sector for the isect disk sector in f */longfileaddr(Xfile *f, long isect, int cflag){ Dosbpb *bp; Dosptr *dp; long clust; bp = f->xf->ptr; dp = f->ptr; if(!f->xf->isfat32 && isroot(dp->addr)){ if(isect*bp->sectsize >= bp->rootsize*DOSDIRSIZE) return -1; return bp->rootaddr + isect; } clust = fileclust(f, isect/bp->clustsize, cflag); if(clust < 0) return -1; return clust2sect(bp, clust) + isect%bp->clustsize;}/* * translate names */voidfixname(char *buf){ int c; char *p; p = buf; while(c = *p){ if(c == ':' && trspaces) *p = ' '; p++; }}/* * classify the file name as one of * Invalid - contains a bad character * Short - short valid 8.3 name, no lowercase letters * ShortLower - short valid 8.3 name except for lowercase letters * Long - long name */intclassifyname(char *buf){ char *p, *dot; int c, isextended, is8dot3, islower, ndot; p = buf; isextended = 0; islower = 0; dot = nil; ndot = 0; while(c = (uchar)*p){ if(c&0x80) /* UTF8 */ isextended = 1; else if(c == '.'){ dot = p; ndot++; }else if(strchr("+,:;=[] ", c)) isextended = 1; else if(!isdos[c]) return Invalid; if('a' <= c && c <= 'z') islower = 1; p++; } is8dot3 = (ndot==0 && p-buf <= 8) || (ndot==1 && dot-buf <= 8 && p-(dot+1) <= 3); if(!isextended && is8dot3){ if(islower) return ShortLower; return Short; } return Long;} /* * make an alias for a valid long file name */voidmkalias(char *name, char *sname, int id){ Rune r; char *s, *e, sid[10]; int i, esuf, v; e = strrchr(name, '.'); if(e == nil) e = strchr(name, '\0'); s = name; i = 0; while(s < e && i < 6){ if(isdos[(uchar)*s]) sname[i++] = *s++; else s += chartorune(&r, s); } v = snprint(sid, 10, "%d", id); if(i + 1 + v > 8) i = 8 - 1 - v; sname[i++] = '~'; strcpy(&sname[i], sid); i += v; sname[i++] = '.'; esuf = i + 3; if(esuf > 12) panic("bad mkalias"); while(*e && i < esuf){ if(isdos[(uchar)*e]) sname[i++] = *e++; else e += chartorune(&r, e); } if(sname[i-1] == '.') i--; sname[i] = '\0';}/* * check for valid plan 9 names, * rewrite ' ' to ':' */char isfrog[256]={ /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,/* [' '] 1, let's try this -rsc */ ['/'] 1, [0x7f] 1,};intnameok(char *elem){ while(*elem) { if(*elem == ' ' && trspaces) *elem = ':'; if(isfrog[*(uchar*)elem]) return 0; elem++; } return 1;}/* * look for a directory entry matching name * always searches for long names which match a short name */intsearchdir(Xfile *f, char *name, Dosptr *dp, int cflag, int longtype){ Xfs *xf; Iosect *p; Dosbpb *bp; Dosdir *d; char buf[261], *bname; int isect, addr, o, addr1, addr2, prevaddr, prevaddr1, o1, islong, have, need, sum; xf = f->xf; bp = xf->ptr; addr1 = -1; addr2 = -1; prevaddr1 = -1; o1 = 0; islong = 0; sum = -1; need = 1; if(longtype!=Short && cflag) need += (utflen(name) + DOSRUNE-1) / DOSRUNE; memset(dp, 0, sizeof(Dosptr)); dp->prevaddr = -1; dp->naddr = -1; dp->paddr = ((Dosptr *)f->ptr)->addr; dp->poffset = ((Dosptr *)f->ptr)->offset; have = 0; addr = -1; bname = nil; for(isect=0;; isect++){ prevaddr = addr; addr = fileaddr(f, isect, cflag); if(addr < 0) break; p = getsect(xf, addr); if(p == 0) break; for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){ d = (Dosdir *)&p->iobuf[o]; if(d->name[0] == 0x00){ chat("end dir(0)..."); putsect(p); if(!cflag) return -1; /* * addr1 & o1 are the start of the dirs * addr2 is the optional second cluster used if the long name * entry does not fit within the addr1 cluster * * have tells us the number of contiguous free dirs * starting at addr1.o1; need are necessary to hold the long name. */ if(addr1 < 0){ addr1 = addr; prevaddr1 = prevaddr; o1 = o; } if(addr2 < 0 && (bp->sectsize-o)/DOSDIRSIZE + have < need){ addr2 = fileaddr(f, isect+1, cflag); if(addr2 < 0) goto breakout; }else if(addr2 < 0) addr2 = addr; if(addr2 == addr1) addr2 = -1; dp->addr = addr1; dp->offset = o1; dp->prevaddr = prevaddr1; dp->naddr = addr2; return 0; } if(d->name[0] == DOSEMPTY){ if(chatty) fprint(2, "empty dir\n"); have++; if(addr1 == -1){ addr1 = addr; o1 = o; prevaddr1 = prevaddr; } if(addr2 == -1 && have >= need) addr2 = addr; continue; } have = 0; if(addr2 == -1) addr1 = -1; dirdump(d); if((d->attr & 0xf) == 0xf){ bname = getnamesect(buf, bname, p->iobuf + o, &islong, &sum, 1); continue; } if(d->attr & DVLABEL){ islong = 0; continue; } if(islong != 1 || sum != aliassum(d) || cistrcmp(bname, name) != 0){ bname = buf; getname(buf, d); } islong = 0; if(cistrcmp(bname, name) != 0) continue; if(chatty) fprint(2, "found\n"); if(cflag){ putsect(p); return -1; } dp->addr = addr; dp->prevaddr = prevaddr; dp->offset = o; dp->p = p; dp->d = d; return 0; } putsect(p); }breakout: chat("end dir(1)..."); return -1;}intemptydir(Xfile *f){ Xfs *xf = f->xf; Dosbpb *bp = xf->ptr; int isect, addr, o; Iosect *p; Dosdir *d; for(isect=0;; isect++){ addr = fileaddr(f, isect, 0); if(addr < 0) break; p = getsect(xf, addr); if(p == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -