freebsd-src/lib/libdisk/chunk.c
Poul-Henning Kamp f9c10dfd1a Next Iteration, getting better.
Made an All_FreeBSD() function.
Added a cmd-line interface (lowest rank) to the tst01 program.
The tst01 program is harmless (worst it can do is coredump), but it
is instructive to run, you can see what the slice-code things of your
disk...
1995-04-29 04:00:57 +00:00

369 lines
7.8 KiB
C

/*
* ----------------------------------------------------------------------------
* "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: chunk.c,v 1.2 1995/04/29 01:55:19 phk Exp $
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.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 && 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<offset;i++) putchar('>');
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;
}
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;
}