jcs
/amend
/amendments
/71
bile: Sync with other projects: bug fixes and high id persistence
jcs made amendment 71 over 2 years ago
--- bile.c Mon Jun 6 22:49:15 2022
+++ bile.c Tue Jun 14 09:47:55 2022
@@ -32,6 +32,7 @@ short bile_read_map(struct bile *bile,
short bile_write_map(struct bile *bile);
size_t bile_xwriteat(struct bile *bile, const size_t pos,
const void *data, const size_t len);
+void bile_check_sanity(struct bile *bile);
/* Public API */
@@ -63,8 +64,14 @@ bile_create(const Str255 filename, short vrefnum, cons
_bile_error = FSOpen(filename, vrefnum, &fh);
if (_bile_error)
return NULL;
-
+
+ _bile_error = SetEOF(fh, BILE_ALLOCATE_SIZE);
+ if (_bile_error)
+ return NULL;
+ SetFPos(fh, fsFromStart, 0);
+
bile = xmalloczero(sizeof(struct bile));
+ memcpy(bile->magic, BILE_MAGIC, sizeof(bile->magic));
bile->vrefnum = vrefnum;
bile->frefnum = fh;
bile->map_ptr.type = BILE_TYPE_MAPPTR;
@@ -117,7 +124,7 @@ struct bile *
bile_open(const Str255 filename, short vrefnum)
{
struct bile *bile = NULL;
- struct bile_object map_obj;
+ struct bile_object map_obj, *o;
char magic[BILE_MAGIC_LEN + 1];
size_t file_size, map_size, size;
short fh, old_map_tried = 0;
@@ -136,6 +143,7 @@ bile_open(const Str255 filename, short vrefnum)
SetFPos(fh, fsFromStart, 0);
bile = xmalloczero(sizeof(struct bile));
+ memcpy(bile->magic, BILE_MAGIC, sizeof(bile->magic));
bile->vrefnum = vrefnum;
bile->frefnum = fh;
memcpy(bile->filename, filename, sizeof(bile->filename));
@@ -189,6 +197,16 @@ open_bail:
return NULL;
}
+void
+bile_check_sanity(struct bile *bile)
+{
+ if (bile == NULL)
+ panic("bile_check_sanity: NULL bile");
+
+ if (memcmp(bile->magic, BILE_MAGIC, sizeof(bile->magic)) != 0)
+ panic("bile_check_sanity: bogus magic");
+}
+
struct bile *
bile_open_recover_map(const Str255 filename, short vrefnum)
{
@@ -207,20 +225,17 @@ bile_open_recover_map(const Str255 filename, short vre
}
short
-bile_autoflush(struct bile *bile, short val)
-{
- bile->autoflush = val;
-}
-
-short
bile_flush(struct bile *bile, short and_vol)
{
IOParam pb;
short ret;
+ bile_check_sanity(bile);
+
memset(&pb, 0, sizeof(pb));
pb.ioRefNum = bile->frefnum;
- ret = PBFlushFile(&pb, false);
+ /* if we're not flushing the volume, write async */
+ ret = PBFlushFile(&pb, !and_vol);
if (ret != noErr)
return ret;
@@ -238,8 +253,7 @@ bile_flush(struct bile *bile, short and_vol)
void
bile_close(struct bile *bile)
{
- if (bile == NULL)
- panic("bile_close: bogus bile");
+ bile_check_sanity(bile);
_bile_error = 0;
@@ -254,6 +268,8 @@ bile_find(struct bile *bile, const OSType type, const
struct bile_object *o, *ocopy;
unsigned long n;
+ bile_check_sanity(bile);
+
o = bile_object_in_map(bile, type, id);
if (o == NULL)
return NULL;
@@ -270,13 +286,12 @@ bile_count_by_type(struct bile *bile, const OSType typ
struct bile_object *o;
size_t n, count = 0;
- if (bile == NULL)
- panic("bile_count_by_type: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
for (n = 0; n < bile->nobjects; n++) {
- o = &bile->map[n - 1];
+ o = &bile->map[n];
if (o->type == type)
count++;
}
@@ -291,8 +306,10 @@ bile_sorted_ids_by_type(struct bile *bile, const OSTyp
size_t count = 0, size = 0, n, j, t;
size_t *ids;
+ bile_check_sanity(bile);
+
for (n = 0; n < bile->nobjects; n++) {
- o = &bile->map[n - 1];
+ o = &bile->map[n];
if (o->type != type)
continue;
@@ -322,13 +339,12 @@ bile_get_nth_of_type(struct bile *bile, const size_t i
struct bile_object *o, *ocopy;
size_t n, count = 0;
- if (bile == NULL)
- panic("bile_get_nth_of_type: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
for (n = 0; n < bile->nobjects; n++) {
- o = &bile->map[n - 1];
+ o = &bile->map[n];
if (o->type != type)
continue;
@@ -348,18 +364,24 @@ bile_next_id(struct bile *bile, const OSType type)
{
struct bile_object *o;
size_t n, id = 1;
+ unsigned long highest;
- if (bile == NULL)
- panic("bile_next_id: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
for (n = 0; n < bile->nobjects; n++) {
- o = &bile->map[n - 1];
+ o = &bile->map[n];
if (o->type == type && o->id >= id)
id = o->id + 1;
}
+ if (bile_read(bile, BILE_TYPE_HIGHESTID, type, &highest,
+ sizeof(unsigned long)) == sizeof(unsigned long)) {
+ if (highest > id)
+ id = highest + 1;
+ }
+
return id;
}
@@ -368,11 +390,11 @@ bile_delete(struct bile *bile, const OSType type, cons
{
static char zero[128] = { 0 };
struct bile_object *o;
- size_t pos, size, wsize;
-
- if (bile == NULL)
- panic("bile_delete: bogus bile");
+ size_t pos, size, wsize, n;
+ unsigned long highest;
+ bile_check_sanity(bile);
+
_bile_error = bile->last_error = 0;
o = bile_object_in_map(bile, type, id);
@@ -385,10 +407,6 @@ bile_delete(struct bile *bile, const OSType type, cons
pos = o->pos;
size = o->size + BILE_OBJECT_SIZE;
- bile_write_map(bile);
- if (_bile_error)
- return -1;
-
_bile_error = bile->last_error = SetFPos(bile->frefnum, fsFromStart,
pos);
if (_bile_error)
@@ -403,19 +421,44 @@ bile_delete(struct bile *bile, const OSType type, cons
if (_bile_error)
return -1;
}
+
+ /*
+ * If this is the highest id of this type, store it so it won't get
+ * handed out again from bile_next_id
+ */
+ highest = id;
+ for (n = 0; n < bile->nobjects; n++) {
+ o = &bile->map[n];
+ if (o->type == type && o->id > highest) {
+ highest = o->id;
+ break;
+ }
+ }
+ if (highest == id) {
+ /* store the type as the id, and the highest id as the data */
+ bile_write(bile, BILE_TYPE_HIGHESTID, type, &highest,
+ sizeof(unsigned long));
+
+ /* bile_write wrote a new map for us */
+ } else {
+ bile_write_map(bile);
+ if (_bile_error)
+ return -1;
+ }
+
return 0;
}
size_t
bile_read_object(struct bile *bile, const struct bile_object *o,
- char *data, const size_t len)
+ void *data, const size_t len)
{
struct bile_object verify;
size_t rsize, wantlen, ret;
- if (bile == NULL)
- panic("bile_read_object: bogus bile");
+ bile_check_sanity(bile);
+
if (o == NULL)
panic("bile_read_object: NULL object passed");
if (data == NULL)
@@ -491,45 +534,44 @@ bile_read_object(struct bile *bile, const struct bile_
size_t
bile_read(struct bile *bile, const OSType type, const unsigned long id,
- char *data, const size_t len)
+ void *data, const size_t len)
{
struct bile_object *o;
size_t ret;
- if (bile == NULL)
- panic("bile_read: bogus bile");
+ bile_check_sanity(bile);
+
if (data == NULL)
panic("bile_read: NULL data pointer passed");
_bile_error = bile->last_error = 0;
- o = bile_find(bile, type, id);
+ o = bile_object_in_map(bile, type, id);
if (o == NULL) {
_bile_error = bile->last_error = -1;
return 0;
}
- ret = bile_read_object(bile, o, data, len);
- free(o);
-
- return ret;
+ return bile_read_object(bile, o, data, len);
}
size_t
bile_read_alloc(struct bile *bile, const OSType type,
- const unsigned long id, char **data)
+ const unsigned long id, void *data_ptr)
{
struct bile_object *o;
size_t ret;
+ char **data;
+
+ bile_check_sanity(bile);
- if (bile == NULL)
- panic("bile_read: bogus bile");
- if (data == NULL)
+ if (data_ptr == NULL)
panic("bile_read: NULL data pointer passed");
-
+
+ data = (char **)data_ptr;
_bile_error = bile->last_error = 0;
- o = bile_find(bile, type, id);
+ o = bile_object_in_map(bile, type, id);
if (o == NULL) {
_bile_error = bile->last_error = -1;
*data = NULL;
@@ -538,7 +580,6 @@ bile_read_alloc(struct bile *bile, const OSType type,
*data = xmalloczero(o->size);
ret = bile_read_object(bile, o, *data, o->size);
- free(o);
return ret;
}
@@ -551,8 +592,8 @@ bile_write(struct bile *bile, const OSType type, const
size_t wrote;
short error;
- if (bile == NULL)
- panic("bile_write: bogus bile");
+ bile_check_sanity(bile);
+
if (len == 0)
panic("bile_write: zero len passed");
if (data == NULL)
@@ -585,17 +626,21 @@ bile_write(struct bile *bile, const OSType type, const
short
bile_marshall_object(struct bile *bile,
const struct bile_object_field *fields, const size_t nfields,
- void *object, char **ret, size_t *retsize)
+ void *object, void *ret_ptr, size_t *ret_size)
{
+ char **ret;
char *data, *ptr;
size_t size = 0, fsize = 0, n;
bool write = false;
- if (ret == NULL)
+ bile_check_sanity(bile);
+
+ if (ret_ptr == NULL)
panic("bile_pack_object invalid ret");
+ ret = (char **)ret_ptr;
*ret = NULL;
- *retsize = 0;
+ *ret_size = 0;
iterate_fields:
for (n = 0; n < nfields; n++) {
@@ -643,7 +688,7 @@ iterate_fields:
}
*ret = data;
- *retsize = size;
+ *ret_size = size;
return 0;
}
@@ -651,15 +696,17 @@ iterate_fields:
short
bile_unmarshall_object(struct bile *bile,
const struct bile_object_field *fields, const size_t nfields,
- const char *data, const size_t size, void *object, bool deep)
+ const void *data, const size_t size, void *object, bool deep)
{
size_t off, fsize = 0, n;
char *ptr, *dptr;
+ bile_check_sanity(bile);
+
for (off = 0, n = 0; n < nfields; n++) {
if (fields[n].size < 0) {
/* dynamically-sized field, read length */
- memcpy(&fsize, data + off, sizeof(fsize));
+ memcpy(&fsize, (char *)data + off, sizeof(fsize));
off += sizeof(fsize);
} else
fsize = fields[n].size;
@@ -679,7 +726,7 @@ bile_unmarshall_object(struct bile *bile,
if (fields[n].size < 0 && !deep)
memset(ptr, 0, sizeof(dptr));
else
- memcpy(ptr, data + off, fsize);
+ memcpy(ptr, (char *)data + off, fsize);
off += fsize;
}
@@ -692,20 +739,23 @@ short
bile_verify(struct bile *bile)
{
struct bile_object o;
- size_t n, size;
+ size_t n, size, pos;
char data;
- if (bile == NULL)
- panic("bile_verify: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
- for (n = 0; n < bile->nobjects; n++) {
+ for (n = 0, pos = 0; n < bile->nobjects; n++) {
size = bile_read_object(bile, &bile->map[n], &data, 1);
if (bile_error(bile))
return bile_error(bile);
else if (size == 0)
return -1;
+
+ if (bile->map[n].pos <= pos)
+ return -1;
+ pos = bile->map[n].pos + bile->map[n].size;
}
return 0;
@@ -720,8 +770,7 @@ bile_object_in_map(struct bile *bile, const OSType typ
struct bile_object *o;
size_t n;
- if (bile == NULL)
- panic("bile_find: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
@@ -743,18 +792,17 @@ bile_alloc(struct bile *bile, const OSType type, const
size_t last_pos = BILE_HEADER_LEN;
size_t n, map_pos;
- if (bile == NULL)
- panic("bile_alloc: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
- /* find a last_pos we can use */
+ /* find a gap big enough to hold our object + its size */
for (n = 0; n < bile->nobjects; n++) {
if (bile->map[n].pos - last_pos >= (size + BILE_OBJECT_SIZE))
break;
last_pos = bile->map[n].pos + BILE_OBJECT_SIZE + bile->map[n].size;
}
-
+
/*
* The map is always sorted, so walk the map to find out where to
* wedge a copy of this new object, then return a pointer to it in
@@ -797,6 +845,8 @@ bile_read_map(struct bile *bile, struct bile_object *m
size_t size;
struct bile_object map_obj, *map;
+ bile_check_sanity(bile);
+
if (map_ptr->pos + map_ptr->size > bile->file_size) {
warn("bile_read_map: map points to %lu + %lu, but file is only %lu",
map_ptr->pos, map_ptr->size, bile->file_size);
@@ -855,8 +905,7 @@ bile_write_map(struct bile *bile)
size_t n;
short ret;
- if (bile == NULL)
- panic("bile_write_map: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
@@ -908,11 +957,9 @@ bile_write_map(struct bile *bile)
SetFPos(bile->frefnum, fsFromLEOF, 0);
GetFPos(bile->frefnum, &bile->file_size);
- if (bile->autoflush) {
- if ((ret = bile_flush(bile, false)) != noErr) {
- warn("bile_write_map: flush failed: %d", ret);
- return -1;
- }
+ if ((ret = bile_flush(bile, false)) != noErr) {
+ warn("bile_write_map: flush failed: %d", ret);
+ return -1;
}
/* successfully wrote new map, switch over */
@@ -936,11 +983,9 @@ bile_write_map(struct bile *bile)
if (bile->last_error)
return -1;
- if (bile->autoflush) {
- if ((ret = bile_flush(bile, false)) != noErr) {
- warn("bile_write_map: final flush failed: %d", ret);
- return -1;
- }
+ if ((ret = bile_flush(bile, false)) != noErr) {
+ warn("bile_write_map: final flush failed: %d", ret);
+ return -1;
}
return 0;
@@ -951,29 +996,27 @@ bile_xwriteat(struct bile *bile, const size_t pos, con
const size_t len)
{
short error;
- size_t wsize;
+ size_t wsize, tsize;
long asize;
- if (bile == NULL)
- panic("bile_xwriteat: bogus bile");
+ bile_check_sanity(bile);
_bile_error = bile->last_error = 0;
- if (pos == bile->file_size) {
- _bile_error = bile->last_error = SetFPos(bile->frefnum, fsFromLEOF,
- 0);
- } else if (pos > bile->file_size) {
- /* may as well allocate to cover len too */
- asize = pos + len - bile->file_size;
- _bile_error = Allocate(bile->frefnum, &asize);
+ if (pos + len > bile->file_size) {
+ /* add new space aligning to BILE_ALLOCATE_SIZE */
+ tsize = pos + len;
+ tsize += BILE_ALLOCATE_SIZE - (tsize % BILE_ALLOCATE_SIZE);
+ _bile_error = SetEOF(bile->frefnum, tsize);
if (_bile_error)
return 0;
- _bile_error = bile->last_error = SetFPos(bile->frefnum, fsFromLEOF,
- 0);
- } else
- _bile_error = bile->last_error = SetFPos(bile->frefnum,
- fsFromStart, pos);
-
+ _bile_error = bile->last_error = bile_flush(bile, true);
+ if (_bile_error)
+ return 0;
+ }
+
+ _bile_error = bile->last_error = SetFPos(bile->frefnum, fsFromStart,
+ pos);
if (_bile_error)
return 0;
--- bile.h Mon Jun 6 22:49:23 2022
+++ bile.h Tue Jun 14 09:14:48 2022
@@ -48,11 +48,12 @@
* [ map id - long ]
* [ map contents ]
*/
-#define BILE_MAGIC "BILE2"
-#define BILE_MAGIC_LEN 5
-#define BILE_TYPE_MAP '_BLM'
-#define BILE_TYPE_MAPPTR '_BL>'
-#define BILE_TYPE_PURGE '_BLP'
+#define BILE_MAGIC "BILE2"
+#define BILE_MAGIC_LEN 5
+#define BILE_TYPE_MAP '_BLM'
+#define BILE_TYPE_MAPPTR '_BL>'
+#define BILE_TYPE_PURGE '_BLP'
+#define BILE_TYPE_HIGHESTID '_BLH'
struct bile_object {
unsigned long pos;
@@ -63,6 +64,9 @@ struct bile_object {
#define BILE_OBJECT_SIZE (sizeof(struct bile_object))
#define BILE_HEADER_LEN 256
+/* allocate filesystem space in chunks of this */
+#define BILE_ALLOCATE_SIZE 8192
+
#ifndef BILE1_MAGIC
#define BILE1_MAGIC "BILE1"
#endif
@@ -73,6 +77,11 @@ struct bile_object {
#define BILE_ERR_NEED_UPGRADE_1 -4000
#define BILE_ERR_BOGUS_OBJECT -4001
+struct bile_highest_id {
+ OSType type;
+ unsigned long highest_id;
+};
+
struct bile {
struct bile_object map_ptr;
struct bile_object old_map_ptr;
@@ -81,7 +90,7 @@ struct bile {
size_t file_size;
struct bile_object *map; /* array of bile_objects */
size_t nobjects;
- short autoflush;
+ char magic[5];
};
struct bile_object_field {
@@ -98,7 +107,6 @@ struct bile * bile_open(const Str255 filename, short
struct bile * bile_open_recover_map(const Str255 filename,
short vrefnum);
short bile_flush(struct bile *bile, short and_vol);
-short bile_autoflush(struct bile *bile, short val);
void bile_close(struct bile *bile);
struct bile_object * bile_find(struct bile *bile, const OSType type,
@@ -113,14 +121,14 @@ size_t bile_next_id(struct bile *bile, const OSTyp
short bile_delete(struct bile *bile, const OSType type,
const unsigned long id);
size_t bile_read_object(struct bile *bile,
- const struct bile_object *o, char *data,
+ const struct bile_object *o, void *data,
const size_t len);
size_t bile_read(struct bile *bile, const OSType type,
- const unsigned long id, char *data,
+ const unsigned long id, void *data,
const size_t len);
size_t bile_read_alloc(struct bile *bile,
const OSType type, const unsigned long id,
- char **data);
+ void *data_ptr);
size_t bile_write(struct bile *bile, OSType type,
const unsigned long id, const void *data,
const size_t len);
@@ -128,11 +136,11 @@ short bile_verify(struct bile *bile);
short bile_marshall_object(struct bile *bile,
const struct bile_object_field *fields,
- const size_t nfields, void *object, char **ret,
- size_t *retsize);
+ const size_t nfields, void *object,
+ void *ret_ptr, size_t *ret_size);
short bile_unmarshall_object(struct bile *bile,
const struct bile_object_field *fields,
- const size_t nfields, const char *data,
+ const size_t nfields, const void *data,
const size_t size, void *object, bool deep);
#endif