12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931 |
- #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];
- int
- isdosfs(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;
- }
- int
- dosfs(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.
- */
- void
- rootfile(Xfile *f)
- {
- Dosptr *dp;
- dp = f->ptr;
- memset(dp, 0, sizeof(Dosptr));
- dp->prevaddr = -1;
- }
- int
- isroot(ulong addr)
- {
- return addr == 0;
- }
- int
- getfile(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;
- }
- void
- putfile(Xfile *f)
- {
- Dosptr *dp;
- dp = f->ptr;
- if(!dp->p)
- panic("putfile");
- putsect(dp->p);
- dp->p = nil;
- dp->d = nil;
- }
- long
- getstart(Xfs *xf, Dosdir *d)
- {
- long start;
- start = GSHORT(d->start);
- if(xf->isfat32)
- start |= GSHORT(d->hstart)<<16;
- return start;
- }
- void
- putstart(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
- */
- long
- fileclust(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
- */
- long
- fileaddr(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
- */
- void
- fixname(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
- */
- int
- classifyname(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
- */
- void
- mkalias(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,
- };
- int
- nameok(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
- */
- int
- searchdir(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;
- }
- int
- emptydir(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)
- return -1;
- for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
- d = (Dosdir *)&p->iobuf[o];
- if(d->name[0] == 0x00){
- putsect(p);
- return 0;
- }
- if(d->name[0] == DOSEMPTY)
- continue;
- if(d->name[0] == '.')
- continue;
- if(d->attr&DVLABEL)
- continue;
- putsect(p);
- return -1;
- }
- putsect(p);
- }
- return 0;
- }
- long
- readdir(Xfile *f, void *vbuf, long offset, long count)
- {
- Xfs *xf;
- Dosbpb *bp;
- Dir dir;
- int isect, addr, o, islong, sum;
- Iosect *p;
- Dosdir *d;
- long rcnt, n;
- char *name, snamebuf[8+1+3+1], namebuf[DOSNAMELEN];
- uchar *buf;
- buf = vbuf;
- rcnt = 0;
- xf = f->xf;
- bp = xf->ptr;
- if(count <= 0)
- return 0;
- islong = 0;
- sum = -1;
- name = nil;
- for(isect=0;; isect++){
- addr = fileaddr(f, isect, 0);
- if(addr < 0)
- break;
- p = getsect(xf, addr);
- if(p == 0)
- return -1;
- for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
- d = (Dosdir *)&p->iobuf[o];
- if(d->name[0] == 0x00){
- putsect(p);
- return rcnt;
- }
- if(d->name[0] == DOSEMPTY)
- continue;
- dirdump(d);
- if(d->name[0] == '.'){
- if(d->name[1] == ' ' || d->name[1] == 0)
- continue;
- if(d->name[1] == '.' &&
- (d->name[2] == ' ' || d->name[2] == 0))
- continue;
- }
- if((d->attr & 0xf) == 0xf){
- name = getnamesect(namebuf, name, p->iobuf+o, &islong, &sum, 1);
- continue;
- }
- if(d->attr & DVLABEL){
- islong = 0;
- continue;
- }
- dir.name = snamebuf;
- getdir(xf, &dir, d, addr, o);
- if(islong == 1 && nameok(name) && sum == aliassum(d))
- dir.name = name;
- islong = 0;
- n = convD2M(&dir, &buf[rcnt], count - rcnt);
- name = nil;
- if(n <= BIT16SZ){ /* no room for next entry */
- putsect(p);
- return rcnt;
- }
- rcnt += n;
- if(offset > 0){
- offset -= rcnt;
- rcnt = 0;
- islong = 0;
- continue;
- }
- if(rcnt == count){
- putsect(p);
- return rcnt;
- }
- }
- putsect(p);
- }
- return rcnt;
- }
- /*
- * set up ndp for a directory's parent
- * the hardest part is setting up paddr
- */
- int
- walkup(Xfile *f, Dosptr *ndp)
- {
- Dosbpb *bp;
- Dosptr *dp;
- Dosdir *xd;
- Iosect *p;
- long k, o, so, start, pstart, ppstart, st, ppclust;
- bp = f->xf->ptr;
- dp = f->ptr;
- memset(ndp, 0, sizeof(Dosptr));
- ndp->prevaddr = -1;
- ndp->naddr = -1;
- ndp->addr = dp->paddr;
- ndp->offset = dp->poffset;
- chat("walkup: paddr=%#lx...", dp->paddr);
- /*
- * root's paddr is always itself
- */
- if(isroot(dp->paddr))
- return 0;
- /*
- * find the start of our parent's directory
- */
- p = getsect(f->xf, dp->paddr);
- if(p == nil)
- goto error;
- xd = (Dosdir *)&p->iobuf[dp->poffset];
- dirdump(xd);
- start = getstart(f->xf, xd);
- chat("start=%#lx...", start);
- if(start == 0)
- goto error;
- putsect(p);
- /*
- * verify that parent's . points to itself
- */
- p = getsect(f->xf, clust2sect(bp, start));
- if(p == nil)
- goto error;
- xd = (Dosdir *)p->iobuf;
- dirdump(xd);
- st = getstart(f->xf, xd);
- if(xd->name[0]!='.' || xd->name[1]!=' ' || start!=st)
- goto error;
- /*
- * parent's .. is the next entry, and has start of parent's parent
- */
- xd++;
- dirdump(xd);
- if(xd->name[0] != '.' || xd->name[1] != '.')
- goto error;
- pstart = getstart(f->xf, xd);
- putsect(p);
- /*
- * we're done if parent is root
- */
- if(pstart == 0 || f->xf->isfat32 && pstart == bp->rootstart)
- return 0;
- /*
- * verify that parent's . points to itself
- */
- p = getsect(f->xf, clust2sect(bp, pstart));
- if(p == 0){
- chat("getsect %ld failed\n", pstart);
- goto error;
- }
- xd = (Dosdir *)p->iobuf;
- dirdump(xd);
- st = getstart(f->xf, xd);
- if(xd->name[0]!='.' || xd->name[1]!=' ' || pstart!=st)
- goto error;
- /*
- * parent's parent's .. is the next entry, and has start of parent's parent's parent
- */
- xd++;
- dirdump(xd);
- if(xd->name[0] != '.' || xd->name[1] != '.')
- goto error;
- ppstart = getstart(f->xf, xd);
- putsect(p);
- /*
- * open parent's parent's parent, and walk through it until parent's parent is found
- * need this to find parent's parent's addr and offset
- */
- ppclust = ppstart;
- if(f->xf->isfat32 && ppclust == 0){
- ppclust = bp->rootstart;
- chat("ppclust 0, resetting to rootstart\n");
- }
- k = ppclust ? clust2sect(bp, ppclust) : bp->rootaddr;
- p = getsect(f->xf, k);
- if(p == nil){
- chat("getsect %ld failed\n", k);
- goto error;
- }
- xd = (Dosdir *)p->iobuf;
- dirdump(xd);
- if(ppstart){
- st = getstart(f->xf, xd);
- if(xd->name[0]!='.' || xd->name[1]!=' ' || ppstart!=st)
- goto error;
- }
- for(so=1;; so++){
- for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
- xd = (Dosdir *)&p->iobuf[o];
- if(xd->name[0] == 0x00){
- chat("end dir\n");
- goto error;
- }
- if(xd->name[0] == DOSEMPTY)
- continue;
- st = getstart(f->xf, xd);
- if(st == pstart)
- goto out;
- }
- if(ppclust){
- if(so%bp->clustsize == 0){
- mlock(bp);
- ppclust = getfat(f->xf, ppclust);
- unmlock(bp);
- if(ppclust < 0){
- chat("getfat %ld failed\n", ppclust);
- goto error;
- }
- }
- k = clust2sect(bp, ppclust) +
- so%bp->clustsize;
- }else{
- if(so*bp->sectsize >= bp->rootsize*DOSDIRSIZE)
- goto error;
- k = bp->rootaddr + so;
- }
- putsect(p);
- p = getsect(f->xf, k);
- if(p == 0){
- chat("getsect %ld failed\n", k);
- goto error;
- }
- }
- out:
- putsect(p);
- ndp->paddr = k;
- ndp->poffset = o;
- return 0;
- error:
- if(p)
- putsect(p);
- return -1;
- }
- long
- readfile(Xfile *f, void *vbuf, long offset, long count)
- {
- Xfs *xf = f->xf;
- Dosbpb *bp = xf->ptr;
- Dosptr *dp = f->ptr;
- Dosdir *d = dp->d;
- int isect, addr, o, c;
- Iosect *p;
- uchar *buf;
- long length, rcnt;
- rcnt = 0;
- length = GLONG(d->length);
- buf = vbuf;
- if(offset >= length)
- return 0;
- if(offset+count >= length)
- count = length - offset;
- isect = offset/bp->sectsize;
- o = offset%bp->sectsize;
- while(count > 0){
- addr = fileaddr(f, isect++, 0);
- if(addr < 0)
- break;
- c = bp->sectsize - o;
- if(c > count)
- c = count;
- p = getsect(xf, addr);
- if(p == 0)
- return -1;
- memmove(&buf[rcnt], &p->iobuf[o], c);
- putsect(p);
- count -= c;
- rcnt += c;
- o = 0;
- }
- return rcnt;
- }
- long
- writefile(Xfile *f, void *vbuf, long offset, long count)
- {
- Xfs *xf = f->xf;
- Dosbpb *bp = xf->ptr;
- Dosptr *dp = f->ptr;
- Dosdir *d = dp->d;
- int isect, addr = 0, o, c;
- Iosect *p;
- uchar *buf;
- long length, rcnt = 0, dlen;
- buf = vbuf;
- isect = offset/bp->sectsize;
- o = offset%bp->sectsize;
- while(count > 0){
- addr = fileaddr(f, isect++, 1);
- if(addr < 0)
- break;
- c = bp->sectsize - o;
- if(c > count)
- c = count;
- if(c == bp->sectsize){
- p = getosect(xf, addr);
- p->flags = 0;
- }else{
- p = getsect(xf, addr);
- if(p == nil)
- return -1;
- }
- memmove(&p->iobuf[o], &buf[rcnt], c);
- p->flags |= BMOD;
- putsect(p);
- count -= c;
- rcnt += c;
- o = 0;
- }
- if(rcnt <= 0 && addr < 0)
- return -1;
- length = 0;
- dlen = GLONG(d->length);
- if(rcnt > 0)
- length = offset+rcnt;
- else if(dp->addr && dp->clust){
- c = bp->clustsize*bp->sectsize;
- if(dp->iclust > (dlen+c-1)/c)
- length = c*dp->iclust;
- }
- if(length > dlen)
- PLONG(d->length, length);
- puttime(d, 0);
- dp->p->flags |= BMOD;
- return rcnt;
- }
- int
- truncfile(Xfile *f, long length)
- {
- Xfs *xf = f->xf;
- Dosbpb *bp = xf->ptr;
- Dosptr *dp = f->ptr;
- Dosdir *d = dp->d;
- long clust, next, n;
- mlock(bp);
- clust = getstart(f->xf, d);
- n = length;
- if(n <= 0)
- putstart(f->xf, d, 0);
- else
- n -= bp->sectsize;
- while(clust > 0){
- next = getfat(xf, clust);
- if(n <= 0)
- putfat(xf, clust, 0);
- else
- n -= bp->clustsize*bp->sectsize;
- clust = next;
- }
- unmlock(bp);
- PLONG(d->length, length);
- dp->iclust = 0;
- dp->clust = 0;
- dp->p->flags |= BMOD;
- return 0;
- }
- void
- putdir(Dosdir *d, Dir *dp)
- {
- if(dp->mode != ~0){
- if(dp->mode & 2)
- d->attr &= ~DRONLY;
- else
- d->attr |= DRONLY;
- if(dp->mode & DMEXCL)
- d->attr |= DSYSTEM;
- else
- d->attr &= ~DSYSTEM;
- }
- if(dp->mtime != ~0)
- puttime(d, dp->mtime);
- }
- /*
- * should extend this to deal with
- * creation and access dates
- */
- void
- getdir(Xfs *xfs, Dir *dp, Dosdir *d, int addr, int offset)
- {
- if(d == nil || addr == 0)
- panic("getdir on root");
- dp->type = 0;
- dp->dev = 0;
- getname(dp->name, d);
- dp->qid.path = addr*(Sectorsize/DOSDIRSIZE) +
- offset/DOSDIRSIZE;
- dp->qid.vers = 0;
- if(d->attr & DRONLY)
- dp->mode = 0444;
- else
- dp->mode = 0666;
- dp->atime = gtime(d);
- dp->mtime = dp->atime;
- dp->qid.type = QTFILE;
- if(d->attr & DDIR){
- dp->qid.type = QTDIR;
- dp->mode |= DMDIR|0111;
- dp->length = 0;
- }else
- dp->length = GLONG(d->length);
- if(d->attr & DSYSTEM){
- dp->mode |= DMEXCL;
- if(iscontig(xfs, d))
- dp->mode |= DMAPPEND;
- }
- dp->uid = "bill";
- dp->muid = "bill";
- dp->gid = "trog";
- }
- void
- getname(char *p, Dosdir *d)
- {
- int c, i;
- for(i=0; i<8; i++){
- c = d->name[i];
- if(c == '\0' || c == ' ')
- break;
- if(i == 0 && c == 0x05)
- c = 0xe5;
- *p++ = c;
- }
- for(i=0; i<3; i++){
- c = d->ext[i];
- if(c == '\0' || c == ' ')
- break;
- if(i == 0)
- *p++ = '.';
- *p++ = c;
- }
- *p = 0;
- }
- static char*
- getnamerunes(char *dst, uchar *buf, int step)
- {
- int i;
- Rune r;
- char dbuf[DOSRUNE * UTFmax + 1], *d;
- d = dbuf;
- r = 1;
- for(i = 1; r && i < 11; i += 2){
- r = buf[i] | (buf[i+1] << 8);
- d += runetochar(d, &r);
- }
- for(i = 14; r && i < 26; i += 2){
- r = buf[i] | (buf[i+1] << 8);
- d += runetochar(d, &r);
- }
- for(i = 28; r && i < 32; i += 2){
- r = buf[i] | (buf[i+1] << 8);
- d += runetochar(d, &r);
- }
- if(step == 1)
- dst -= d - dbuf;
- memmove(dst, dbuf, d - dbuf);
- if(step == -1){
- dst += d - dbuf;
- *dst = '\0';
- }
- return dst;
- }
- char*
- getnamesect(char *dbuf, char *d, uchar *buf, int *islong, int *sum, int step)
- {
- /*
- * validation checks to make sure we're
- * making up a consistent name
- */
- if(buf[11] != 0xf || buf[12] != 0){
- *islong = 0;
- return nil;
- }
- if(step == 1){
- if((buf[0] & 0xc0) == 0x40){
- *islong = buf[0] & 0x3f;
- *sum = buf[13];
- d = dbuf + DOSNAMELEN;
- *--d = '\0';
- }else if(*islong && *islong == buf[0] + 1 && *sum == buf[13]){
- *islong = buf[0];
- }else{
- *islong = 0;
- return nil;
- }
- }else{
- if(*islong + 1 == (buf[0] & 0xbf) && *sum == buf[13]){
- *islong = buf[0] & 0x3f;
- if(buf[0] & 0x40)
- *sum = -1;
- }else{
- *islong = 0;
- *sum = -1;
- return nil;
- }
- }
- if(*islong > 20){
- *islong = 0;
- *sum = -1;
- return nil;
- }
- return getnamerunes(d, buf, step);
- }
- void
- putname(char *p, Dosdir *d)
- {
- int i;
- memset(d->name, ' ', sizeof d->name+sizeof d->ext);
- for(i=0; i<sizeof d->name; i++){
- if(*p == 0 || *p == '.')
- break;
- d->name[i] = toupper(*p++);
- }
- p = strrchr(p, '.');
- if(p){
- for(i=0; i<sizeof d->ext; i++){
- if(*++p == 0)
- break;
- d->ext[i] = toupper(*p);
- }
- }
- }
- static void
- putnamesect(uchar *slot, Rune *longname, int curslot, int first, int sum)
- {
- Rune r;
- Dosdir ds;
- int i, j;
- memset(&ds, 0xff, sizeof ds);
- ds.attr = 0xf;
- ds.reserved[0] = 0;
- ds.reserved[1] = sum;
- ds.start[0] = 0;
- ds.start[1] = 0;
- if(first)
- ds.name[0] = 0x40 | curslot;
- else
- ds.name[0] = curslot;
- memmove(slot, &ds, sizeof ds);
- j = (curslot-1) * DOSRUNE;
- for(i = 1; i < 11; i += 2){
- r = longname[j++];
- slot[i] = r;
- slot[i+1] = r >> 8;
- if(r == 0)
- return;
- }
- for(i = 14; i < 26; i += 2){
- r = longname[j++];
- slot[i] = r;
- slot[i+1] = r >> 8;
- if(r == 0)
- return;
- }
- for(i = 28; i < 32; i += 2){
- r = longname[j++];
- slot[i] = r;
- slot[i+1] = r >> 8;
- if(r == 0)
- return;
- }
- }
- int
- aliassum(Dosdir *d)
- {
- int i, sum;
- if(d == nil)
- return -1;
- sum = 0;
- for(i = 0; i < 11; i++)
- sum = (((sum&1)<<7) | ((sum&0xfe)>>1)) + d->name[i];
- return sum & 0xff;
- }
- int
- putlongname(Xfs *xf, Dosptr *ndp, char *name, char sname[13])
- {
- Dosbpb *bp;
- Dosdir tmpd;
- Rune longname[DOSNAMELEN+1];
- int i, first, sum, nds, len;
- /* calculate checksum */
- putname(sname, &tmpd);
- sum = aliassum(&tmpd);
- bp = xf->ptr;
- first = 1;
- len = utftorunes(longname, name, DOSNAMELEN);
- if(chatty){
- chat("utftorunes %s =", name);
- for(i=0; i<len; i++)
- chat(" %.4X", longname[i]);
- chat("\n");
- }
- for(nds = (len + DOSRUNE-1) / DOSRUNE; nds > 0; nds--){
- putnamesect(&ndp->p->iobuf[ndp->offset], longname, nds, first, sum);
- first = 0;
- ndp->offset += 32;
- if(ndp->offset == bp->sectsize){
- chat("long name moving over sector boundary\n");
- ndp->p->flags |= BMOD;
- putsect(ndp->p);
- ndp->p = nil;
- /*
- * switch to the next cluster for a long entry
- * naddr should be set up correctly by searchdir
- */
- ndp->prevaddr = ndp->addr;
- ndp->addr = ndp->naddr;
- ndp->naddr = -1;
- if(ndp->addr == -1)
- return -1;
- ndp->p = getsect(xf, ndp->addr);
- if(ndp->p == nil)
- return -1;
- ndp->offset = 0;
- ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
- }
- }
- return 0;
- }
- long
- getfat(Xfs *xf, int n)
- {
- Dosbpb *bp = xf->ptr;
- Iosect *p;
- ulong k, sect;
- int o, fb;
- if(n < FATRESRV || n >= bp->fatclusters)
- return -1;
- fb = bp->fatbits;
- k = (fb * n) >> 3;
- if(k >= bp->fatsize*bp->sectsize)
- panic("getfat");
- sect = k/bp->sectsize + bp->fataddr;
- o = k%bp->sectsize;
- p = getsect(xf, sect);
- if(p == nil)
- return -1;
- k = p->iobuf[o++];
- if(o >= bp->sectsize){
- putsect(p);
- p = getsect(xf, sect+1);
- if(p == nil)
- return -1;
- o = 0;
- }
- k |= p->iobuf[o++]<<8;
- if(fb == 32){
- /* fat32 is really fat28 */
- k |= p->iobuf[o++] << 16;
- k |= (p->iobuf[o] & 0x0f) << 24;
- fb = 28;
- }
- putsect(p);
- if(fb == 12){
- if(n&1)
- k >>= 4;
- else
- k &= 0xfff;
- }
- if(chatty > 1)
- chat("fat(%#x)=%#lx...", n, k);
- /*
- * This is a very strange check for out of range.
- * As a concrete example, for a 16-bit FAT,
- * FFF8 through FFFF all signify ``end of cluster chain.''
- * This generalizes to other-sized FATs.
- */
- if(k >= (1 << fb) - 8)
- return -1;
- return k;
- }
- void
- putfat(Xfs *xf, int n, ulong val)
- {
- Fatinfo *fi;
- Dosbpb *bp;
- Iosect *p;
- ulong k, sect, esect;
- int o;
- bp = xf->ptr;
- if(n < FATRESRV || n >= bp->fatclusters)
- panic("putfat n=%d", n);
- k = (bp->fatbits * n) >> 3;
- if(k >= bp->fatsize*bp->sectsize)
- panic("putfat");
- sect = k/bp->sectsize + bp->fataddr;
- esect = sect + bp->nfats * bp->fatsize;
- for(; sect<esect; sect+=bp->fatsize){
- o = k%bp->sectsize;
- p = getsect(xf, sect);
- if(p == nil)
- continue;
- switch(bp->fatbits){
- case 12:
- if(n&1){
- p->iobuf[o] &= 0x0f;
- p->iobuf[o++] |= val<<4;
- if(o >= bp->sectsize){
- p->flags |= BMOD;
- putsect(p);
- p = getsect(xf, sect+1);
- if(p == nil)
- continue;
- o = 0;
- }
- p->iobuf[o] = val>>4;
- }else{
- p->iobuf[o++] = val;
- if(o >= bp->sectsize){
- p->flags |= BMOD;
- putsect(p);
- p = getsect(xf, sect+1);
- if(p == nil)
- continue;
- o = 0;
- }
- p->iobuf[o] &= 0xf0;
- p->iobuf[o] |= (val>>8) & 0x0f;
- }
- break;
- case 16:
- p->iobuf[o++] = val;
- p->iobuf[o] = val>>8;
- break;
- case 32: /* fat32 is really fat28 */
- p->iobuf[o++] = val;
- p->iobuf[o++] = val>>8;
- p->iobuf[o++] = val>>16;
- p->iobuf[o] = (p->iobuf[o] & 0xf0) | ((val>>24) & 0x0f);
- break;
- default:
- panic("putfat fatbits");
- }
- p->flags |= BMOD;
- putsect(p);
- }
- if(val == 0)
- bp->freeclusters++;
- else
- bp->freeclusters--;
- if(bp->fatinfo){
- p = getsect(xf, bp->fatinfo);
- if(p != nil){
- fi = (Fatinfo*)p->iobuf;
- PLONG(fi->nextfree, bp->freeptr);
- PLONG(fi->freeclust, bp->freeclusters);
- p->flags |= BMOD;
- putsect(p);
- }
- }
- }
- /*
- * Contiguous falloc; if we can, use lastclust+1.
- * Otherwise, move the file to get some space.
- * If there just isn't enough contiguous space
- * anywhere on disk, fail.
- */
- int
- cfalloc(Xfile *f)
- {
- int l;
- if((l=makecontig(f, 8)) >= 0)
- return l;
- return makecontig(f, 1);
- }
- /*
- * Check whether a file is contiguous.
- */
- int
- iscontig(Xfs *xf, Dosdir *d)
- {
- long clust, next;
- clust = getstart(xf, d);
- if(clust <= 0)
- return 1;
- for(;;) {
- next = getfat(xf, clust);
- if(next < 0)
- return 1;
- if(next != clust+1)
- return 0;
- clust = next;
- }
- return 0; /* not reached */
- }
- /*
- * Make a file contiguous, with nextra clusters of
- * free space after it for later expansion.
- * Return the number of the first new cluster.
- */
- int
- makecontig(Xfile *f, int nextra)
- {
- Dosbpb *bp;
- Dosdir *d;
- Dosptr *dp;
- Xfs *xf;
- Iosect *wp, *rp;
- long clust, next, last, start, rclust, wclust, eclust, ostart;
- int isok, i, n, nclust, nrun, rs, ws;
- xf = f->xf;
- bp = xf->ptr;
- dp = f->ptr;
- d = dp->d;
- isok = 1;
- nclust = 0;
- clust = fileclust(f, 0, 0);
- chat("clust %#lux", clust);
- if(clust != -1) {
- for(;;) {
- nclust++;
- chat(".");
- next = getfat(xf, clust);
- if(next <= 0)
- break;
- if(next != clust+1)
- isok = 0;
- clust = next;
- }
- }
- chat("nclust %d\n", nclust);
- if(isok && clust != -1) {
- eclust = clust+1; /* eclust = first cluster past file */
- assert(eclust == fileclust(f, 0, 0)+nclust);
- for(i=0; i<nextra; i++)
- if(getfat(xf, eclust+i) != 0)
- break;
- if(i == nextra) { /* they were all free */
- chat("eclust=%#lx, getfat eclust-1 = %#lux\n", eclust, getfat(xf, eclust-1));
- assert(getfat(xf, eclust-1) == 0xffffffff);
- putfat(xf, eclust-1, eclust);
- putfat(xf, eclust, 0xffffffff);
- bp->freeptr = clust+1; /* to help keep the blocks free */
- return eclust;
- }
- }
- /* need to search for nclust+nextra contiguous free blocks */
- last = -1;
- n = bp->freeptr;
- nrun = 0;
- for(;;){
- if(getfat(xf, n) == 0) {
- if(last+1 == n)
- nrun++;
- else
- nrun = 1;
- if(nrun >= nclust+nextra)
- break;
- last = n;
- }
- if(++n >= bp->fatclusters)
- n = FATRESRV;
- if(n == bp->freeptr) {
- errno = Econtig;
- return -1;
- }
- }
- bp->freeptr = n+1;
- /* copy old data over */
- start = n+1 - nrun;
- /* sanity check */
- for(i=0; i<nclust+nextra; i++)
- assert(getfat(xf, start+i) == 0);
- chat("relocate chain %lux -> 0x%lux len %d\n", fileclust(f, 0, 0), start, nclust);
- wclust = start;
- for(rclust = fileclust(f, 0, 0); rclust > 0; rclust = next){
- rs = clust2sect(bp, rclust);
- ws = clust2sect(bp, wclust);
- for(i=0; i<bp->clustsize; i++, rs++, ws++){
- rp = getsect(xf, rs);
- if(rp == nil)
- return -1;
- wp = getosect(xf, ws);
- assert(wp != nil);
- memmove(wp->iobuf, rp->iobuf, bp->sectsize);
- wp->flags = BMOD;
- putsect(rp);
- putsect(wp);
- }
- chat("move cluster %#lx -> %#lx...", rclust, wclust);
- next = getfat(xf, rclust);
- putfat(xf, wclust, wclust+1);
- wclust++;
- }
- /* now wclust points at the first new cluster; chain it in */
- chat("wclust 0x%lux start 0x%lux (fat->0x%lux) nclust %d\n", wclust, start, getfat(xf, start), nclust);
- assert(wclust == start+nclust);
- putfat(xf, wclust, 0xffffffff); /* end of file */
- /* update directory entry to point at new start */
- ostart = fileclust(f, 0, 0);
- putstart(xf, d, start);
- /* check our work */
- i = 0;
- clust = fileclust(f, 0, 0);
- if(clust != -1) {
- for(;;) {
- i++;
- next = getfat(xf, clust);
- if(next <= 0)
- break;
- assert(next == clust+1);
- clust = next;
- }
- }
- chat("chain check: len %d\n", i);
- assert(i == nclust+1);
- /* succeeded; remove old chain. */
- for(rclust = ostart; rclust > 0; rclust = next){
- next = getfat(xf, rclust);
- putfat(xf, rclust, 0); /* free cluster */
- }
- return start+nclust;
- }
- int
- falloc(Xfs *xf)
- {
- Dosbpb *bp = xf->ptr;
- Iosect *p;
- int n, i, k;
- n = bp->freeptr;
- for(;;){
- if(getfat(xf, n) == 0)
- break;
- if(++n >= bp->fatclusters)
- n = FATRESRV;
- if(n == bp->freeptr)
- return -1;
- }
- bp->freeptr = n+1;
- if(bp->freeptr >= bp->fatclusters)
- bp->freeptr = FATRESRV;
- putfat(xf, n, 0xffffffff);
- k = clust2sect(bp, n);
- for(i=0; i<bp->clustsize; i++){
- p = getosect(xf, k+i);
- memset(p->iobuf, 0, bp->sectsize);
- p->flags = BMOD;
- putsect(p);
- }
- return n;
- }
- void
- ffree(Xfs *xf, long start)
- {
- putfat(xf, start, 0);
- }
- long
- clust2sect(Dosbpb *bp, long clust)
- {
- return bp->dataaddr + (clust - FATRESRV) * bp->clustsize;
- }
- long
- sect2clust(Dosbpb *bp, long sect)
- {
- long c;
- c = (sect - bp->dataaddr) / bp->clustsize + FATRESRV;
- assert(sect == clust2sect(bp, c));
- return c;
- }
- void
- puttime(Dosdir *d, long s)
- {
- Tm *t;
- ushort x;
- if(s == 0)
- s = time(0);
- t = localtime(s);
- x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
- PSHORT(d->time, x);
- x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
- PSHORT(d->date, x);
- }
- long
- gtime(Dosdir *dp)
- {
- Tm tm;
- int i;
- i = GSHORT(dp->time);
- tm.hour = i >> 11;
- tm.min = (i >> 5) & 63;
- tm.sec = (i & 31) << 1;
- i = GSHORT(dp->date);
- tm.year = 80 + (i >> 9);
- tm.mon = ((i >> 5) & 15) - 1;
- tm.mday = i & 31;
- tm.zone[0] = '\0';
- tm.tzoff = 0;
- tm.yday = 0;
- return tm2sec(&tm);
- }
- /*
- * structure dumps for debugging
- */
- void
- bootdump(int fd, Dosboot *b)
- {
- Biobuf bp;
- Binit(&bp, fd, OWRITE);
- Bprint(&bp, "magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
- b->magic[0], b->magic[1], b->magic[2]);
- Bprint(&bp, "version: \"%8.8s\"\n", (char*)b->version);
- Bprint(&bp, "sectsize: %d\n", GSHORT(b->sectsize));
- Bprint(&bp, "clustsize: %d\n", b->clustsize);
- Bprint(&bp, "nresrv: %d\n", GSHORT(b->nresrv));
- Bprint(&bp, "nfats: %d\n", b->nfats);
- Bprint(&bp, "rootsize: %d\n", GSHORT(b->rootsize));
- Bprint(&bp, "volsize: %d\n", GSHORT(b->volsize));
- Bprint(&bp, "mediadesc: 0x%2.2x\n", b->mediadesc);
- Bprint(&bp, "fatsize: %d\n", GSHORT(b->fatsize));
- Bprint(&bp, "trksize: %d\n", GSHORT(b->trksize));
- Bprint(&bp, "nheads: %d\n", GSHORT(b->nheads));
- Bprint(&bp, "nhidden: %ld\n", GLONG(b->nhidden));
- Bprint(&bp, "bigvolsize: %ld\n", GLONG(b->bigvolsize));
- Bprint(&bp, "driveno: %d\n", b->driveno);
- Bprint(&bp, "reserved0: 0x%2.2x\n", b->reserved0);
- Bprint(&bp, "bootsig: 0x%2.2x\n", b->bootsig);
- Bprint(&bp, "volid: 0x%8.8lux\n", GLONG(b->volid));
- Bprint(&bp, "label: \"%11.11s\"\n", (char*)b->label);
- Bterm(&bp);
- }
- void
- bootdump32(int fd, Dosboot32 *b)
- {
- Biobuf bp;
- Binit(&bp, fd, OWRITE);
- Bprint(&bp, "magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
- b->magic[0], b->magic[1], b->magic[2]);
- Bprint(&bp, "version: \"%8.8s\"\n", (char*)b->version);
- Bprint(&bp, "sectsize: %d\n", GSHORT(b->sectsize));
- Bprint(&bp, "clustsize: %d\n", b->clustsize);
- Bprint(&bp, "nresrv: %d\n", GSHORT(b->nresrv));
- Bprint(&bp, "nfats: %d\n", b->nfats);
- Bprint(&bp, "rootsize: %d\n", GSHORT(b->rootsize));
- Bprint(&bp, "volsize: %d\n", GSHORT(b->volsize));
- Bprint(&bp, "mediadesc: 0x%2.2x\n", b->mediadesc);
- Bprint(&bp, "fatsize: %d\n", GSHORT(b->fatsize));
- Bprint(&bp, "trksize: %d\n", GSHORT(b->trksize));
- Bprint(&bp, "nheads: %d\n", GSHORT(b->nheads));
- Bprint(&bp, "nhidden: %ld\n", GLONG(b->nhidden));
- Bprint(&bp, "bigvolsize: %ld\n", GLONG(b->bigvolsize));
- Bprint(&bp, "fatsize32: %ld\n", GLONG(b->fatsize32));
- Bprint(&bp, "extflags: %d\n", GSHORT(b->extflags));
- Bprint(&bp, "version: %d\n", GSHORT(b->version1));
- Bprint(&bp, "rootstart: %ld\n", GLONG(b->rootstart));
- Bprint(&bp, "infospec: %d\n", GSHORT(b->infospec));
- Bprint(&bp, "backupboot: %d\n", GSHORT(b->backupboot));
- Bprint(&bp, "reserved: %d %d %d %d %d %d %d %d %d %d %d %d\n",
- b->reserved[0], b->reserved[1], b->reserved[2], b->reserved[3],
- b->reserved[4], b->reserved[5], b->reserved[6], b->reserved[7],
- b->reserved[8], b->reserved[9], b->reserved[10], b->reserved[11]);
- Bterm(&bp);
- }
- void
- bootsecdump32(int fd, Xfs *xf, Dosboot32 *b32)
- {
- Fatinfo *fi;
- Iosect *p1;
- int fisec, bsec, res;
- fprint(fd, "\nfat32\n");
- bootdump32(fd, b32);
- res = GSHORT(b32->nresrv);
- bsec = GSHORT(b32->backupboot);
- if(bsec < res && bsec != 0){
- p1 = getsect(xf, bsec);
- if(p1 == nil)
- fprint(fd, "\ncouldn't get backup boot sector: %r\n");
- else{
- fprint(fd, "\nbackup boot\n");
- bootdump32(fd, (Dosboot32*)p1->iobuf);
- putsect(p1);
- }
- }else if(bsec != 0xffff)
- fprint(fd, "bad backup boot sector: %d reserved %d\n", bsec, res);
- fisec = GSHORT(b32->infospec);
- if(fisec < res && fisec != 0){
- p1 = getsect(xf, fisec);
- if(p1 == nil)
- fprint(fd, "\ncouldn't get fat info sector: %r\n");
- else{
- fprint(fd, "\nfat info %d\n", fisec);
- fi = (Fatinfo*)p1->iobuf;
- fprint(fd, "sig1: 0x%lux sb 0x%lux\n", GLONG(fi->sig1), FATINFOSIG1);
- fprint(fd, "sig: 0x%lux sb 0x%lux\n", GLONG(fi->sig), FATINFOSIG);
- fprint(fd, "freeclust: %lud\n", GLONG(fi->freeclust));
- fprint(fd, "nextfree: %lud\n", GLONG(fi->nextfree));
- fprint(fd, "reserved: %lud %lud %lud\n", GLONG(fi->resrv), GLONG(fi->resrv+4), GLONG(fi->resrv+8));
- putsect(p1);
- }
- }else if(fisec != 0xffff)
- fprint(2, "bad fat info sector: %d reserved %d\n", bsec, res);
- }
- void
- dirdump(void *vdbuf)
- {
- static char attrchar[] = "rhsvda67";
- Dosdir *d;
- char *name, namebuf[DOSNAMELEN];
- char buf[128], *s, *ebuf;
- uchar *dbuf;
- int i;
- if(!chatty)
- return;
- d = vdbuf;
- ebuf = buf + sizeof(buf);
- if(d->attr == 0xf){
- dbuf = vdbuf;
- name = namebuf + DOSNAMELEN;
- *--name = '\0';
- name = getnamerunes(name, dbuf, 1);
- seprint(buf, ebuf, "\"%s\" %2.2x %2.2ux %2.2ux %d", name, dbuf[0], dbuf[12], dbuf[13], GSHORT(d->start));
- }else{
- s = seprint(buf, ebuf, "\"%.8s.%.3s\" ", (char*)d->name, (char*)d->ext);
- for(i=7; i>=0; i--)
- *s++ = d->attr&(1<<i) ? attrchar[i] : '-';
-
- i = GSHORT(d->time);
- s = seprint(s, ebuf, " %2.2d:%2.2d:%2.2d", i>>11, (i>>5)&63, (i&31)<<1);
- i = GSHORT(d->date);
- s = seprint(s, ebuf, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
-
- i = GSHORT(d->ctime);
- s = seprint(s, ebuf, " %2.2d:%2.2d:%2.2d", i>>11, (i>>5)&63, (i&31)<<1);
- i = GSHORT(d->cdate);
- s = seprint(s, ebuf, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
-
- i = GSHORT(d->adate);
- s = seprint(s, ebuf, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
- seprint(s, ebuf, " %d %d", GSHORT(d->start), GSHORT(d->length));
- }
- chat("%s\n", buf);
- }
- int
- cistrcmp(char *s1, char *s2)
- {
- int c1, c2;
- while(*s1){
- c1 = *s1++;
- c2 = *s2++;
- if(c1 >= 'A' && c1 <= 'Z')
- c1 -= 'A' - 'a';
- if(c2 >= 'A' && c2 <= 'Z')
- c2 -= 'A' - 'a';
- if(c1 != c2)
- return c1 - c2;
- }
- return -*s2;
- }
- int
- utftorunes(Rune *rr, char *s, int n)
- {
- Rune *r, *re;
- int c;
- r = rr;
- re = r + n - 1;
- while(c = (uchar)*s){
- if(c < Runeself){
- *r = c;
- s++;
- }else
- s += chartorune(r, s);
- r++;
- if(r >= re)
- break;
- }
- *r = 0;
- return r - rr;
- }
|