f9c10dfd1a
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...
369 lines
7.8 KiB
C
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;
|
|
}
|