diff options
author | phk <phk@FreeBSD.org> | 1995-04-28 23:57:04 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1995-04-28 23:57:04 +0000 |
commit | 773ad9f330436a3c7484840bf3a542958fd14c96 (patch) | |
tree | 52b9513433e8fa4d94139f8ec002668ef2560b11 /lib/libdisk/chunk.c | |
parent | e31775a1086bdadc2cd01b0eed72cb217fb1e9e8 (diff) | |
download | FreeBSD-src-773ad9f330436a3c7484840bf3a542958fd14c96.zip FreeBSD-src-773ad9f330436a3c7484840bf3a542958fd14c96.tar.gz |
This is a revision 0.00 of the backend stuff for the fdisk/disklabel stuff
in the new sysinstall. If you want to give a helping hand, then send email
to phk@FreeBSD.ORG. DO NOT COMMIT TO THIS DIRECTORY!
Diffstat (limited to 'lib/libdisk/chunk.c')
-rw-r--r-- | lib/libdisk/chunk.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/lib/libdisk/chunk.c b/lib/libdisk/chunk.c new file mode 100644 index 0000000..088b5ab --- /dev/null +++ b/lib/libdisk/chunk.c @@ -0,0 +1,365 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> 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$ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/queue.h> +#include <err.h> +#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(name); + 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) + 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<offset;i++) putchar('>'); + for(;i<10;i++) putchar(' '); + printf("%10lu %10lu %10lu %-8s %d %-8s %d %lx\n", + 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, u_long offset, u_long end, chunk_e type) +{ + struct chunk *c1=0,*c2,*c3; + + if(type == whole) + return 1; + 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) + return 1; + for(c2=c1->part;c2;c2=c2->next) { + if (c2->offset == offset && + c2->end == end && + c2->type == type) { + 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; + } + 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->offset, c1->end, c1->type); + 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; +} |