jcs
/subtext
/amendments
/58
bile: Sync with upstream
jcs made amendment 58 over 2 years ago
--- bile.c Tue Jan 18 16:50:07 2022
+++ bile.c Fri Jan 21 17:59:46 2022
@@ -19,12 +19,16 @@
#include "util.h"
/* for errors not specific to a bile */
-static short _bile_error;
+static short _bile_error = 0;
+static short _bile_open_ignore_primary_map = 0;
+
struct bile_object * bile_alloc(struct bile *bile, const OSType type,
const unsigned long id, const size_t size);
struct bile_object * bile_object_in_map(struct bile *bile,
const OSType type, const unsigned long id);
+short bile_read_map(struct bile *bile,
+ struct bile_object *map_ptr);
short bile_write_map(struct bile *bile);
void bile_sort_by_pos(struct bile *bile);
size_t bile_xwriteat(struct bile *bile, const size_t pos,
@@ -47,7 +51,7 @@ bile_create(const Str255 filename, short vrefnum, cons
{
struct bile *bile = NULL;
size_t len;
- char *magic;
+ char *tmp;
short fh;
_bile_error = 0;
@@ -69,9 +73,9 @@ bile_create(const Str255 filename, short vrefnum, cons
/* write magic */
len = BILE_MAGIC_LEN;
- magic = xstrdup(BILE_MAGIC);
- _bile_error = FSWrite(bile->frefnum, &len, magic);
- free(magic);
+ tmp = xstrdup(BILE_MAGIC);
+ _bile_error = FSWrite(bile->frefnum, &len, tmp);
+ free(tmp);
if (_bile_error)
goto create_bail;
@@ -81,6 +85,20 @@ bile_create(const Str255 filename, short vrefnum, cons
if (_bile_error)
goto create_bail;
+ len = sizeof(bile->old_map_ptr);
+ _bile_error = FSWrite(bile->frefnum, &len, &bile->old_map_ptr);
+ if (_bile_error)
+ goto create_bail;
+
+ /* padding */
+ len = BILE_HEADER_LEN - BILE_MAGIC_LEN - BILE_OBJECT_SIZE -
+ BILE_OBJECT_SIZE;
+ tmp = xmalloczero(len);
+ _bile_error = FSWrite(bile->frefnum, &len, tmp);
+ if (_bile_error)
+ goto create_bail;
+ free(tmp);
+
GetFPos(fh, &bile->file_size);
if (bile->file_size != BILE_HEADER_LEN)
@@ -101,9 +119,9 @@ bile_open(const Str255 filename, short vrefnum)
{
struct bile *bile = NULL;
struct bile_object map_obj;
- size_t file_size, map_size, size;
- short fh;
char magic[BILE_MAGIC_LEN + 1];
+ size_t file_size, map_size, size;
+ short fh, old_map_tried = 0;
_bile_error = 0;
@@ -118,6 +136,12 @@ bile_open(const Str255 filename, short vrefnum)
GetFPos(fh, &file_size);
SetFPos(fh, fsFromStart, 0);
+ bile = xmalloczero(sizeof(struct bile));
+ bile->vrefnum = vrefnum;
+ bile->frefnum = fh;
+ memcpy(bile->filename, filename, sizeof(bile->filename));
+ bile->file_size = file_size;
+
/* verify magic */
size = BILE_MAGIC_LEN;
_bile_error = FSRead(fh, &size, &magic);
@@ -125,55 +149,36 @@ bile_open(const Str255 filename, short vrefnum)
goto open_bail;
if (strncmp(magic, BILE_MAGIC, BILE_MAGIC_LEN) != 0) {
- _bile_error = -1;
+ if (strncmp(magic, BILE1_MAGIC, BILE1_MAGIC_LEN) == 0)
+ _bile_error = BILE_ERR_NEED_UPGRADE_1;
+ else
+ _bile_error = -1;
goto open_bail;
}
-
- bile = xmalloczero(sizeof(struct bile));
- bile->vrefnum = vrefnum;
- bile->frefnum = fh;
- memcpy(bile->filename, filename, sizeof(bile->filename));
- bile->file_size = file_size;
-
+
/* load map pointer */
size = sizeof(bile->map_ptr);
_bile_error = FSRead(bile->frefnum, &size, &bile->map_ptr);
if (_bile_error)
goto open_bail;
+
+ /* old map pointer */
+ size = sizeof(bile->old_map_ptr);
+ _bile_error = FSRead(bile->frefnum, &size, &bile->old_map_ptr);
+ if (_bile_error)
+ goto open_bail;
- if (bile->map_ptr.pos + bile->map_ptr.size > file_size)
- panic("bile_open: map points to %lu + %lu, but file is only %lu",
- bile->map_ptr.pos, bile->map_ptr.size, file_size);
- if (bile->map_ptr.size % BILE_OBJECT_SIZE != 0)
- panic("bile_open: map pointer size is not a multiple of object "
- "size (%lu): %lu", BILE_OBJECT_SIZE, bile->map_ptr.size);
+ if (_bile_open_ignore_primary_map) {
+ if (!bile->old_map_ptr.size)
+ goto open_bail;
+ bile->map_ptr = bile->old_map_ptr;
+ }
if (bile->map_ptr.size) {
- /* read and verify map object header map_ptr points to */
- _bile_error = SetFPos(bile->frefnum, fsFromStart,
- bile->map_ptr.pos);
- if (_bile_error)
+ if (bile_read_map(bile, &bile->map_ptr) != 0) {
+ warn("bile_open: Failed reading map");
goto open_bail;
-
- size = sizeof(struct bile_object);
- _bile_error = FSRead(bile->frefnum, &size, &map_obj);
- if (_bile_error)
- goto open_bail;
-
- if (map_obj.pos != bile->map_ptr.pos)
- panic("bile_open: map pointer points to %lu but object there "
- "has position %lu", bile->map_ptr.pos, map_obj.pos);
- if (map_obj.size != bile->map_ptr.size)
- panic("bile_open: map is supposed to have size %lu but object "
- "pointed to has size %lu", bile->map_ptr.size, map_obj.size);
-
- /* read entire map */
- size = map_obj.size;
- bile->map = xmalloczero(size);
- _bile_error = FSRead(bile->frefnum, &size, bile->map);
- if (_bile_error)
- goto open_bail;
- bile->nobjects = map_obj.size / BILE_OBJECT_SIZE;
+ }
}
return bile;
@@ -185,6 +190,52 @@ open_bail:
return NULL;
}
+struct bile *
+bile_open_recover_map(const Str255 filename, short vrefnum)
+{
+ struct bile *bile;
+
+ _bile_open_ignore_primary_map = 1;
+ bile = bile_open(filename, vrefnum);
+ _bile_open_ignore_primary_map = 0;
+
+ if (bile) {
+ bile->map_ptr = bile->old_map_ptr;
+ bile_write_map(bile);
+ }
+
+ return bile;
+}
+
+short
+bile_autoflush(struct bile *bile, short val)
+{
+ bile->autoflush = val;
+}
+
+short
+bile_flush(struct bile *bile, short and_vol)
+{
+ IOParam pb;
+ short ret;
+
+ memset(&pb, 0, sizeof(pb));
+ pb.ioRefNum = bile->frefnum;
+ ret = PBFlushFile(&pb, false);
+ if (ret != noErr)
+ return ret;
+
+ if (and_vol) {
+ memset(&pb, 0, sizeof(pb));
+ /* XXX: this flushes default volume, maybe flush specific volume */
+ ret = PBFlushVol(&pb, false);
+ if (ret != noErr)
+ return ret;
+ }
+
+ return 0;
+}
+
void
bile_close(struct bile *bile)
{
@@ -345,30 +396,51 @@ bile_read_object(struct bile *bile, const struct bile_
_bile_error = bile->last_error = 0;
- if (o->pos + BILE_OBJECT_SIZE + o->size > bile->file_size)
- panic("bile_read_object: object %ld pos %ld size %ld > file size %ld",
- o->id, o->pos, o->size, bile->file_size);
+ if (o->pos + BILE_OBJECT_SIZE + o->size > bile->file_size) {
+ warn("bile_read_object: object %s:%ld pos %ld size %ld > "
+ "file size %ld", OSTypeToString(o->type), o->id, o->pos,
+ o->size, bile->file_size);
+ _bile_error = bile->last_error = BILE_ERR_BOGUS_OBJECT;
+ return 0;
+ }
- _bile_error = SetFPos(bile->frefnum, fsFromStart, o->pos);
- if (_bile_error)
- panic("bile_read_object: object %lu points to bogus position %lu",
- o->id, o->pos);
-
+ _bile_error = bile->last_error = SetFPos(bile->frefnum, fsFromStart,
+ o->pos);
+ if (_bile_error) {
+ warn("bile_read_object: object %s:%lu points to bogus position "
+ "%lu", OSTypeToString(o->type), o->id, o->pos);
+ _bile_error = bile->last_error = BILE_ERR_BOGUS_OBJECT;
+ return 0;
+ }
+
rsize = BILE_OBJECT_SIZE;
- _bile_error = bile->last_error = FSRead(bile->frefnum, &rsize, &verify);
+ _bile_error = bile->last_error = FSRead(bile->frefnum, &rsize,
+ &verify);
if (_bile_error)
return 0;
- if (verify.id != o->id)
- panic("bile_read_object: object %ld pos %ld wrong id %ld, "
- "expected %ld", o->id, o->pos, verify.id, o->id);
- if (verify.type != o->type)
- panic("bile_read_object: object %ld pos %ld wrong type %ld, "
- "expected %ld", o->id, o->pos, verify.type, o->type);
- if (verify.size != o->size)
- panic("bile_read_object: object %ld pos %ld wrong size %ld, "
- "expected %ld", o->id, o->pos, verify.size, o->size);
-
+ if (verify.id != o->id) {
+ warn("bile_read_object: object %s:%ld pos %ld wrong id %ld, "
+ "expected %ld", OSTypeToString(o->type), o->id, o->pos,
+ verify.id, o->id);
+ _bile_error = bile->last_error = BILE_ERR_BOGUS_OBJECT;
+ return 0;
+ }
+ if (verify.type != o->type) {
+ warn("bile_read_object: object %s:%ld pos %ld wrong type %ld, "
+ "expected %ld", OSTypeToString(o->type), o->id, o->pos,
+ verify.type, o->type);
+ _bile_error = bile->last_error = BILE_ERR_BOGUS_OBJECT;
+ return 0;
+ }
+ if (verify.size != o->size) {
+ warn("bile_read_object: object %s:%ld pos %ld wrong size %ld, "
+ "expected %ld", OSTypeToString(o->type), o->id, o->pos,
+ verify.size, o->size);
+ _bile_error = bile->last_error = BILE_ERR_BOGUS_OBJECT;
+ return 0;
+ }
+
wantlen = len;
if (wantlen > o->size)
wantlen = o->size;
@@ -378,9 +450,13 @@ bile_read_object(struct bile *bile, const struct bile_
if (_bile_error)
return 0;
- if (rsize != wantlen)
- panic("bile_read: needed to read %ld, read %ld", wantlen, rsize);
-
+ if (rsize != wantlen) {
+ warn("bile_read: %s:%lu: needed to read %ld, read %ld",
+ OSTypeToString(o->type), o->id, wantlen, rsize);
+ _bile_error = bile->last_error = BILE_ERR_BOGUS_OBJECT;
+ return 0;
+ }
+
return rsize;
}
@@ -460,8 +536,8 @@ bile_write(struct bile *bile, const OSType type, const
new_obj = bile_alloc(bile, type, id, len);
- bile_xwriteat(bile, new_obj->pos, new_obj, BILE_OBJECT_SIZE);
- if (bile->last_error)
+ wrote = bile_xwriteat(bile, new_obj->pos, new_obj, BILE_OBJECT_SIZE);
+ if (wrote != BILE_OBJECT_SIZE || bile->last_error)
return 0;
wrote = bile_xwriteat(bile, new_obj->pos + BILE_OBJECT_SIZE, data, len);
if (wrote != len || bile->last_error)
@@ -477,21 +553,27 @@ bile_write(struct bile *bile, const OSType type, const
return wrote;
}
-
-void
-bile_fsck(struct bile *bile)
+short
+bile_verify(struct bile *bile)
{
struct bile_object o;
- size_t n;
+ size_t n, size;
char data;
if (bile == NULL)
- panic("bile_fsck: bogus bile");
+ panic("bile_verify: bogus bile");
_bile_error = bile->last_error = 0;
- for (n = 0; n < bile->nobjects; n++)
- bile_read_object(bile, &bile->map[n], &data, 1);
+ for (n = 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;
+ }
+
+ return 0;
}
/* Private API */
@@ -561,9 +643,63 @@ bile_alloc(struct bile *bile, const OSType type, const
}
short
+bile_read_map(struct bile *bile, struct bile_object *map_ptr)
+{
+ size_t size;
+ struct bile_object map_obj, *map;
+
+ 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);
+ return -1;
+ }
+
+ if (map_ptr->size % BILE_OBJECT_SIZE != 0) {
+ warn("bile_read_map: map pointer size is not a multiple of object "
+ "size (%lu): %lu", BILE_OBJECT_SIZE, map_ptr->size);
+ return -1;
+ }
+
+ /* read and verify map object header map_ptr points to */
+ _bile_error = SetFPos(bile->frefnum, fsFromStart, map_ptr->pos);
+ if (_bile_error)
+ return -1;
+
+ size = sizeof(struct bile_object);
+ _bile_error = FSRead(bile->frefnum, &size, &map_obj);
+ if (_bile_error)
+ return -1;
+
+ if (map_obj.pos != map_ptr->pos) {
+ warn("bile_read_map: map pointer points to %lu but object "
+ "there has position %lu", map_ptr->pos, map_obj.pos);
+ return -1;
+ }
+
+ if (map_obj.size != map_ptr->size) {
+ warn("bile_read_map: map is supposed to have size %lu but "
+ "object pointed to has size %lu", map_ptr->size, map_obj.size);
+ return -1;
+ }
+
+ /* read entire map */
+ size = map_obj.size;
+ map = xmalloczero(size);
+ _bile_error = FSRead(bile->frefnum, &size, map);
+ if (_bile_error) {
+ free(map);
+ return -1;
+ }
+
+ bile->map = map;
+ bile->nobjects = map_obj.size / BILE_OBJECT_SIZE;
+
+ return 0;
+}
+
+short
bile_write_map(struct bile *bile)
{
- IOParam pb;
struct bile_object *obj, *new_map_obj, *new_map,
*new_map_obj_in_new_map = NULL;
size_t new_map_size, new_nobjects, new_map_id;
@@ -623,14 +759,20 @@ bile_write_map(struct bile *bile)
SetFPos(bile->frefnum, fsFromLEOF, 0);
GetFPos(bile->frefnum, &bile->file_size);
- memset(&pb, 0, sizeof(pb));
- pb.ioRefNum = bile->frefnum;
- PBFlushFile(&pb, false);
-
+ if (bile->autoflush) {
+ if ((ret = bile_flush(bile, false)) != noErr) {
+ warn("bile_write_map: flush failed: %d", ret);
+ return -1;
+ }
+ }
+
/* successfully wrote new map, switch over */
free(bile->map);
bile->nobjects = new_nobjects;
bile->map = new_map;
+ bile->old_map_ptr.pos = bile->map_ptr.pos;
+ bile->old_map_ptr.size = bile->map_ptr.size;
+ bile->old_map_ptr.id = bile->map_ptr.id;
bile->map_ptr.pos = new_map_obj->pos;
bile->map_ptr.size = new_map_obj->size;
bile->map_ptr.id = new_map_obj->id;
@@ -640,9 +782,18 @@ bile_write_map(struct bile *bile)
sizeof(bile->map_ptr));
if (bile->last_error)
return -1;
+ bile_xwriteat(bile, BILE_MAGIC_LEN + sizeof(bile->map_ptr),
+ &bile->old_map_ptr, sizeof(bile->old_map_ptr));
+ if (bile->last_error)
+ return -1;
- PBFlushFile(&pb, false);
-
+ if (bile->autoflush) {
+ if ((ret = bile_flush(bile, false)) != noErr) {
+ warn("bile_write_map: final flush failed: %d", ret);
+ return -1;
+ }
+ }
+
return 0;
}
--- bile.h Mon Jan 10 21:07:52 2022
+++ bile.h Fri Jan 21 17:58:40 2022
@@ -28,6 +28,12 @@
* [ pointer size - long ]
* [ pointer type (_BL>) - long ]
* [ pointer id - long ]
+ * [ previous map pointer object ]
+ * [ pointer position - long ]
+ * [ pointer size - long ]
+ * [ pointer type (_BL>) - long ]
+ * [ pointer id - long ]
+ * [ padding for future use ]
* [ object[0] start (map points to this as its position) ]
* [ object[0] position - long ]
* [ object[0] size - long ]
@@ -42,7 +48,7 @@
* [ map id - long ]
* [ map contents ]
*/
-#define BILE_MAGIC "BILE1"
+#define BILE_MAGIC "BILE2"
#define BILE_MAGIC_LEN 5
#define BILE_TYPE_MAP '_BLM'
#define BILE_TYPE_MAPPTR '_BL>'
@@ -54,16 +60,28 @@ struct bile_object {
OSType type;
unsigned long id;
};
-#define BILE_OBJECT_SIZE (sizeof(struct bile_object))
-#define BILE_HEADER_LEN (BILE_MAGIC_LEN + BILE_OBJECT_SIZE)
+#define BILE_OBJECT_SIZE (sizeof(struct bile_object))
+#define BILE_HEADER_LEN 256
+#ifndef BILE1_MAGIC
+#define BILE1_MAGIC "BILE1"
+#endif
+#ifndef BILE1_MAGIC_LEN
+#define BILE1_MAGIC_LEN 5
+#endif
+
+#define BILE_ERR_NEED_UPGRADE_1 -4000
+#define BILE_ERR_BOGUS_OBJECT -4001
+
struct bile {
struct bile_object map_ptr;
+ struct bile_object old_map_ptr;
short vrefnum, frefnum, last_error;
Str255 filename;
size_t file_size;
struct bile_object *map; /* array of bile_objects */
size_t nobjects;
+ short autoflush;
};
short bile_error(struct bile *bile);
@@ -71,6 +89,10 @@ short bile_error(struct bile *bile);
struct bile * bile_create(const Str255 filename, short vrefnum,
const OSType creator, const OSType type);
struct bile * bile_open(const Str255 filename, short vrefnum);
+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,
@@ -94,6 +116,6 @@ size_t bile_read_alloc(struct bile *bile,
size_t bile_write(struct bile *bile, OSType type,
const unsigned long id, const void *data,
const size_t len);
-void bile_fsck(struct bile *bile);
+short bile_verify(struct bile *bile);
#endif