diff options
Diffstat (limited to 'mbbsd/brc.c')
-rw-r--r-- | mbbsd/brc.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/mbbsd/brc.c b/mbbsd/brc.c new file mode 100644 index 00000000..cb5432cc --- /dev/null +++ b/mbbsd/brc.c @@ -0,0 +1,423 @@ +#include "bbs.h" + +#ifndef BRC_MAXNUM +#define BRC_STRLEN 15 /* Length of board name */ +#define BRC_MAXSIZE 24576 /* Effective size of brc rc file, 8192 * 3 */ +#define BRC_MAXNUM 80 /* Upper bound of brc_num, size of brc_list */ +#endif + +#define BRC_BLOCKSIZE 1024 + +#if MAX_BOARD > 32767 || BRC_MAXSIZE > 32767 +#error Max number of boards or BRC_MAXSIZE cannot fit in unsighed short, \ +please rewrite brc.c +#endif + +typedef unsigned short brcbid_t; +typedef unsigned short brcnbrd_t; + +/* old brc rc file form: + * board_name 15 bytes + * brc_num 1 byte, binary integer + * brc_list brc_num * sizeof(int) bytes, brc_num binary integer(s) */ + +static time_t brc_expire_time; + /* Will be set to the time one year before login. All the files created + * before then will be recognized read. */ + +static int brc_changed = 0; +/* The below two will be filled by read_brc_buf() and brc_update() */ +static char *brc_buf = NULL; +static int brc_size; +static int brc_alloc; + +static char * const fn_oldboardrc = ".boardrc"; +static char * const fn_brc = ".brc2"; + +#if 0 +/* unused after brc2 */ +static char * +brc_getrecord(char *ptr, char *endp, brcbid_t *bid, brcnbrd_t *pnum, time_t *list) +{ + brcnbrd_t num; + char *tmp; + + if (ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) > endp) + return endp + 1; /* dangling, ignoring it */ + *bid = *(brcbid_t*)ptr; /* bid */ + ptr += sizeof(brcbid_t); + num = *(brcnbrd_t*)ptr; /* brc_num */ + ptr += sizeof(brcnbrd_t); + tmp = ptr + num * sizeof(time_t); /* end of this record */ + if (tmp <= endp){ + memcpy(list, ptr, num * sizeof(time_t)); /* brc_list */ + if (num > BRC_MAXNUM) + num = BRC_MAXNUM; + *pnum = num; + } + return tmp; +} +#endif + +/* Returns the address of the record strictly between begin and endp with + * bid equal to the parameter. Returns 0 if not found. + * brcnbrd_t *num is an output parameter which will filled with brc_num + * if the record is found. If not found the record, *num will be the number + * of dangling bytes. */ +static char * +brc_findrecord_in(char *begin, char *endp, brcbid_t bid, brcnbrd_t *num) +{ + char *tmpp, *ptr = begin; + brcbid_t tbid; + while (ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) < endp) { + /* for each available records */ + tmpp = ptr; + tbid = *(brcbid_t*)tmpp; + tmpp += sizeof(brcbid_t); + *num = *(brcnbrd_t*)tmpp; + tmpp += sizeof(brcnbrd_t) + *num * sizeof(time_t); /* end of record */ + + if ( tmpp > endp ){ + /* dangling, ignore the trailing data */ + *num = (brcnbrd_t)(endp - ptr); /* for brc_insert_record() */ + return 0; + } + if ( tbid == bid ) + return ptr; + ptr = tmpp; + } + + *num = 0; + return 0; +} + +time_t * +brc_find_record(int bid, int *num) +{ + char *p; + *num = 0; + p = brc_findrecord_in(brc_buf, brc_buf + brc_size, bid, (brcnbrd_t*)num); + if (p) + return (time_t*)(p + sizeof(brcbid_t) + sizeof(brcnbrd_t)); + *num = 0; + return 0; +} + +static char * +brc_putrecord(char *ptr, char *endp, brcbid_t bid, brcnbrd_t num, const time_t *list) +{ + char * tmp; + if (num > 0 && list[0] > brc_expire_time && + ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) <= endp) { + if (num > BRC_MAXNUM) + num = BRC_MAXNUM; + + while (num > 0 && list[num - 1] < brc_expire_time) + num--; /* don't write the times before brc_expire_time */ + + if (num == 0) return ptr; + + *(brcbid_t*)ptr = bid; /* write in bid */ + ptr += sizeof(brcbid_t); + *(brcnbrd_t*)ptr = num; /* write in brc_num */ + ptr += sizeof(brcnbrd_t); + tmp = ptr + num * sizeof(time_t); + if (tmp <= endp) + memcpy(ptr, list, num * sizeof(time_t)); /* write in brc_list */ + ptr = tmp; + } + return ptr; +} + +static inline int +brc_enlarge_buf() +{ + char buffer[BRC_MAXSIZE - BRC_BLOCKSIZE]; + if (brc_alloc >= BRC_MAXSIZE) + return 0; + memcpy(buffer, brc_buf, brc_alloc); + free(brc_buf); + brc_alloc += BRC_BLOCKSIZE; + brc_buf = (char*)malloc(brc_alloc); + memcpy(brc_buf, buffer, brc_alloc - BRC_BLOCKSIZE); + return 1; +} + +static inline void +brc_get_buf(int size){ + if (!size) + brc_alloc = BRC_BLOCKSIZE; + else + brc_alloc = (size + BRC_BLOCKSIZE - 1) / BRC_BLOCKSIZE * BRC_BLOCKSIZE; + if (brc_alloc > BRC_MAXSIZE) + brc_alloc = BRC_MAXSIZE; + brc_buf = (char*)malloc(brc_alloc); +} + +static inline void +brc_insert_record(brcbid_t bid, brcnbrd_t num, time_t* list) +{ + char *ptr; + int new_size, end_size; + brcnbrd_t tnum; + + ptr = brc_findrecord_in(brc_buf, brc_buf + brc_size, bid, &tnum); + + /* FIXME: this loop is copied from brc_putrecord() */ + while (num > 0 && list[num - 1] < brc_expire_time) + num--; /* don't write the times before brc_expire_time */ + + if (!ptr) { + brc_size -= tnum; + + /* put on the beginning */ + if (num && (new_size = + sizeof(brcbid_t) + sizeof(brcnbrd_t) + num * sizeof(time_t))){ + brc_size += new_size; + if (brc_size > brc_alloc && !brc_enlarge_buf()) + brc_size = BRC_MAXSIZE; + if (brc_size > new_size) + memmove(brc_buf + new_size, brc_buf, brc_size - new_size); + brc_putrecord(brc_buf, brc_buf + new_size, bid, num, list); + } + } else { + /* ptr points to the old current brc list. + * tmpp is the end of it (exclusive). */ + char *tmpp = ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) + + tnum * sizeof(time_t); + end_size = brc_buf + brc_size - tmpp; + if (num) { + new_size = sizeof(brcbid_t) + sizeof(brcnbrd_t) + + num * sizeof(time_t); + brc_size += new_size - (tmpp - ptr); + if (brc_size > brc_alloc && ! brc_enlarge_buf() ) { + end_size -= brc_size - BRC_MAXSIZE; + brc_size = BRC_MAXSIZE; + } + if (end_size > 0 && ptr + new_size != tmpp) + memmove(ptr + new_size, tmpp, end_size); + brc_putrecord(ptr, brc_buf + brc_alloc, bid, num, list); + } else { /* deleting record */ + memmove(ptr, tmpp, end_size); + brc_size -= (tmpp - ptr); + } + } + + brc_changed = 0; +} + +void +brc_update(){ + if (brc_changed && cuser->userlevel && brc_num > 0) + brc_insert_record(currbid, brc_num, brc_list); +} + +/* return 1 if successfully read from old .boardrc file. + * otherwise, return 0. */ +inline static void +read_old_brc(int fd) +{ + char brdname[BRC_STRLEN + 1]; + char *ptr; + brcnbrd_t num; + brcbid_t bid; + brcbid_t read_brd[512]; + int nRead = 0, i; + + ptr = brc_buf; + brc_size = 0; + while (read(fd, brdname, BRC_STRLEN + 1) == BRC_STRLEN + 1) { + num = brdname[BRC_STRLEN]; + brdname[BRC_STRLEN] = 0; + bid = getbnum(brdname); + + for (i = 0; i < nRead; ++i) + if (read_brd[i] == bid) + break; + if (i != nRead){ + lseek(fd, num * sizeof(int), SEEK_CUR); + continue; + } + read_brd[nRead >= 512 ? nRead = 0 : nRead++] = bid; + + *(brcbid_t*)ptr = bid; + ptr += sizeof(brcbid_t); + *(brcnbrd_t*)ptr = num; + ptr += sizeof(brcnbrd_t); + if (read(fd, ptr, sizeof(int) * num) != sizeof(int) * num) + break; + + brc_size += sizeof(brcbid_t) + sizeof(brcnbrd_t) + + sizeof(time_t) * num; + ptr += sizeof(time_t) * num; + } +} + +inline static void +read_brc_buf() +{ + if (brc_buf == NULL) { + char brcfile[STRLEN]; + int fd; + struct stat brcstat; + + setuserfile(brcfile, fn_brc); + if ((fd = open(brcfile, O_RDONLY)) != -1) { + fstat(fd, &brcstat); + brc_get_buf(brcstat.st_size); + brc_size = read(fd, brc_buf, brc_alloc); + close(fd); + } else { + setuserfile(brcfile, fn_oldboardrc); + if ((fd = open(brcfile, O_RDONLY)) != -1) { + fstat(fd, &brcstat); + brc_get_buf(brcstat.st_size); + read_old_brc(fd); + close(fd); + } else + brc_size = 0; + } + } +} + +void +brc_finalize(){ + char brcfile[STRLEN]; + int fd; + brc_update(); + setuserfile(brcfile, fn_brc); + if (brc_buf != NULL && + (fd = open(brcfile, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) { + write(fd, brc_buf, brc_size); + close(fd); + } +} + +int +brc_initialize(){ + static char done = 0; + if (done) + return 1; + done = 1; + brc_expire_time = login_start_time - 365 * 86400; + read_brc_buf(); + return 0; +} + +int +brc_read_record(int bid, int *num, time_t *list){ + char *ptr; + *num = 0; + ptr = brc_findrecord_in(brc_buf, brc_buf + brc_size, bid, (brcnbrd_t*)num); + if ( ptr ){ + memcpy(list, ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t), + *num * sizeof(time_t)); + return *num; + } + list[0] = *num = 1; + return 0; +} + +int +brc_initial_board(const char *boardname) +{ + brc_initialize(); + + if (strcmp(currboard, boardname) == 0) { + return brc_num; + } + + brc_update(); /* write back first */ + currbid = getbnum(boardname); + currboard = bcache[currbid - 1].brdname; + currbrdattr = bcache[currbid - 1].brdattr; + + return brc_read_record(currbid, &brc_num, brc_list); +} + +void +brc_trunc(int bid, time_t ftime){ + brc_insert_record(bid, 1, &ftime); + if ( bid == currbid ){ + brc_num = 1; + brc_list[0] = ftime; + brc_changed = 0; + } +} + +void +brc_addlist(const char *fname) +{ + int n, i; + time_t ftime; + + if (!cuser->userlevel) + return; + + ftime = atoi(&fname[2]); + if (ftime <= brc_expire_time /* too old, don't do any thing */ + /* || fname[0] != 'M' || fname[1] != '.' */ ) { + return; + } + if (brc_num <= 0) { /* uninitialized */ + brc_list[0] = ftime; + brc_num = 1; + brc_changed = 1; + return; + } + if ((brc_num == 1) && (ftime < brc_list[0])) /* most when after 'v' */ + return; + for (n = 0; n < brc_num; n++) { /* using linear search */ + if (ftime == brc_list[n]) { + return; + } else if (ftime > brc_list[n]) { + if (brc_num < BRC_MAXNUM) + brc_num++; + /* insert ftime into brc_list */ + for (i = brc_num - 1; --i >= n; brc_list[i + 1] = brc_list[i]); + brc_list[n] = ftime; + brc_changed = 1; + return; + } + } +} + +int +brc_unread_time(time_t ftime, int bnum, const time_t *blist) +{ + int n; + + if (ftime <= brc_expire_time) /* too old */ + return 0; + + if (bnum <= 0) + return 1; + for (n = 0; n < bnum; n++) { /* using linear search */ + if (ftime > blist[n]) + return 1; + else if (ftime == blist[n]) + return 0; + } + return 0; +} + +int +brc_unread(const char *fname, int bnum, const time_t *blist) +{ + int ftime, n; + + ftime = atoi(&fname[2]); /* this will get the time of the file created */ + + if (ftime <= brc_expire_time) /* too old */ + return 0; + + if (bnum <= 0) + return 1; + for (n = 0; n < bnum; n++) { /* using linear search */ + if (ftime > blist[n]) + return 1; + else if (ftime == blist[n]) + return 0; + } + return 0; +} |