/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * * $Id: chunk.c,v 1.3 1995/04/29 04:00:54 phk Exp $ * */ #include #include #include #include #include #include #include "libdisk.h" CHAR_N; #define new_chunk() malloc(sizeof(struct chunk)) /* Is c2 completely inside c1 ? */ static int Chunk_Inside(struct chunk *c1, struct chunk *c2) { /* if c1 ends before c2 do */ if (c1->end < c2->end) return 0; /* if c1 starts after c2 do */ if (c1->offset > c2->offset) return 0; return 1; } struct chunk * Find_Mother_Chunk(struct chunk *chunks, u_long offset, u_long end, chunk_e type) { struct chunk *c1,*c2,ct; ct.offset = offset; ct.end = end; switch (type) { case whole: if (Chunk_Inside(chunks,&ct)) return chunks; case extended: for(c1=chunks->part;c1;c1=c1->next) { if (c1->type != type) continue; if (Chunk_Inside(c1,&ct)) return c1; } return 0; break; case freebsd: for(c1=chunks->part;c1;c1=c1->next) { if (c1->type == type) if (Chunk_Inside(c1,&ct)) return c1; if (c1->type == extended) { for(c2=c1->part;c2;c2=c2->next) if (c2->type == type) if (Chunk_Inside(c2,&ct)) return c2; } } return 0; break; default: err(1,"Mumble!"); } } void Free_Chunk(struct chunk *c1) { /* XXX remove all chunks which "ref" us */ if(!c1) return; if(c1->part) Free_Chunk(c1->part); if(c1->next) Free_Chunk(c1->next); free(c1->name); free(c1); } struct chunk * Clone_Chunk(struct chunk *c1) { struct chunk *c2; if(!c1) return 0; c2 = new_chunk(); if (!c2) err(1,"malloc failed"); *c2 = *c1; c2->name = strdup(c2->name); c2->next = Clone_Chunk(c2->next); c2->part = Clone_Chunk(c2->part); return c2; } int Insert_Chunk(struct chunk *c2, u_long offset, u_long size, char *name, chunk_e type, int subtype, u_long flags) { struct chunk *ct,*cs; ct = new_chunk(); if (!ct) err(1,"malloc failed"); ct->offset = offset; ct->size = size; ct->end = offset + size - 1; ct->type = type; ct->name = strdup(name); ct->next = 0; ct->part = 0; ct->subtype = subtype; ct->flags = flags; if(type==freebsd || type==extended) { cs = new_chunk(); if (!cs) err(1,"malloc failed"); memset(cs,0,sizeof *cs); cs->offset = offset; cs->size = size; cs->end = offset + size - 1; cs->type = unused; cs->name = strdup("-"); cs->next = 0; cs->part = 0; ct->part = cs; } if (c2->type != unused) return __LINE__; if (Chunk_Inside(c2,ct)) { if (c2->end > ct->end) { cs = new_chunk(); if (!cs) err(1,"malloc failed"); *cs = *c2; cs->offset = ct->end + 1; cs->size = c2->end - ct->end; if(c2->name) cs->name = strdup(c2->name); c2->next = cs; c2->size -= c2->end - ct->end; c2->end = ct->end; } if (c2->offset == ct->offset) { c2->name = ct->name; c2->type = ct->type; c2->part = ct->part; c2->subtype = ct->subtype; c2->flags = ct->flags; ct->name = 0; ct->part = 0; Free_Chunk(ct); return 0; } c2->end = ct->offset - 1; c2->size -= ct->size; ct->next = c2->next; c2->next = ct; return 0; } return __LINE__; } int Add_Chunk(struct disk *d, u_long offset, u_long size, char *name, chunk_e type, int subtype, u_long flags) { struct chunk *c1,*c2,ct; u_long end = offset + size - 1; ct.offset = offset; ct.end = end; ct.size = size; if (type == whole) { d->chunks = c1 = new_chunk(); if (!c1) err(1,"malloc failed"); memset(c1,0,sizeof *c1); c2 = c1->part = new_chunk(); if (!c2) err(1,"malloc failed"); memset(c2,0,sizeof *c2); c2->offset = c1->offset = offset; c2->size = c1->size = size; c2->end = c1->end = end; c1->name = strdup(name); c2->name = strdup("-"); c1->type = type; c2->type = unused; c1->flags = flags; c1->subtype = subtype; return 0; } c1 = 0; if(!c1 && (type == freebsd || type == fat || type == foo)) c1 = Find_Mother_Chunk(d->chunks,offset,end,extended); if(!c1 && (type == freebsd || type == fat || type == foo)) c1 = Find_Mother_Chunk(d->chunks,offset,end,whole); if(!c1 && type == extended) c1 = Find_Mother_Chunk(d->chunks,offset,end,whole); if(!c1 && type == part) c1 = Find_Mother_Chunk(d->chunks,offset,end,freebsd); if(!c1 && type == reserved) c1 = Find_Mother_Chunk(d->chunks,offset,end,extended); if(!c1 && type == reserved) c1 = Find_Mother_Chunk(d->chunks,offset,end,whole); if(!c1) return __LINE__; for(c2=c1->part;c2;c2=c2->next) { if (c2->type != unused) continue; if(Chunk_Inside(c2,&ct)) return Insert_Chunk(c2,offset,size,name,type,subtype,flags); } return __LINE__; } void Print_Chunk(struct chunk *c1,int offset) { int i; if(!c1) return; for(i=0;i'); for(;i<10;i++) putchar(' '); printf("%p %10lu %10lu %10lu %-8s %d %-8s %d %lx\n", c1, c1->offset, c1->size, c1->end, c1->name, c1->type, chunk_n[c1->type],c1->subtype,c1->flags); Print_Chunk(c1->part,offset + 2); Print_Chunk(c1->next,offset); } void Debug_Chunk(struct chunk *c1) { Print_Chunk(c1,2); } void Bios_Limit_Chunk(struct chunk *c1, u_long limit) { if (c1->part) Bios_Limit_Chunk(c1->part,limit); if (c1->next) Bios_Limit_Chunk(c1->next,limit); if (c1->end >= limit) { c1->flags |= CHUNK_PAST_1024; } else { c1->flags &= ~CHUNK_PAST_1024; } } int Delete_Chunk(struct disk *d, struct chunk *c) { struct chunk *c1=0,*c2,*c3; chunk_e type = c->type; if(type == whole) return 1; if(!c1 && (type == freebsd || type == fat || type == foo)) c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,extended); if(!c1 && (type == freebsd || type == fat || type == foo)) c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,whole); if(!c1 && type == extended) c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,whole); if(!c1 && type == part) c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,freebsd); if(!c1) return 1; for(c2=c1->part;c2;c2=c2->next) { if (c2 == c) { c2->type = unused; c2->subtype = 0; c2->flags = 0; free(c2->name); c2->name = strdup("-"); Free_Chunk(c2->part); c2->part =0; goto scan; } } return 1; scan: for(c2=c1->part;c2;c2=c2->next) { if (c2->type != unused) continue; if (!c2->next) continue; if (c2->next->type != unused) continue; c3 = c2->next; c2->size += c3->size; c2->end = c3->end; c2->next = c3->next; c3->next = 0; Free_Chunk(c3); goto scan; } Fixup_Names(d); return 0; } int Collapse_Chunk(struct disk *d, struct chunk *c1) { struct chunk *c2, *c3; if(c1->next && Collapse_Chunk(d,c1->next)) return 1; if(c1->type == unused && c1->next && c1->next->type == unused) { c3 = c1->next; c1->size += c3->size; c1->end = c3->end; c1->next = c3->next; c3->next = 0; Free_Chunk(c3); return 1; } c3 = c1->part; if(!c3) return 0; if (Collapse_Chunk(d,c1->part)) return 1; if (c1->type == whole) return 0; if(c3->type == unused && c3->size == c1->size) { Delete_Chunk(d,c1); return 1; } if(c3->type == unused) { c2 = new_chunk(); *c2 = *c1; c1->next = c2; c1->name = strdup("-"); c1->part = 0; c1->type = unused; c1->flags = 0; c1->subtype = 0; c1->size = c3->size; c1->end = c3->end; c2->offset += c1->size; c2->size -= c1->size; c2->part = c3->next; c3->next = 0; Free_Chunk(c3); return 1; } for(c2=c3;c2->next;c2 = c2->next) c3 = c2; if (c2 && c2->type == unused) { c3->next = 0; c2->next = c1->next; c1->next = c2; c1->size -= c2->size; c1->end -= c2->size; return 1; } return 0; }