Initial revision
authorewt <devnull@localhost>
Wed, 13 Dec 1995 20:13:49 +0000 (20:13 +0000)
committerewt <devnull@localhost>
Wed, 13 Dec 1995 20:13:49 +0000 (20:13 +0000)
CVS patchset: 31
CVS date: 1995/12/13 20:13:49

lib/falloc.c [new file with mode: 0644]
lib/falloc.h [new file with mode: 0644]

diff --git a/lib/falloc.c b/lib/falloc.c
new file mode 100644 (file)
index 0000000..3f6ac14
--- /dev/null
@@ -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);
+}
diff --git a/lib/falloc.h b/lib/falloc.h
new file mode 100644 (file)
index 0000000..c633999
--- /dev/null
@@ -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