jcs
/subtext
/amendments
/46
bile: More work
jcs made amendment 46 over 2 years ago
--- bile.c Mon Jan 3 22:21:19 2022
+++ bile.c Tue Jan 4 16:30:53 2022
@@ -19,11 +19,12 @@
#include "util.h"
void bile_write_map(struct bile *bile);
-void bile_sort_objects(struct bile *bile);
+void bile_sort_by_pos(struct bile *bile);
void bile_free(struct bile *bile, unsigned long id);
+size_t bile_xwriteat(struct bile *bile, size_t pos, size_t len, void *data);
struct bile *
-bile_create(Str255 filename, OSType creator)
+bile_create(Str255 filename, OSType creator, OSType type)
{
struct bile *bile;
size_t len;
@@ -31,7 +32,7 @@ bile_create(Str255 filename, OSType creator)
short error, fh;
/* create file */
- error = Create(filename, 0, creator, BILE_FILE_TYPE);
+ error = Create(filename, 0, creator, type);
if (error)
panic("bile_create: failed to create %s: %d", PtoCstr(filename),
error);
@@ -159,22 +160,38 @@ bile_close(struct bile *bile)
/* XXX: these become invalid once we re-sort, should we return a copy? */
struct bile_object *
-bile_find(struct bile *bile, unsigned long id)
+bile_find(struct bile *bile, OSType type, unsigned long id)
{
struct bile_object *o;
unsigned long n;
- for (n = 0; n < bile->nobjects; n++) {
- o = &bile->map[n];
- if (o->id == id)
+ /* look backwards, optimizing for newer data */
+ for (n = bile->nobjects; n > 0; n--) {
+ o = &bile->map[n - 1];
+ if (o->type == type && o->id == id)
return o;
}
return NULL;
}
+size_t
+bile_next_id(struct bile *bile, OSType type)
+{
+ struct bile_object *o;
+ size_t n, id = 1;
+
+ for (n = 0; n < bile->nobjects; n++) {
+ o = &bile->map[n - 1];
+ if (o->type == type && o->id >= id)
+ id = o->id + 1;
+ }
+
+ return id;
+}
+
struct bile_object *
-bile_alloc(struct bile *bile, size_t size)
+bile_alloc(struct bile *bile, OSType type, unsigned long id, size_t size)
{
struct bile_object *new, *o;
size_t last_pos = BILE_HEADER_LEN;
@@ -194,13 +211,15 @@ bile_alloc(struct bile *bile, size_t size)
bile->nobjects++;
new->pos = last_pos;
new->size = size;
-
- bile_sort_objects(bile);
+ new->type = type;
+ new->id = id;
+ bile_sort_by_pos(bile);
+
/* find our new object pointer after sorting */
- for (n = 0; n < bile->nobjects; n++) {
- o = &bile->map[n];
- if (o->pos == last_pos)
+ for (n = bile->nobjects; n > 0; n--) {
+ o = &bile->map[n - 1];
+ if (o->type == type && o->pos == last_pos)
return o;
}
@@ -208,12 +227,11 @@ bile_alloc(struct bile *bile, size_t size)
}
void
-bile_sort_objects(struct bile *bile)
+bile_sort_by_pos(struct bile *bile)
{
short i, j;
struct bile_object o;
- /* sort maps by position */
for (i = 0; i < bile->nobjects; i++) {
for (j = 0; j < bile->nobjects - i - 1; j++) {
if (bile->map[j].pos > bile->map[j + 1].pos) {
@@ -226,18 +244,52 @@ bile_sort_objects(struct bile *bile)
}
void
-bile_free(struct bile *bile, unsigned long id)
+bile_delete(struct bile *bile, OSType type, unsigned long id)
{
- /* TODO */
+ struct bile_object *o;
+ size_t pos, size, wsize;
+ short error;
+ char *zero;
+
+ o = bile_find(bile, type, id);
+ if (o == NULL)
+ return;
+
+ o->type = BILE_PURGE_TYPE;
+ pos = o->pos;
+ size = o->size + BILE_OBJECT_SIZE;
+
+ bile_write_map(bile);
+
+ error = SetFPos(bile->vrefid, fsFromStart, pos);
+ if (error)
+ goto write_error;
+
+ zero = xmalloczero(128);
+ while (size > 0) {
+ wsize = MIN(128, size);
+ size -= wsize;
+
+ error = FSWrite(bile->vrefid, &wsize, zero);
+ if (error)
+ goto write_error;
+ }
+
+ return;
+
+write_error:
+ panic("bile_delete: failed writing to %s: %d", PtoCstr(bile->filename),
+ error);
}
size_t
-bile_read(struct bile *bile, unsigned long id, char **data)
+bile_read(struct bile *bile, OSType type, unsigned long id, char **data)
{
- struct bile_object *o = bile_find(bile, id);
+ struct bile_object *o, verify;
size_t rsize;
short error;
+ o = bile_find(bile, type, id);
if (o == NULL)
return -1;
@@ -252,8 +304,20 @@ bile_read(struct bile *bile, unsigned long id, char **
if (error)
goto read_error;
- /* TODO: read object header and verify size and id */
-
+ rsize = BILE_OBJECT_SIZE;
+ error = FSRead(bile->vrefid, &rsize, &verify);
+ if (error)
+ goto read_error;
+ if (verify.id != id)
+ panic("bile_read: object %ld pos %ld wrong id %ld, expected %ld",
+ id, o->pos, verify.id, id);
+ if (verify.type != type)
+ panic("bile_read: object %ld pos %ld wrong type %ld, expected %ld",
+ id, o->pos, verify.type, type);
+ if (verify.size != o->size)
+ panic("bile_read: object %ld pos %ld wrong size %ld, expected %ld",
+ id, o->pos, verify.size, o->size);
+
rsize = o->size;
error = FSRead(bile->vrefid, &rsize, *data);
if (error)
@@ -269,51 +333,28 @@ read_error:
}
size_t
-bile_write(struct bile *bile, unsigned long id, char *data, size_t size)
+bile_write(struct bile *bile, OSType type, unsigned long id, char *data,
+ size_t size)
{
struct bile_object *old, *new_obj;
- size_t ret, wsize;
+ size_t ret;
short error;
- new_obj = bile_alloc(bile, size);
- /* we must find after alloc because it re-sorts */
- old = bile_find(bile, id);
- new_obj->id = id;
+ old = bile_find(bile, type, id);
+ if (old)
+ old->type = BILE_PURGE_TYPE;
+
+ new_obj = bile_alloc(bile, type, id, size);
- if (new_obj->pos >= bile->file_size)
- error = SetFPos(bile->vrefid, fsFromLEOF, 0);
- else
- error = SetFPos(bile->vrefid, fsFromStart, new_obj->pos);
- if (error)
- goto write_error;
+ bile_xwriteat(bile, new_obj->pos, BILE_OBJECT_SIZE, new_obj);
+ bile_xwriteat(bile, new_obj->pos + BILE_OBJECT_SIZE, size, data);
- wsize = BILE_OBJECT_SIZE;
- error = FSWrite(bile->vrefid, &wsize, new_obj);
- if (error)
- goto write_error;
-
- wsize = size;
- error = FSWrite(bile->vrefid, &wsize, data);
- if (error)
- goto write_error;
- if (wsize != size)
- panic("bile_open: needed to write %ld, wrote %ld", size, wsize);
-
- error = SetFPos(bile->vrefid, fsFromLEOF, 0);
- if (error)
- goto write_error;
+ SetFPos(bile->vrefid, fsFromLEOF, 0);
GetFPos(bile->vrefid, &bile->file_size);
- if (old)
- old->id = BILE_PURGE_ID;
-
bile_write_map(bile);
return ret;
-
-write_error:
- panic("bile_write: failed writing %ld to %s: %d", size,
- PtoCstr(bile->filename), error);
}
void
@@ -321,58 +362,39 @@ bile_write_map(struct bile *bile)
{
struct bile_object *obj, *new_map_obj, *new_map;
size_t new_map_size, new_nobjects;
- size_t size, n, new_n;
+ size_t pos, n;
short error;
- char *magic;
-
- new_nobjects = 1; /* for the new map */
- for (n = 0; n < bile->nobjects; n++) {
- obj = &bile->map[n];
-
- if (obj->pos == bile->map_pos || obj->id == BILE_PURGE_ID)
- /* ignore old map and purgable objects */
- continue;
-
- new_nobjects++;
- }
+ /* allocate a new map slightly larger than we need */
+ new_nobjects = bile->nobjects;
+ if (!bile->map_pos)
+ new_nobjects++;
new_map_size = BILE_OBJECT_SIZE * new_nobjects;
- new_map_obj = bile_alloc(bile, new_map_size);
- new_map_obj->id = BILE_MAP_ID;
-
- /* write new map object header */
- if (new_map_obj->pos == bile->file_size)
- error = SetFPos(bile->vrefid, fsFromLEOF, 0);
- else
- error = SetFPos(bile->vrefid, fsFromStart, new_map_obj->pos);
- if (error)
- goto write_error;
-
- size = BILE_OBJECT_SIZE;
- error = FSWrite(bile->vrefid, &size, &new_map_obj);
- if (error)
- goto write_error;
-
+ new_map_obj = bile_alloc(bile, BILE_MAP_TYPE, 0, new_map_size);
new_map = xmallocarray(BILE_OBJECT_SIZE, new_nobjects);
- new_n = 0;
- for (n = 0; n < bile->nobjects; n++) {
+
+ for (n = 0, new_nobjects = 0; n < bile->nobjects; n++) {
obj = &bile->map[n];
- if (obj->pos == bile->map_pos || obj->id == BILE_PURGE_ID)
- /* ignore old map and purgable objects */
+ if (obj->type == BILE_MAP_TYPE && obj->pos == bile->map_pos)
+ /* don't include old map in new one */
continue;
-
- new_map[new_n++] = *obj;
+ if (obj->type == BILE_PURGE_TYPE)
+ continue;
+
+ new_map[new_nobjects++] = *obj;
}
- size = new_map_size;
- error = FSWrite(bile->vrefid, &size, new_map);
- if (error)
- goto write_error;
+ /* shrink to new object count */
+ new_map_size = BILE_OBJECT_SIZE * new_nobjects;
+ new_map_obj->size = new_map_size;
+ bile->nobjects = new_nobjects;
- error = SetFPos(bile->vrefid, fsFromLEOF, 0);
- if (error)
- goto write_error;
+ pos = bile_xwriteat(bile, new_map_obj->pos, BILE_OBJECT_SIZE,
+ &new_map_obj);
+ pos = bile_xwriteat(bile, pos, new_map_size, new_map);
+
+ SetFPos(bile->vrefid, fsFromLEOF, 0);
GetFPos(bile->vrefid, &bile->file_size);
/* successfully wrote new map, switch over */
@@ -382,29 +404,44 @@ bile_write_map(struct bile *bile)
bile->map_size = new_map_obj->size;
/* write new header to point at new map object */
- magic = xstrdup(BILE_MAGIC);
- size = BILE_MAGIC_LEN;
- error = SetFPos(bile->vrefid, fsFromStart, 0);
- if (error)
- goto write_error;
- error = FSWrite(bile->vrefid, &size, magic);
- free(magic);
- if (error)
- goto write_error;
- size = sizeof(long);
- error = FSWrite(bile->vrefid, &size, &bile->map_pos);
- if (error)
- goto write_error;
- error = FSWrite(bile->vrefid, &size, &bile->map_size);
- if (error)
- goto write_error;
+ pos = bile_xwriteat(bile, BILE_MAGIC_LEN, sizeof(long),
+ &bile->map_pos);
+ pos = bile_xwriteat(bile, pos, sizeof(long), &bile->map_size);
/* TODO: flush? */
+}
+
+size_t
+bile_xwriteat(struct bile *bile, size_t pos, size_t len, void *data)
+{
+ short error;
+ size_t wsize;
+ long asize;
- return;
-
-write_error:
- panic("bile_write_map: failed writing to %s: %d",
- PtoCstr(bile->filename), error);
+ if (pos == bile->file_size) {
+ error = SetFPos(bile->vrefid, fsFromLEOF, 0);
+ } else if (pos > bile->file_size) {
+ /* may as well allocate to cover len too */
+ asize = pos + len - bile->file_size;
+ error = Allocate(bile->vrefid, &asize);
+ if (error)
+ panic("bile_xwriteat: failed Allocate of %lu in %s: %d",
+ pos + len - bile->file_size, PtoCstr(bile->filename), error);
+ error = SetFPos(bile->vrefid, fsFromLEOF, 0);
+ } else
+ error = SetFPos(bile->vrefid, fsFromStart, pos);
+ if (error)
+ panic("bile_xwriteat: failed SetFPos to %lu in %s: %d",
+ pos, PtoCstr(bile->filename), error);
+ wsize = len;
+ error = FSWrite(bile->vrefid, &wsize, data);
+ if (error)
+ panic("bile_xwriteat: failed writing %lu at %lu to %s: %d",
+ len, pos, PtoCstr(bile->filename), error);
+ if (wsize != len)
+ panic("bile_xwriteat: short write of %lu at %lu to %s: %lu",
+ len, pos, PtoCstr(bile->filename), wsize);
+
+ return pos + len;
}
--- bile.h Mon Jan 3 22:22:07 2022
+++ bile.h Tue Jan 4 16:21:13 2022
@@ -25,25 +25,27 @@
* [ map contents - (map_size) ]
* [ object[0] position - long ]
* [ object[0] size - long ]
+ * [ object[0] type - long ]
* [ object[0] id - long ]
* [ ... ]
* [ object[0] start (map points to this as its position) ]
* [ object[0] position - long ]
* [ object[0] size - long ]
+ * [ object[0] type - long ]
* [ object[0] id - long ]
* [ object[1] start ]
* [ .. ]
*/
#define BILE_MAGIC "BILE1"
#define BILE_MAGIC_LEN 5
-#define BILE_MAP_ID (ULONG_MAX)
-#define BILE_PURGE_ID (ULONG_MAX - 1)
-#define BILE_FILE_TYPE 'BILE'
#define BILE_HEADER_LEN (BILE_MAGIC_LEN + (sizeof(long) + sizeof(long)))
+#define BILE_MAP_TYPE '_BLM'
+#define BILE_PURGE_TYPE '_BLP'
struct bile_object {
unsigned long pos;
unsigned long size;
+ OSType type;
unsigned long id;
};
#define BILE_OBJECT_SIZE (sizeof(struct bile_object))
@@ -59,11 +61,16 @@ struct bile {
size_t nobjects;
};
-struct bile * bile_create(Str255 filename, OSType creator);
+struct bile * bile_create(Str255 filename, OSType creator, OSType type);
struct bile * bile_open(Str255 filename);
void bile_close(struct bile *bile);
-struct bile_object * bile_find(struct bile *bile, unsigned long id);
-struct bile_object * bile_alloc(struct bile *bile, size_t size);
-size_t bile_read(struct bile *bile, unsigned long id, char **data);
-size_t bile_write(struct bile *bile, unsigned long id, char *data,
- size_t size);
+struct bile_object * bile_find(struct bile *bile, OSType type,
+ unsigned long id);
+size_t bile_next_id(struct bile *bile, OSType type);
+struct bile_object * bile_alloc(struct bile *bile, OSType type,
+ unsigned long id, size_t size);
+void bile_delete(struct bile *bile, OSType type, unsigned long id);
+size_t bile_read(struct bile *bile, OSType type, unsigned long id,
+ char **data);
+size_t bile_write(struct bile *bile, OSType type, unsigned long id,
+ char *data, size_t size);