#include "all.h" #include "mem.h" #include "io.h" #include "../pc/dosfs.h" #define dprint(...) if(pdebug)print(__VA_ARGS__) enum{ Npart = 8, Ntab = 8, Sblank = 0, Eblank = 0, }; typedef struct{ char type; uchar rem; /* unaligned partition */ Devsize start; Devsize end; char name[NAMELEN]; }Part; typedef struct{ char devstr[NAMELEN]; int n; Part tab[Npart]; }Tab; static Tab *tab; static int ntab; static int pdebug = 0; static void initpart(void) { static int done; if(done++) return; tab = ialloc(Ntab*sizeof *tab, 0); } /* * each Device has one partition table, even if d->dno is different. */ Tab* devtotab(Device *d, int *new) { char *s, buf[NAMELEN]; int i; Tab *t; initpart(); snprint(buf, sizeof buf, "%Z", d); for(i = 0; i < Ntab; i++){ t = tab+i; s = t->devstr; if(*s == 0){ memmove(s, buf, sizeof buf); *new = 1; return t; }else if(!strcmp(buf, s)) return t; } panic("too many partitioned devices"); return 0; } Devsize sectooff(Device *d, uvlong sec) { return (sec*devsecsize(d))/RBUFSIZE; } uvlong offtosec(Device *d, Off off) { return ((uvlong)off*RBUFSIZE)/devsecsize(d); } Part* addpart(Device *parent, Device *d, char *s, uvlong a, uvlong b, int sec) { uint sperrb; Tab *t; Part *p; dprint(" %Z %s [%lld, %lld) -> ", d, s, a, b); t = parent->private; if(t->n+1 == Npart){ print("too many partitions; part %s %lld %lld dropped\n", s, a, b); return t->tab+t->n; } p = t->tab+t->n++; sperrb = offtosec(d, 1); if(sperrb > 0) p->rem = a%sperrb; else p->rem = 0; if(sec){ p->type = 's'; p->start = sectooff(d, a+sperrb-1)+Sblank; /* round up */ p->end = sectooff(d, b&~(sperrb-1))-Eblank; /* round down */ }else{ p->type = 'o'; p->start = a; p->end = b; } if(p->end < p->start) print("bad partition %s %lld not < %lld\n", s, p->start, p->end); strncpy(p->name, s, NAMELEN); dprint("[%lld, %lld)\n", p->start, p->end); return p; } /* * read raw disk; only used for groking partition tables & reading * fat during configuration. very inefficient. */ static int tailio(Device *d, int write, uvlong byte, ulong l, void *buf) { int r; ulong rem; Devsize off; Msgbuf *t; t = mballoc(RBUFSIZE, 0, Mxxx); rem = byte&(RBUFSIZE-1); off = byte/RBUFSIZE; // print("tailio(%Z, %c, byte %llud [b %llud], %lud)\n", d, "rw"[write], byte, off, rem); r = devread(d, off, t->data); if(!r && write){ memmove(t->data+rem, buf, l); r = devwrite(d, off, t->data); }else if(!r) memmove(buf, t->data+rem, l); mbfree(t); return r; } Off byteio0(Device *d, int write, uvlong byte, ulong l, void *vbuf) { uchar *buf; ulong rem, l0; int (*io)(Device*, Off, void*); l0 = l; buf = vbuf; io = write? devwrite: devread; rem = RBUFSIZE - (byte%RBUFSIZE); if(rem){ if(rem > l) rem = l; if(tailio(d, write, byte, rem, buf)) goto done; byte += rem; buf += rem; l -= rem; } while(l >= RBUFSIZE){ if(io(d, byte/RBUFSIZE, buf)) goto done; byte += RBUFSIZE; buf += RBUFSIZE; l -= RBUFSIZE; } if(l){ if(byte%RBUFSIZE != 0) panic("byte%%rbufsize"); if(tailio(d, write, byte, l, buf)) goto done; byte += l; // buf += l; l -= l; } done: return l0-l; } int secio(Device *d, int write, uvlong sec, void *buf) { return byteio0(d, write, sec*512, 512, buf) != 512; } /* * deal with dos partitions placed on odd-sized boundaries. * to further our misfortune, byteio0 can't deal with negative * offsets. */ static Part *findpart(Device*, char*); Off byteio(Device *d, int write, uvlong byte, ulong l, void *vbuf) { uvlong rem; Part *p; if(d->type == Devpart){ p = findpart(d, d->part.name); rem = p->rem*devsecsize(d); if(rem) byte -= RBUFSIZE-rem; byte -= Sblank*RBUFSIZE; byte += d->part.base*RBUFSIZE; d = d->part.d; } return byteio0(d, write, byte, l, vbuf); } int mbrread(Device *d, uvlong sec, void *buf) { uchar *u; if(byteio(d, 0, sec*512, 512, buf) != 512) return 1; u = buf; if(u[0x1fe] != 0x55 || u[0x1ff] != 0xaa) return 1; return 0; } static int p9part(Device *parent, Device *d, uvlong sec, char *buf) { char *field[4], *line[Npart+1]; uvlong start, end; int i, n; if(secio(d, 0, sec+1, buf)) return 1; buf[512-1] = '\0'; if(strncmp(buf, "part ", 5)) return 1; n = getfields(buf, line, Npart+1, 1, "\n"); dprint("p9part %d lines..", n); if(n == 0) return -1; for(i = 0; i < n; i++){ if(strncmp(line[i], "part ", 5) != 0) break; if(getfields(line[i], field, 4, 0, " ") != 4) break; start = strtoull(field[2], 0, 0); end = strtoull(field[3], 0, 0); if(start >= end || end > offtosec(d, d->size)) break; addpart(parent, d, field[1], sec+start, sec+end, 1); } return 0; } int isdos(int t) { return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X; } int isextend(int t) { return t==EXTEND || t==EXTHUGE || t==LEXTEND; } static int mbrpart(Device *parent, Device *d, char *mbrbuf, char *partbuf) { char name[10]; int ndos, i, nplan9; ulong sec, start, end; ulong firstx, nextx, npart; Dospart *dp; int (*repart)(Device*, Device*, uvlong, char*); sec = 0; dp = (Dospart*)&mbrbuf[0x1be]; /* get the MBR (allowing for DMDDO) */ if(mbrread(d, sec, mbrbuf)) return 1; for(i=0; i<4; i++) if(dp[i].type == DMDDO) { dprint("DMDDO %d\n", i); sec = 63; if(mbrread(d, sec, mbrbuf)) return 1; i = -1; /* start over */ } /* * Read the partitions, first from the MBR and then * from successive extended partition tables. */ nplan9 = 0; ndos = 0; firstx = 0; for(npart=0;; npart++) { if(mbrread(d, sec, mbrbuf)) return 1; if(firstx) print("%Z ext %lud ", d, sec); else print("%Z mbr ", d); nextx = 0; for(i=0; i<4; i++) { start = sec+GLONG(dp[i].start); end = start+GLONG(dp[i].len); if(dp[i].type == 0 && start == 0 && end == 0) continue; dprint("type %x [%ld, %ld)", dp[i].type, start, end); repart = 0; if(dp[i].type == PLAN9) { if(nplan9 == 0) strcpy(name, "plan9"); else sprint(name, "plan9.%d", nplan9); repart = p9part; nplan9++; }else if(!ndos && isdos(dp[i].type)){ ndos = 1; strcpy(name, "dos"); }else snprint(name, sizeof name, "%ld", npart); if(end != 0){ dprint(" %s..", name); addpart(parent, d, name, start, end, 1); } if(repart) repart(parent, d, start, partbuf); /* nextx is relative to firstx (or 0), not sec */ if(isextend(dp[i].type)){ nextx = start-sec+firstx; dprint("link %lud...", nextx); } } dprint("\n"); if(!nextx) break; if(!firstx) firstx = nextx; sec = nextx; } return 0; } static int guessparttab(Tab *t) { int i, c; for(i = 0; i < t->n; i++){ c = t->tab[i].type; if(c == 's' || c == 'o') return 1; } return 0; } static Part* findpart(Device *d, char *s) { char c; int i; uvlong l, start, end; Part *p; Tab *t; t = d->private; if(s == 0) goto mkpart; for(i = 0; i < t->n; i++) if(!strcmp(t->tab[i].name, s)) return t->tab+i; panic("part %Z not found", d); mkpart: if(guessparttab(t)) print("warning: ignoring part table on %Z\n", d->part.d); if(d->part.base < 101 && d->part.size < 101){ c = '%'; l = d->part.d->size / 100; start = d->part.base*l; end = start + d->part.size*l; }else{ c = 'b'; start = d->part.base; end = d->part.size; } for(i = 0; i < t->n; i++){ p = t->tab+i; if(start == p->start) if(end == p->end) return p; } p = addpart(d, d->part.d, "", start, end, 0); if(c) p->type = c; snprint(p->name, sizeof p->name, "f%ld%ld", t-tab, p-t->tab); // BOTCH return p; } void partition(Device *parent, Device *d) { char *m, *p; int new; Msgbuf *mbr, *part; Part *q; new = 0; parent->private = devtotab(d, &new); if(new){ mbr = mballoc(RBUFSIZE, 0, Mxxx); part = mballoc(RBUFSIZE, 0, Mxxx); m = (char*)mbr->data; p = (char*)part->data; !mbrpart(parent, d, m, p) || p9part(parent, d, 0, p); mbfree(mbr); mbfree(part); } q = findpart(parent, parent->part.name); parent->part.base = q->start; parent->part.size = q->end-q->start; } void cmd_part(int argc, char **argv) { int i, j; Part *p; Tab *t; if(argc == 1 && !strcmp(*argv, "trace")){ pdebug ^= 1; return; } for(i = 0; i < Ntab; i++){ t = tab+i; if(*t->devstr == 0) continue; print("%d %s\n", i, t->devstr); for(j = 0; j < Npart; j++){ p = t->tab+j; if(*p->name == 0 && p->start == 0 && p->end == 0) continue; print(" %c\t%s\t%llud\t%llud r %d\n", p->type, p->name, p->start, p->end, p->rem); } } } void partinit(Device *d) { static int once; if(once++ == 0) cmd_install("part", "-- partition info", cmd_part); devinit(d->part.d); d->part.d->size = devsize(d->part.d); partition(d, d->part.d); } Devsize partsize(Device *d) { return d->part.size; } int partread(Device *d, Off b, void *c) { if(b < d->part.size) return devread(d->part.d, d->part.base+b, c); print("partread %llud %llud\n", (Wideoff)b, d->part.size); return 1; } int partwrite(Device *d, Off b, void *c) { if(b < d->part.size) return devwrite(d->part.d, d->part.base+b, c); print("partwrite %llud %llud\n", (Wideoff)b, d->part.size); return 1; } void partream(Device *d, int) { devream(d->part.d, 0); }