Initial revision
CVS patchset: 31 CVS date: 1995/12/13 20:13:49
This commit is contained in:
parent
b1df00c561
commit
75ab7b91d4
|
@ -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);
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue