AmendHub

Download:

jcs

/

amend

/

amendments

/

71

bile: Sync with other projects: bug fixes and high id persistence


jcs made amendment 71 about 1 year 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