Initial revision

CVS patchset: 31
CVS date: 1995/12/13 20:13:49
This commit is contained in:
ewt 1995-12-13 20:13:49 +00:00
parent b1df00c561
commit 75ab7b91d4
2 changed files with 222 additions and 0 deletions

202
lib/falloc.c Normal file
View File

@ -0,0 +1,202 @@
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "falloc.h"
#define FA_MAGIC 0x02050920
typedef unsigned int u32; /* this could be wrong someday */
struct faFileHeader{
u32 magic;
u32 firstFree;
};
/* the free list is kept *sorted* to keep fragment compaction fast */
struct faBlock {
u32 isFree;
u32 next; /* only meaningful if free */
u32 prev; /* only meaningful if free */
u32 size;
};
/* flags here is the same as for open(2) - NULL returned on error */
faFile faOpen(char * path, int flags, int perms) {
struct faFileHeader newHdr;
struct faFile_s fas;
faFile fa;
off_t end;
if (flags & O_WRONLY) {
return NULL;
}
if (flags & O_RDWR) {
fas.readOnly = 0;
} else {
fas.readOnly = 1;
}
fas.fd = open(path, flags, perms);
if (fas.fd < 0) return NULL;
/* is this file brand new? */
end = lseek(fas.fd, 0, SEEK_END);
if (!end) {
newHdr.magic = FA_MAGIC;
newHdr.firstFree = 0;
if (write(fas.fd, &newHdr, sizeof(newHdr)) != sizeof(newHdr)) {
close(fas.fd);
return NULL;
}
fas.firstFree = 0;
}
else {
if (read(fas.fd, &newHdr, sizeof(newHdr)) != sizeof(newHdr)) {
close(fas.fd);
return NULL;
}
if (newHdr.magic != FA_MAGIC) {
close(fas.fd);
return NULL;
}
fas.firstFree = newHdr.firstFree;
}
fa = malloc(sizeof(*fa));
if (fa) *fa = fas;
return fa;
}
unsigned int faAlloc(faFile fa, unsigned int size) { /* returns 0 on failure */
u32 nextFreeBlock;
u32 bestFreeBlock = 0;
u32 bestFreeSize = 0;
unsigned int newBlock;
struct faBlock block, prevBlock, nextBlock;
int failed = 0;
/* Make sure they are allocing multiples of four bytes. It'll keep
things smoother that way */
(size % 4) ? size += (4 - (size % 4)) : 0;
/* first, look through the free list for the best fit */
nextFreeBlock = fa->firstFree;
while (nextFreeBlock) {
if (lseek(fa->fd, nextFreeBlock, SEEK_SET) < 0) return 0;
if (read(fa->fd, &block, sizeof(block)) != sizeof(block)) return 0;
if (block.size >= size) {
if (bestFreeBlock) {
if (block.size < bestFreeSize) {
bestFreeSize = block.size;
bestFreeBlock = nextFreeBlock;
}
} else {
bestFreeSize = block.size;
bestFreeBlock = nextFreeBlock;
}
}
nextFreeBlock = block.next;
}
if (bestFreeBlock) {
if (lseek(fa->fd, bestFreeBlock, SEEK_SET) < 0) return 0;
if (read(fa->fd, &block, sizeof(block)) != sizeof(block))
return 0;
/* update the free list chain */
if (lseek(fa->fd, block.prev, SEEK_SET) < 0) return 0;
if (read(fa->fd, &prevBlock, sizeof(prevBlock)) != sizeof(prevBlock))
return 0;
if (lseek(fa->fd, block.next, SEEK_SET) < 0) return 0;
if (read(fa->fd, &nextBlock, sizeof(nextBlock)) != sizeof(nextBlock))
return 0;
prevBlock.next = block.next;
nextBlock.prev = block.prev;
if (lseek(fa->fd, block.prev, SEEK_SET) < 0) return 0;
if (write(fa->fd, &prevBlock, sizeof(prevBlock)) != sizeof(prevBlock))
return 0;
if (lseek(fa->fd, block.next, SEEK_SET) < 0) {
failed = 1;
} else {
if (write(fa->fd, &nextBlock, sizeof(nextBlock)) !=
sizeof(nextBlock)) {
failed = 1;
}
}
if (failed) {
/* try and restore the "prev" block, this won't be a complete
disaster */
prevBlock.next = bestFreeBlock;
lseek(fa->fd, block.prev, SEEK_SET);
write(fa->fd, &prevBlock, sizeof(prevBlock));
return 0;
}
block.isFree = 0; /* mark it as used */
block.prev = block.next = 0;
/* At some point, we should split this block into two if it's
bigger then the amount that's being allocated. Any space left
at the end of this block is wasted right now ***/
if (lseek(fa->fd, bestFreeBlock, SEEK_SET) < 0) {
failed = 1;
} else {
if (write(fa->fd, &block, sizeof(block)) != sizeof(block)) {
failed = 1;
}
}
if (failed) {
/* this space is gone :-( this really shouldn't ever happen. It
won't result in furthur date coruption though, so lets not
make it worse! */
return 0;
}
newBlock = bestFreeBlock;
} else {
char * space;
/* make a new block */
if (lseek(fa->fd, 0, SEEK_END) < 0) return 0;
newBlock = lseek(fa->fd, 0, SEEK_CUR);
space = calloc(1, size);
if (!space) return 0;
block.next = block.prev = 0;
block.size = size;
block.isFree = 0;
if (write(fa->fd, &block, sizeof(block)) != sizeof(block)) {
free(space);
return 0;
}
if (write(fa->fd, space, size) != size) {
free(space);
return 0;
}
free(space);
}
return newBlock + sizeof(block);
}
void faFree(faFile fa, unsigned int offset);
void faClose(faFile fa) {
close(fa->fd);
free(fa);
}

20
lib/falloc.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef H_FALLOC
#define H_FALLOC
/* File space allocation routines. Best fit allocation is used, free blocks
are compacted. Minimal fragmentation is more important then speed. This
uses 32 bit offsets on all platforms and should be byte order independent */
typedef struct faFile_s {
int fd;
int readOnly;
unsigned int firstFree;
} * faFile;
/* flags here is the same as for open(2) - NULL returned on error */
faFile faOpen(char * path, int flags, int perms);
unsigned int faAlloc(faFile fa, unsigned int size); /* returns 0 on failure */
void faFree(faFile fa, unsigned int offset);
void faClose(faFile fa);
#endif H_FALLOC