AmendHub

Download:

jcs

/

subtext

/

amendments

/

48

db+user: Switch database from resource files to bile format


jcs made amendment 48 over 2 years ago
--- db.c Wed Dec 8 14:39:24 2021 +++ db.c Wed Jan 5 20:46:27 2022 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,36 +18,16 @@ #include <string.h> #include <time.h> +#include "bile.h" #include "db.h" #include "subtext.h" #include "user.h" #include "util.h" -struct tmpl tmpls[10]; -short ntmpls; - -struct db *db_init(char *path, short is_new); +struct db * db_init(char *path, struct bile *bile); short db_migrate(struct db *tdb, short is_new); void db_config_load(struct db *tdb); -void -load_db_tmpls(void) -{ - short n; - - ntmpls = Count1Resources('TMPL'); - if (ntmpls > nitems(tmpls)) - panic("ntmpls %d > %d", ntmpls, nitems(tmpls)); - for (n = 0; n < ntmpls; n++) { - tmpls[n].h = GetIndResource('TMPL', n + 1); - if (tmpls[n].h == NULL) - panic("Failed fetching TMPL %d", n + 1); - GetResInfo(tmpls[n].h, &tmpls[n].id, &tmpls[n].type, - &tmpls[n].name); - DetachResource(tmpls[n].h); - } -} - struct db * db_open(char *file) { @@ -60,7 +40,7 @@ db_open(char *file) if (file) { if (stat((const char *)file, &sb) == 0) - return db_init(file, 0); + return db_init(file, NULL); warn("Failed to open %s", file); } @@ -73,7 +53,7 @@ db_open(char *file) ReleaseResource(lastfileh); PtoCstr(file); if (stat(file, &sb) == 0) { - ret = db_init(file, 0); + ret = db_init(file, NULL); free(file); return ret; } @@ -85,7 +65,7 @@ db_open(char *file) SFGetFile(pt, NULL, NULL, 1, &types, NULL, &reply); if (reply.good) { getpath(reply.vRefNum, reply.fName, &file, 1); - ret = db_init(file, 0); + ret = db_init(file, NULL); free(file); return ret; } @@ -99,55 +79,57 @@ db_create(void) Point pt = { 75, 100 }; SFReply reply; struct db *ret; + struct bile *bile; char *path; + Str255 ppath; short error, fh, tfh, i; SFPutFile(pt, "\pCreate new Subtext DB:", "\p", NULL, &reply); if (!reply.good) return NULL; - - error = Create(reply.fName, reply.vRefNum, SUBTEXT_CREATOR, DB_TYPE); - if (error == dupFNErr) { + + getpath(reply.vRefNum, reply.fName, &path, true); + memcpy(ppath, path, sizeof(ppath)); + CtoPstr(ppath); + + bile = bile_create(ppath, SUBTEXT_CREATOR, DB_TYPE); + if (bile == NULL && bile_error() == dupFNErr) { error = FSDelete(reply.fName, reply.vRefNum); if (error) panic("Failed to re-create file %s: %d", PtoCstr(reply.fName), error); - error = Create(reply.fName, reply.vRefNum, SUBTEXT_CREATOR, - DB_TYPE); + bile = bile_create(ppath, SUBTEXT_CREATOR, DB_TYPE); } - if (error) - panic("Failed to create %s: %d", PtoCstr(reply.fName), error); - getpath(reply.vRefNum, reply.fName, &path, 1); - - CtoPstr(path); - CreateResFile(path); - if (ResError() != 0) - panic("Failed to create DB %s: %d", PtoCstr(path), ResError()); - PtoCstr(path); - - ret = db_init(path, 1); + if (bile == NULL) + panic("Failed to create file %s: %d", PtoCstr(reply.fName), error); + + ret = db_init(path, bile); free(path); + return ret; } struct db * -db_init(char *path, short is_new) +db_init(char *path, struct bile *bile) { - Str255 buf; struct db *tdb; Handle resh, lastfileh; - short error, fh, i; - char *ppath; + short was_new, error, i; + Str255 ppath; - ppath = xstrdup(path); + memcpy(ppath, path, sizeof(ppath)); CtoPstr(ppath); - fh = OpenResFile(ppath); - if (fh == -1) - panic("Failed to open %s: %d", path, ResError()); + was_new = (bile != NULL); + + if (bile == NULL) { + bile = bile_open(ppath); + if (bile == NULL) + panic("Failed to open DB file %s: %d", path, bile_error()); + } + /* we got this far, store it as the last-accessed file */ - UseResFile(mainResFile); lastfileh = Get1Resource('STR ', STR_LAST_DB); if (lastfileh) xSetHandleSize(lastfileh, ppath[0] + 1); @@ -162,39 +144,39 @@ db_init(char *path, short is_new) ChangedResource(lastfileh); WriteResource(lastfileh); DetachResource(lastfileh); - UseResFile(fh); - free(ppath); - tdb = xmalloczero(sizeof(struct db)); - tdb->fh = fh; - strlcpy(tdb->filename, path, sizeof(tdb->filename)); + tdb->bile = bile; - if (db_migrate(tdb, is_new) != 0) { + if (db_migrate(tdb, was_new) != 0) { + bile_close(tdb->bile); free(tdb); return NULL; } - if (!is_new) + if (!was_new) db_config_load(tdb); - + + user_update_cache_map(tdb); + return tdb; } void db_close(struct db *tdb) { - CloseResFile(tdb->fh); + bile_close(db->bile); + free(db->bile); free(tdb); } short db_migrate(struct db *tdb, short is_new) { - Handle verh, resh; - short ver, add = 0, i, nfiles, size; struct user *user; + struct bile_object *bob; char *error; + char ver; if (is_new) { ver = DB_CUR_VERS; @@ -215,18 +197,13 @@ db_migrate(struct db *tdb, short is_new) user->is_sysop = DB_TRUE; user_save(tdb, user); } else { - verh = Get1Resource(DB_VERS_RTYPE, 1); - if (verh == NULL) + if (bile_read(tdb->bile, DB_VERS_RTYPE, 1, &ver, 1) != 1) ver = 1; - else { - ver = (unsigned char)((*verh)[0]); - ReleaseResource(verh); - } - + if (ver == DB_CUR_VERS) return 0; - if (ask("Migrate this database from version %d to %d to open it?", + if (ask("Migrate this database from version %c to %d to open it?", ver, DB_CUR_VERS) != ASK_YES) return -1; } @@ -234,77 +211,34 @@ db_migrate(struct db *tdb, short is_new) /* per-version migrations */ /* store new version */ - verh = Get1Resource(DB_VERS_RTYPE, 1); - if (verh == NULL) { - verh = NewHandle(1); - add = 1; - } - (*verh)[0] = ver; - if (add) - AddResource(verh, DB_VERS_RTYPE, 1, "\p"); - else - ChangedResource(verh); - - /* update templates */ - for (i = 0; i < ntmpls; i++) { - resh = Get1Resource(tmpls[i].type, tmpls[i].id); - if (resh) - RmveResource(resh); - AddResource(tmpls[i].h, tmpls[i].type, tmpls[i].id, tmpls[i].name); - WriteResource(tmpls[i].h); - DetachResource(tmpls[i].h); - } - - UpdateResFile(tdb->fh); - + ver = DB_CUR_VERS; + if (bile_write(tdb->bile, DB_VERS_RTYPE, 1, &ver, 1) != 1) + panic("Failed writing new version: %d", bile_error()); + return 0; } void db_config_save(struct db *tdb) { - Handle hconfig; - short is_new = 0; - - hconfig = Get1Resource(DB_CONFIG_RTYPE, 1); - if (hconfig) { - if (sizeof(tdb->config) != GetHandleSize(hconfig)) - panic("db_config_save: handle size %ld, struct size %ld", - GetHandleSize(hconfig), sizeof(tdb->config)); - } else { - hconfig = xNewHandle(sizeof(tdb->config)); - is_new = 1; - } - - HLock(hconfig); - memcpy(*hconfig, &tdb->config, sizeof(tdb->config)); - HUnlock(hconfig); - - if (is_new) { - AddResource(hconfig, DB_CONFIG_RTYPE, 1, "\p"); - if (ResError()) - panic("db_config_save: failed to AddResource: %d", - ResError()); - } else { - ChangedResource(hconfig); - } - - WriteResource(hconfig); - if (ResError()) - panic("db_config_save: failed to WriteResource: %d", ResError()); - ReleaseResource(hconfig); + if (bile_write(tdb->bile, DB_CONFIG_RTYPE, 1, &tdb->config, + sizeof(tdb->config)) != sizeof(tdb->config)) + panic("db_config_save: failed to write: %d", bile_error()); } void db_config_load(struct db *tdb) { - Handle hconfig; + size_t rlen; + char *newconfig; - hconfig = Get1Resource(DB_CONFIG_RTYPE, 1); - if (!hconfig) - panic("db_config_load: no config in existing db!"); - - HLock(hconfig); - memcpy(&tdb->config, *hconfig, sizeof(tdb->config)); - HUnlock(hconfig); + rlen = bile_read_alloc(tdb->bile, DB_CONFIG_RTYPE, 1, &newconfig); + if (rlen == 0 || bile_error()) + panic("db_config_load: error reading config: %d", bile_error()); + if (rlen != sizeof(tdb->config)) + panic("db_config_load: read config of size %lu, but expected %lu", + rlen, sizeof(tdb->config)); + + memcpy(&tdb->config, newconfig, sizeof(tdb->config)); + free(newconfig); } --- db.h Wed Dec 29 16:09:47 2021 +++ db.h Wed Jan 5 17:17:56 2022 @@ -19,6 +19,7 @@ #include <time.h> +#include "bile.h" #include "sha2.h" #define SUBTEXT_CREATOR 'SUBT' @@ -30,11 +31,11 @@ #define DB_TRUE 0x100 #define DB_FALSE 0x000 -#define DB_CONFIG_RTYPE 'STCF' -#define DB_USER_RTYPE 'STUS' -#define DB_BOARD_RTYPE 'STBD' -#define DB_FILEAREA_RTYPE 'STFL' -#define DB_VERS_RTYPE 'STVR' +#define DB_CONFIG_RTYPE 'CONF' +#define DB_USER_RTYPE 'USER' +#define DB_BOARD_RTYPE 'BORD' +#define DB_FILEAREA_RTYPE 'FILA' +#define DB_VERS_RTYPE 'VERS' #define DB_TEXT_TYPE 'TEXT' #define DB_TEXT_MENU_ID 1 @@ -49,11 +50,14 @@ struct config { short telnet_port; }; -#define DB_USERNAME_SIZE 16 +#define DB_USERNAME_LENGTH 16 struct user { + /* keep this first so we can quickly read it during caching */ + char username_key[DB_USERNAME_LENGTH + 1]; + short id; - char username[DB_USERNAME_SIZE]; + char username[DB_USERNAME_LENGTH + 1]; char password_hash[SHA256_DIGEST_STRING_LENGTH + 1]; /* 66 */ char password_salt[SHA256_DIGEST_STRING_LENGTH + 1]; unsigned long created_at; @@ -61,26 +65,21 @@ struct user { short is_sysop; }; +struct user_map { + short id; + char username_key[DB_USERNAME_LENGTH + 1]; +}; + struct db { - char filename[256]; + struct bile *bile; short fh; struct config config; + struct user_map *user_map; short nusers; }; -struct tmpl { - Handle h; - ResType type; - Str255 name; - short id; -}; - -extern struct tmpl tmpls[10]; -extern short ntmpls; - -void load_db_tmpls(void); -struct db *db_open(char *file); -struct db *db_create(void); +struct db * db_open(char *file); +struct db * db_create(void); void db_close(struct db *tdb); void db_config_save(struct db *tdb); --- main.c Sat Jan 1 20:20:23 2022 +++ main.c Wed Jan 5 13:07:33 2022 @@ -28,7 +28,7 @@ MenuHandle file_menu; short quitting = 0; struct console *cur_console = NULL; -struct db *db; +struct db *db = NULL; short mainResFile; void handle_menu(long menu_id); @@ -58,10 +58,8 @@ main(void) InitDialogs(0); InitCursor(); MaxApplZone(); - - mainResFile = CurMap; + err_init(); - load_db_tmpls(); mbar = GetNewMBar(MBAR_ID); SetMenuBar(mbar); --- session.c Sun Jan 2 10:22:55 2022 +++ session.c Wed Jan 5 13:43:19 2022 @@ -410,8 +410,8 @@ session_login(struct session *s) username = xstrdup(s->autologin_username); } else { session_flush(s); - username = session_field_input(s, DB_USERNAME_SIZE, - DB_USERNAME_SIZE - 1, 0); + username = session_field_input(s, DB_USERNAME_LENGTH + 1, + DB_USERNAME_LENGTH, 0); session_output(s, "\r\n", 2); session_flush(s); @@ -437,10 +437,15 @@ session_login(struct session *s) user = user_find(db, username); } - if (s->autologin_username[0] && user) { - free(username); - s->user = user; - return AUTH_USER_OK; + if (s->autologin_username[0]) { + if (user) { + free(username); + s->user = user; + return AUTH_USER_OK; + } + + memset(s->autologin_username, 0, + sizeof(s->autologin_username)); } session_output_string(s, "Password: "); --- session.h Sun Jan 2 10:21:53 2022 +++ session.h Wed Jan 5 12:34:53 2022 @@ -41,7 +41,7 @@ struct node_funcs { }; struct session_log { - char username[DB_USERNAME_SIZE]; + char username[DB_USERNAME_LENGTH + 1]; char node[10]; unsigned long logged_on_at; unsigned long logged_off_at; @@ -73,7 +73,7 @@ struct session { unsigned char chatting_with_node[10]; unsigned char chat_ring_idx; struct session_log log; - char autologin_username[32]; + char autologin_username[DB_USERNAME_LENGTH + 1]; struct user *user; void *cookie; struct node_funcs *node_funcs; --- subtext.π.r Wed Dec 29 16:14:01 2021 +++ subtext.π.r Wed Jan 5 21:02:58 2022 @@ -24,9 +24,10 @@ data 'DITL' (128) { }; data 'DITL' (129) { - $"0001 0000 0000 0046 00E6 005A 0120 0402" /* .......F...Z. .. */ - $"4F4B 0000 0000 000A 003C 0040 011E 0802" /* OK.......<.@.... */ - $"5E30" /* ^0 */ + $"0002 0000 0000 0046 00E6 005A 0120 0402" /* .......F...Z. .. */ + $"4F4B 0000 0000 000A 0032 0040 0121 0802" /* OK.......2.@.!.. */ + $"5E30 0000 0000 000A 000A 002A 002A A002" /* ^0.........*.*†. */ + $"0002" /* .. */ }; data 'WIND' (128) { @@ -43,28 +44,6 @@ data 'vers' (1) { data 'DLOG' (128) { $"0064 0083 00A0 017D 0001 0100 0100 0000" /* .d.É.†.}........ */ $"0000 0080 001A 280A" /* ...Ä..(. */ -}; - -data 'USER' (128) { - $"0001 6A63 7300" /* ..jcs. */ -}; - -data 'TMPL' (128, "STCF") { - $"046E 616D 6543 3032 300C 7068 6F6E 655F" /* .nameC020.phone_ */ - $"6E75 6D62 6572 4330 3130 086C 6F63 6174" /* numberC010.locat */ - $"696F 6E43 3034 3008 686F 7374 6E61 6D65" /* ionC040.hostname */ - $"4330 3230 0B74 656C 6E65 745F 706F 7274" /* C020.telnet_port */ - $"4457 5244" /* DWRD */ -}; - -data 'TMPL' (129, "STUS") { - $"0269 6444 5752 4408 7573 6572 6E61 6D65" /* .idDWRD.username */ - $"4330 3130 0D70 6173 7377 6F72 645F 6861" /* C010¬password_ha */ - $"7368 4330 3432 0D70 6173 7377 6F72 645F" /* shC042¬password_ */ - $"7361 6C74 4330 3432 0A63 7265 6174 6564" /* saltC042.created */ - $"5F61 7444 4C4E 470C 6C61 7374 5F73 6565" /* _atDLNG.last_see */ - $"6E5F 6174 444C 4E47 0869 735F 7379 736F" /* n_atDLNG.is_syso */ - $"7042 4F4F 4C" /* pBOOL */ }; data 'STR ' (128, "STR_LAST_DB") { --- user.c Wed Dec 8 14:39:50 2021 +++ user.c Wed Jan 5 20:54:21 2022 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,12 +17,46 @@ #include <ctype.h> #include <string.h> +#include "bile.h" #include "db.h" #include "sha2.h" #include "subtext.h" #include "user.h" #include "util.h" +void +user_update_cache_map(struct db *tdb) +{ + struct user_map *muser; + struct bile_object *o; + size_t nuser, len, j, n; + + if (tdb->user_map != NULL) + free(tdb->user_map); + + tdb->nusers = bile_count_by_type(tdb->bile, DB_USER_RTYPE); + tdb->user_map = xmalloczero(sizeof(struct user_map) * tdb->nusers); + + nuser = 0; + for (n = 0; n < tdb->bile->nobjects; n++) { + o = &tdb->bile->map[n]; + if (o->type != DB_USER_RTYPE) + continue; + + muser = &tdb->user_map[nuser]; + muser->id = o->id; + + /* the lowercased username should be the first bytes of each rec */ + len = bile_read(tdb->bile, DB_USER_RTYPE, o->id, + muser->username_key, sizeof(muser->username_key)); + if (len != sizeof(muser->username_key)) + panic("user_update_cache_map: can't read user %lu: %d", o->id, + bile_error()); + + nuser++; + } +} + struct user * user_build(struct db *tdb, char *username, char **error) { @@ -60,147 +94,62 @@ user_build(struct db *tdb, char *username, char **erro void user_save(struct db *tdb, struct user *user) { - Handle huser = NULL; - size_t hsize = 0, len; - size_t datapos; - char *data, *lusername; - short n, is_new = 0; + size_t len, n; - if (user->id) { - huser = Get1Resource(DB_USER_RTYPE, user->id); - if (!huser) - panic("user_save: user %s has id %d but no resource", - user->username, user->id); - hsize = GetHandleSize(huser); - } else { - hsize = sizeof(struct user); - huser = xNewHandle(hsize); - user->id = Count1Resources(DB_USER_RTYPE) + 1; + if (!user->id) { + user->id = bile_next_id(tdb->bile, DB_USER_RTYPE); user->created_at = Time; - is_new = 1; } - HLock(huser); - data = (char *)(*huser); - datapos = 0; - - memcpy(data + datapos, &user->id, sizeof(user->id)); - datapos += sizeof(user->id); - - memcpy(data + datapos, &user->username, sizeof(user->username)); - datapos += sizeof(user->username); - - memcpy(data + datapos, &user->password_hash, sizeof(user->password_hash)); - datapos += sizeof(user->password_hash); - - memcpy(data + datapos, &user->password_salt, sizeof(user->password_salt)); - datapos += sizeof(user->password_salt); - - memcpy(data + datapos, &user->created_at, sizeof(user->created_at)); - datapos += sizeof(user->created_at); - - memcpy(data + datapos, &user->last_seen_at, sizeof(user->last_seen_at)); - datapos += sizeof(user->last_seen_at); - - memcpy(data + datapos, &user->is_sysop, sizeof(user->is_sysop)); - datapos += sizeof(user->is_sysop); - - if (datapos != hsize) - panic("user_save handle size %ld, data position %ld", - hsize, datapos); - - HUnlock(huser); - - /* update resource name with lowercase username for index */ + /* update username key */ + memset(user->username_key, 0, sizeof(user->username_key)); len = strlen(user->username); - lusername = xmalloc(len + 1); - lusername[0] = len; for (n = 0; n < len; n++) - lusername[n + 1] = tolower(user->username[n]); - - if (is_new) { - AddResource(huser, DB_USER_RTYPE, user->id, lusername); - if (ResError()) - panic("user_save: failed to AddResource: %d", ResError()); - } else { - SetResInfo(huser, user->id, lusername); - ChangedResource(huser); - } + user->username_key[n] = tolower(user->username[n]); - WriteResource(huser); - if (ResError()) - panic("user_save: failed to WriteResource: %d", ResError()); - ReleaseResource(huser); + len = bile_write(tdb->bile, DB_USER_RTYPE, user->id, + user, sizeof(struct user)); + if (len != sizeof(struct user)) + panic("user_save: failed to write: %d", bile_error()); - tdb->nusers = Count1Resources(DB_USER_RTYPE); + user_update_cache_map(tdb); } struct user * user_find(struct db *tdb, char *username) { - struct user suser; + struct user suser, *user; + struct user_map *muser; + char lusername[DB_USERNAME_LENGTH + 1] = { 0 }; + char *data; short n; - Handle huser; - Str255 pusername = { 0 }; size_t len; len = strlen(username); - if (len > sizeof(suser.username)) + if (len > sizeof(suser.username_key)) return NULL; - pusername[0] = len; + /* downcase username and find it in the cache map */ for (n = 0; n < len; n++) - pusername[n + 1] = tolower(username[n]); + lusername[n] = tolower(username[n]); - huser = Get1NamedResource(DB_USER_RTYPE, pusername); - if (!huser) - return NULL; - - return user_parse(tdb, huser); -} - -struct user * -user_parse(struct db *tdb, Handle huser) -{ - struct user *user; - short hlen, datapos; - char *data; + for (n = 0; n < tdb->nusers; n++) { + muser = &tdb->user_map[n]; + + if (strcmp(muser->username_key, lusername) == 0) { + len = bile_read_alloc(tdb->bile, DB_USER_RTYPE, muser->id, + &data); + if (len != sizeof(struct user)) + panic("user_find: bad user record size %lu != %lu", + len, sizeof(struct user)); + user = xmalloczero(sizeof(struct user)); + memcpy(user, data, sizeof(struct user)); + free(data); + return user; + } + } - user = xmalloczero(sizeof(struct user)); - - data = (char *)(*huser); - datapos = 0; - - hlen = GetHandleSize(huser); - - memcpy(&user->id, data + datapos, sizeof(user->id)); - datapos += sizeof(user->id); - - memcpy(&user->username, data + datapos, sizeof(user->username)); - datapos += sizeof(user->username); - - memcpy(&user->password_hash, data + datapos, sizeof(user->password_hash)); - datapos += sizeof(user->password_hash); - - memcpy(&user->password_salt, data + datapos, sizeof(user->password_salt)); - datapos += sizeof(user->password_salt); - - memcpy(&user->created_at, data + datapos, sizeof(user->created_at)); - datapos += sizeof(user->created_at); - - memcpy(&user->last_seen_at, data + datapos, sizeof(user->last_seen_at)); - datapos += sizeof(user->last_seen_at); - - memcpy(&user->is_sysop, data + datapos, sizeof(user->is_sysop)); - datapos += sizeof(user->is_sysop); - - if (datapos != hlen) - panic("user_parse handle len %d, data position %d", hlen, datapos); - - HUnlock(huser); - ReleaseResource(huser); - - return user; + return NULL; } short --- user.h Sun Dec 5 08:41:18 2021 +++ user.h Wed Jan 5 20:54:49 2022 @@ -22,11 +22,11 @@ #define AUTH_USER_OK 1 #define AUTH_USER_FAILED 2 -struct user *user_build(struct db *tdb, char *username, char **error); +void user_update_cache_map(struct db *tdb); +struct user * user_build(struct db *tdb, char *username, char **error); void user_save(struct db *tdb, struct user *user); -struct user *user_find(struct db *tdb, char *username); +struct user * user_find(struct db *tdb, char *username); short user_authenticate(struct db *tdb, struct user *user, char *password); void user_set_password(struct db *tdb, struct user *user, char *password); -struct user *user_parse(struct db *tdb, Handle huser); #endif