fdisk: attempt fixing extended partition handling

This commit is contained in:
cinap_lenrek 2011-07-17 21:17:28 +02:00
parent bd24f31a4e
commit 1c5d8e24e3

View file

@ -14,7 +14,7 @@ enum {
Mpart = 64,
};
static void rdpart(Edit*, uvlong, uvlong);
static void rdpart(Edit*, uvlong, uvlong, int);
static void findmbr(Edit*);
static void autopart(Edit*);
static void wrpart(Edit*);
@ -27,7 +27,6 @@ static int dowrite;
static int file;
static int rdonly;
static int doauto;
static vlong mbroffset;
static int printflag;
static int printchs;
static int sec2cyl;
@ -151,7 +150,7 @@ main(int argc, char **argv)
if(blank)
blankpart(&edit);
else
rdpart(&edit, 0, 0);
rdpart(&edit, 0, 0, 0);
if(doauto)
autopart(&edit);
@ -263,9 +262,9 @@ struct Dospart {
Part;
Tentry;
u32int lba;
u32int size;
int primary;
int ebrtype;
vlong ebrstart;
int primary;
};
struct Recover {
@ -385,11 +384,13 @@ Error:
}
static Dospart*
mkpart(char *name, int primary, vlong lba, vlong size, Tentry *t)
mkpart(char *name, vlong lba, vlong size, Tentry *t, vlong ebrstart, int ebrtype)
{
static int n;
int primary;
Dospart *p;
primary = (ebrstart == 0) && (ebrtype == 0);
p = emalloc(sizeof(*p));
if(name)
p->name = estrdup(name);
@ -406,18 +407,25 @@ mkpart(char *name, int primary, vlong lba, vlong size, Tentry *t)
p->changed = 0;
p->start = lba/sec2cyl;
p->end = (lba+size+sec2cyl-1)/sec2cyl;
p->ctlstart = lba;
p->ctlend = lba+size;
p->lba = lba;
if (p->lba != lba)
fprint(2, "%s: start of partition (%lld) won't fit in MBR table\n", argv0, lba);
p->size = size;
if (p->size != size)
fprint(2, "%s: size of partition (%lld) won't fit in MBR table\n", argv0, size);
p->ebrstart = ebrstart;
p->ebrtype = ebrtype;
p->primary = primary;
return p;
}
static int
mkebrtype(vlong end)
{
if(end >= 1024*sec2cyl)
return TypeEXTHUGE;
return TypeEXTENDED;
}
/*
* Recovery takes care of remembering what the various tables
* looked like when we started, attempting to restore them when
@ -481,7 +489,7 @@ recover(Edit *edit)
* from the disk into the part array.
*/
static void
rdpart(Edit *edit, uvlong lba, uvlong xbase)
rdpart(Edit *edit, uvlong xbase, uvlong ebrstart, int ebrtype)
{
char *err;
Table table;
@ -489,15 +497,12 @@ rdpart(Edit *edit, uvlong lba, uvlong xbase)
Dospart *p;
if(xbase == 0)
xbase = lba;
xbase = ebrstart;
diskread(edit->disk, &table, sizeof table, mbroffset+lba, Toffset);
addrecover(table, mbroffset+lba);
if(table.magic[0] != Magic0 || table.magic[1] != Magic1) {
assert(lba != 0);
diskread(edit->disk, &table, sizeof table, ebrstart, Toffset);
addrecover(table, ebrstart);
if(table.magic[0] != Magic0 || table.magic[1] != Magic1)
return;
}
for(tp=table.entry, ep=tp+NTentry; tp<ep && npart < Mpart; tp++) {
switch(tp->type) {
@ -506,10 +511,10 @@ rdpart(Edit *edit, uvlong lba, uvlong xbase)
case TypeEXTENDED:
case TypeEXTHUGE:
case TypeLINUXEXT:
rdpart(edit, xbase+getle32(tp->xlba), xbase);
rdpart(edit, xbase, xbase+getle32(tp->xlba), tp->type);
break;
default:
p = mkpart(nil, lba==0, lba+getle32(tp->xlba), getle32(tp->xsize), tp);
p = mkpart(nil, ebrstart+getle32(tp->xlba), getle32(tp->xsize), tp, ebrstart, ebrtype);
if(err = addpart(edit, p))
fprint(2, "adding partition: %s\n", err);
break;
@ -532,10 +537,6 @@ findmbr(Edit *edit)
diskread(edit->disk, &table, sizeof(Table), 0, Toffset);
if(table.magic[0] != Magic0 || table.magic[1] != Magic1)
sysfatal("did not find master boot record");
for(tp = table.entry; tp < &table.entry[NTentry]; tp++)
if(tp->type == TypeDMDDO)
mbroffset = edit->disk->s;
}
static int
@ -639,7 +640,7 @@ autopart(Edit *edit)
bigstart += edit->disk->s;
bigsize -= edit->disk->s;
}
p = mkpart(nil, 1, bigstart, bigsize, nil);
p = mkpart(nil, bigstart, bigsize, nil, 0, 0);
p->active = active;
p->changed = 1;
p->type = Type9;
@ -662,7 +663,6 @@ plan9print(Dospart *part, int fd)
int i, ok;
char *name, *vname;
Name *n;
vlong start, end;
char *sep;
vname = types[part->type].name;
@ -671,9 +671,6 @@ plan9print(Dospart *part, int fd)
return;
}
start = mbroffset+part->lba;
end = start+part->size;
/* avoid names like plan90 */
i = strlen(vname) - 1;
if(vname[i] >= '0' && vname[i] <= '9')
@ -703,7 +700,7 @@ plan9print(Dospart *part, int fd)
part->ctlname = name;
if(fd >= 0)
print("part %s %lld %lld\n", name, start, end);
print("part %s %lld %lld\n", name, part->ctlstart, part->ctlend);
}
static void
@ -798,14 +795,26 @@ static char*
cmdadd(Edit *edit, char *name, vlong start, vlong end)
{
Dospart *p;
vlong ebrstart;
int ebrtype;
if(!haveroom(edit, name[0]=='p', start))
return "no room for partition";
start *= sec2cyl;
end *= sec2cyl;
if(start == 0 || name[0] != 'p')
if(name[0] == 'p'){
ebrtype = 0;
ebrstart = 0;
if(start == 0)
start += edit->disk->s;
}else{
if(start == 0)
start += edit->disk->s;
ebrtype = mkebrtype(end);
ebrstart = start;
start += edit->disk->s;
p = mkpart(name, name[0]=='p', start, end-start, nil);
}
p = mkpart(name, start, end-start, nil, ebrstart, ebrtype);
p->changed = 1;
p->type = Type9;
return addpart(edit, p);
@ -1006,46 +1015,60 @@ wrextend(Edit *edit, int i, vlong xbase, vlong startlba, vlong *endlba)
Tentry *tp, *ep;
Dospart *p;
Disk *disk;
vlong nextebrstart;
int nextebrtype;
if(i == edit->npart){
*endlba = edit->disk->secs;
Finish:
if(startlba < *endlba){
disk = edit->disk;
diskread(disk, &table, sizeof table, mbroffset+startlba, Toffset);
diskread(disk, &table, sizeof table, startlba, Toffset);
tp = table.entry;
ep = tp+NTentry;
for(; tp<ep; tp++)
memset(tp, 0, sizeof *tp);
table.magic[0] = Magic0;
table.magic[1] = Magic1;
if(diskwrite(edit->disk, &table, sizeof table, mbroffset+startlba, Toffset) < 0)
if(diskwrite(edit->disk, &table, sizeof table, startlba, Toffset) < 0)
recover(edit);
}
return i;
}
p = (Dospart*)edit->part[i];
if(p->primary){
*endlba = (vlong)p->ctlstart;
*endlba = startlba;
goto Finish;
}
disk = edit->disk;
diskread(disk, &table, sizeof table, mbroffset+startlba, Toffset);
diskread(disk, &table, sizeof table, startlba, Toffset);
tp = table.entry;
ep = tp+NTentry;
ni = wrextend(edit, i+1, xbase, p->ctlend, endlba);
nextebrtype = TypeEMPTY;
if(i+1 >= edit->npart)
nextebrstart = p->ctlend;
else{
Dospart *x = (Dospart*)edit->part[i+1];
if(x->primary)
nextebrstart = x->ctlstart;
else{
nextebrstart = x->ebrstart;
nextebrtype = x->ebrtype;
}
}
ni = wrextend(edit, i+1, xbase, nextebrstart, endlba);
*tp = p->Tentry;
wrtentry(disk, tp, p->type, startlba, startlba+disk->s, p->ctlend);
wrtentry(disk, tp, p->type, startlba, p->ctlstart, p->ctlend);
tp++;
if(p->ctlend != *endlba){
if(nextebrstart != *endlba){
memset(tp, 0, sizeof *tp);
wrtentry(disk, tp, TypeEXTENDED, xbase, p->ctlend, *endlba);
if(nextebrtype == TypeEMPTY)
nextebrtype = mkebrtype(*endlba);
wrtentry(disk, tp, nextebrtype, xbase, nextebrstart, *endlba);
tp++;
}
@ -1055,7 +1078,7 @@ wrextend(Edit *edit, int i, vlong xbase, vlong startlba, vlong *endlba)
table.magic[0] = Magic0;
table.magic[1] = Magic1;
if(diskwrite(edit->disk, &table, sizeof table, mbroffset+startlba, Toffset) < 0)
if(diskwrite(edit->disk, &table, sizeof table, startlba, Toffset) < 0)
recover(edit);
return ni;
}
@ -1063,38 +1086,30 @@ wrextend(Edit *edit, int i, vlong xbase, vlong startlba, vlong *endlba)
static void
wrpart(Edit *edit)
{
int i, ni, t;
int i, ni;
Table table;
Tentry *tp, *ep;
Disk *disk;
vlong s, endlba;
vlong endlba;
Dospart *p;
disk = edit->disk;
diskread(disk, &table, sizeof table, mbroffset, Toffset);
diskread(disk, &table, sizeof table, 0, Toffset);
tp = table.entry;
ep = tp+NTentry;
for(i=0; i<edit->npart && tp<ep; ) {
p = (Dospart*)edit->part[i];
if(p->start == 0)
s = disk->s;
else
s = p->ctlstart;
if(p->primary) {
*tp = p->Tentry;
wrtentry(disk, tp, p->type, 0, s, p->ctlend);
wrtentry(disk, tp, p->type, 0, p->ctlstart, p->ctlend);
tp++;
i++;
} else {
ni = wrextend(edit, i, p->ctlstart, p->ctlstart, &endlba);
ni = wrextend(edit, i, p->ebrstart, p->ebrstart, &endlba);
memset(tp, 0, sizeof *tp);
if(endlba >= 1024*sec2cyl)
t = TypeEXTHUGE;
else
t = TypeEXTENDED;
wrtentry(disk, tp, t, 0, s, endlba);
wrtentry(disk, tp, p->ebrtype, 0, p->ebrstart, endlba);
tp++;
i = ni;
}
@ -1105,7 +1120,7 @@ wrpart(Edit *edit)
if(i != edit->npart)
sysfatal("cannot happen #1");
if(diskwrite(disk, &table, sizeof table, mbroffset, Toffset) < 0)
if(diskwrite(disk, &table, sizeof table, 0, Toffset) < 0)
recover(edit);
/* bring parts up to date */