1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930 |
- #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;
- }
- }
- /*
- * 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;
- }
|