void FREE(void *ptr) { int size = ((int *)ptr)[-1]; munmap((void *)(&(((int *)ptr)[-1])), size); #if defined(DEBUG) vmsgf("critical free %d bytes", size); #endif }
void *MALLOC(int size) { int *p; p = (int *)mmap(NULL, (size + 4), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); p[0] = size; #if defined(DEBUG) vmsgf("critical malloc %d bytes", size); #endif return (void *)&p[1]; }
static void a_showname(const menu_t * pm) { char buf[PATHLEN]; int len; int i; int sym; move(b_lines - 1, 0); snprintf(buf, sizeof(buf), "%s/%s", pm->path, pm->header[pm->now - pm->page].filename); if (dashl(buf)) { prints("此 symbolic link 名稱為 %s\n", pm->header[pm->now - pm->page].filename); if ((len = readlink(buf, buf, PATHLEN - 1)) >= 0) { buf[len] = '\0'; for (i = 0; BBSHOME[i] && buf[i] == BBSHOME[i]; i++); if (!BBSHOME[i] && buf[i] == '/') { if (HasUserPerm(PERM_BBSADM)) sym = 1; else { sym = 0; for (i++; BBSHOME "/man"[i] && buf[i] == BBSHOME "/man"[i]; i++); if (!BBSHOME "/man"[i] && buf[i] == '/') sym = 1; } if (sym) { vmsgf("此 symbolic link 指向 %s", &buf[i + 1]); } } } } else if (dashf(buf)) prints("此文章名稱為 %s", pm->header[pm->now - pm->page].filename); else if (dashd(buf)) prints("此目錄名稱為 %s", pm->header[pm->now - pm->page].filename); else outs("此項目已損毀, 建議將其刪除!"); pressanykey(); }
int a_menu_rec(const char *maintitle, const char *path, int lastlevel, int lastbid, char *trans_buffer, a_menu_session_t *sess, const int *preselect, // we don't change root's value (but may change root pointer) // we may change parent's value (but never change parent pointer) const menu_t *root, menu_t* const parent) { menu_t me = {0}; char fname[PATHLEN]; int ch, returnvalue = FULLUPDATE; assert(sess); // prevent deep resursive directories if (strlen(path) + FNLEN >= PATHLEN) { // it is not save to enter such directory. return returnvalue; } if(trans_buffer) trans_buffer[0] = '\0'; if (parent) { parent->next = &me; } else { assert(root == NULL); root = &me; } me.header_size = p_lines; me.header = (fileheader_t *) calloc(me.header_size, FHSZ); me.path = path; strlcpy(me.mtitle, maintitle, sizeof(me.mtitle)); setadir(fname, me.path); me.num = get_num_records(fname, FHSZ); me.bid = lastbid; /* 精華區-tree 中部份結構屬於 cuser ==> BM */ if (!(me.level = lastlevel)) { char *ptr; // warning: this is only valid for me.level. // is_uBM should not do anything except returning test result: // for ex, setting user BM permission automatically. // such extra behavior will result in any sub-op to have PERM_BM // ability, which leads to entering BM board without authority. // Thanks to mtdas@ptt for reporting this exploit. if (HasBasicUserPerm(PERM_LOGINOK) && !HasUserPerm(PERM_NOCITIZEN) && (ptr = strrchr(me.mtitle, '['))) me.level = is_uBM(ptr + 1, cuser.userid); } me.page = A_INVALID_PAGE; if (preselect && !*preselect) preselect = NULL; me.now = preselect ? (*preselect -1) : 0; for (;;) { if (me.now >= me.num) me.now = me.num - 1; if (me.now < 0) me.now = 0; if (me.now < me.page || me.now >= me.page + me.header_size) { me.page = me.now - ((me.page == 10000 && me.now > p_lines / 2) ? (p_lines / 2) : (me.now % p_lines)); if (!a_showmenu(&me)) { // some directories are invalid, restart! sess->bReturnToRoot = 1; break; } } if (preselect && *preselect && preselect[1]) { // if this is not the last preselect entry, enter it ch = KEY_ENTER; } else { ch = cursor_key(2 + me.now - me.page, 0); } if (ch == 'q' || ch == 'Q' || ch == KEY_LEFT) break; // TODO maybe we should let 1-9=simple search and z=tree-search // TODO or let 'z' prefix means 'back to root' if ((ch >= '1' && ch <= '9') || (ch == 'z' || ch == 'Z')) { int n = a_multi_search_num(ch, sess); me.page = A_INVALID_PAGE; if (n > 0) { // simple (single) selection me.now = n-1; me.page = 10000; // I don't know what's the magic value 10000... } else if (n == 0 && sess->z_indexes[0] == 0) { // empty/invalid input } else { // n == 0 with multiple selects preselect = sess->z_indexes; if (*preselect < 0) { // return to root first? if (parent) { sess->bReturnToRoot = 1; return DONOTHING; } // already in root preselect ++; } // handle first preselect (maybe zero due to previous 'already in root') if (*preselect > 0) me.now = *preselect - 1; else preselect = NULL; } continue; } switch (ch) { case KEY_UP: case 'k': if (--me.now < 0) me.now = me.num - 1; break; case KEY_DOWN: case 'j': if (++me.now >= me.num) me.now = 0; break; case KEY_PGUP: case Ctrl('B'): if (me.now >= p_lines) me.now -= p_lines; else if (me.now > 0) me.now = 0; else me.now = me.num - 1; break; case ' ': case KEY_PGDN: case Ctrl('F'): if (me.now < me.num - p_lines) me.now += p_lines; else if (me.now < me.num - 1) me.now = me.num - 1; else me.now = 0; break; case KEY_HOME: case '0': me.now = 0; break; case KEY_END: case '$': me.now = me.num - 1; break; case '?': case '/': if(me.num) { me.now = a_searchtitle(&me, ch == '?'); me.page = A_INVALID_PAGE; } break; case 'h': a_showhelp(me.level); me.page = A_INVALID_PAGE; break; case Ctrl('W'): a_where_am_i(root, me.now, me.header[me.now - me.page].title); vmsg(NULL); me.page = A_INVALID_PAGE; break; case 'e': case 'E': snprintf(fname, sizeof(fname), "%s/%s", path, me.header[me.now - me.page].filename); if (dashf(fname) && me.level >= MANAGER) { int edflags = 0; *quote_file = 0; # ifdef BN_BBSMOVIE if (me.bid && strcmp(getbcache(me.bid)->brdname, BN_BBSMOVIE) == 0) { edflags |= EDITFLAG_UPLOAD; edflags |= EDITFLAG_ALLOWLARGE; } # endif // BN_BBSMOVIE if (vedit2(fname, NA, NULL, edflags) != -1) { char fpath[PATHLEN]; fileheader_t fhdr; strlcpy(fpath, path, sizeof(fpath)); stampfile(fpath, &fhdr); unlink(fpath); strlcpy(fhdr.filename, me.header[me.now - me.page].filename, sizeof(fhdr.filename)); strlcpy(me.header[me.now - me.page].owner, cuser.userid, sizeof(me.header[me.now - me.page].owner)); setadir(fpath, path); substitute_record(fpath, me.header + me.now - me.page, sizeof(fhdr), me.now + 1); } me.page = A_INVALID_PAGE; } break; case 't': case 'c': if (me.now < me.num) { if (!isvisible_man(&me)) break; snprintf(fname, sizeof(fname), "%s/%s", path, me.header[me.now - me.page].filename); /* XXX: dirty fix 應該要改成如果發現該目錄裡面有隱形目錄的話才拒絕. 不過這樣的話須要整個搜一遍, 而且目前判斷該資料是目錄 還是檔案竟然是用 fstat(2) 而不是直接存在 .DIR 內 |||b 須等該資料寫入 .DIR 內再 implement才有效率. */ if( !me.level && !HasUserPerm(PERM_SYSOP) && (me.bid==0 || !is_BM_cache(me.bid)) && dashd(fname) ) vmsg("只有板主才可以拷貝目錄唷!"); else a_copyitem(fname, me.header[me.now - me.page].title, 0, 1); me.page = A_INVALID_PAGE; /* move down */ if (++me.now >= me.num) me.now = 0; break; } case KEY_ENTER: case KEY_RIGHT: case 'r': if (me.now >= me.num || me.now < 0) { preselect = NULL; continue; } else { fileheader_t *fhdr = &me.header[me.now - me.page]; const int *newselect = preselect ? preselect+1 : NULL; preselect = NULL; if (!isvisible_man(&me)) break; #ifdef DEBUG vmsgf("%s/%s", &path[11], fhdr->filename);; #endif snprintf(fname, sizeof(fname), "%s/%s", path, fhdr->filename); if (dashf(fname)) { int more_result; while ((more_result = more(fname, YEA))) { /* Ptt 範本精靈 plugin */ if (trans_buffer && (currstat == EDITEXP || currstat == OSONG)) { char ans[4]; move(22, 0); clrtoeol(); getdata(22, 1, currstat == EDITEXP ? "要把範例加入到文章內嗎?[y/N]" : "確定要選這篇嗎?[y/N]", ans, sizeof(ans), LCECHO); if (ans[0] == 'y') { strlcpy(trans_buffer, fname, PATHLEN); sess->bReturnToRoot = 1; if (currstat == OSONG) { log_filef(FN_USSONG, LOG_CREAT, "%s\n", fhdr->title); } free(me.header); return FULLUPDATE; } } if (more_result == READ_PREV) { if (--me.now < 0) { me.now = 0; break; } } else if (more_result == READ_NEXT) { if (++me.now >= me.num) { me.now = me.num - 1; break; } /* we only load me.header_size pages */ if (me.now - me.page >= me.header_size) break; } else break; if (!isvisible_man(&me)) break; snprintf(fname, sizeof(fname), "%s/%s", path, me.header[me.now - me.page].filename); if (!dashf(fname)) break; } } else if (dashd(fname)) { returnvalue = a_menu_rec(me.header[me.now - me.page].title, fname, me.level, me.bid, trans_buffer, sess, newselect, root, &me); if (returnvalue == DONOTHING) { // DONOTHING will only be caused by previous a_multi_search_num + preselect. assert(sess->bReturnToRoot); if (!parent) { // we've reached root menu! assert(sess->z_indexes[0] == -1); sess->bReturnToRoot = 0; returnvalue = FULLUPDATE; preselect = sess->z_indexes+1; // skip first 'return to root' if (*preselect > 0) me.now = *preselect-1; } } else { returnvalue = FULLUPDATE; } me.next = NULL; /* Ptt 強力跳出recursive */ if (sess->bReturnToRoot) { free(me.header); return returnvalue; } } me.page = A_INVALID_PAGE; } break; case 'F': case 'U': if (me.now < me.num) { fileheader_t *fhdr = &me.header[me.now - me.page]; if (!isvisible_man(&me)) break; snprintf(fname, sizeof(fname), "%s/%s", path, fhdr->filename); if (HasBasicUserPerm(PERM_LOGINOK) && dashf(fname)) { a_forward(path, fhdr, ch /* == 'U' */ ); /* By CharlieL */ } else vmsg("無法轉寄此項目"); me.page = A_INVALID_PAGE; } break; } if (me.level >= MANAGER) { switch (ch) { case 'n': a_newitem(&me, ADDITEM); me.page = A_INVALID_PAGE; break; case 'g': a_newitem(&me, ADDGROUP); me.page = A_INVALID_PAGE; break; case 'p': a_pasteitem(&me, 1); me.page = A_INVALID_PAGE; break; case 'f': a_editsign(&me); me.page = A_INVALID_PAGE; break; case Ctrl('P'): a_pastetagpost(&me, -1); returnvalue = DIRCHANGED; me.page = A_INVALID_PAGE; break; case Ctrl('A'): a_pastetagpost(&me, 1); returnvalue = DIRCHANGED; me.page = A_INVALID_PAGE; break; case 'a': a_appenditem(&me, 1); me.page = A_INVALID_PAGE; break; } if (me.num) switch (ch) { case 'm': a_moveitem(&me); me.page = A_INVALID_PAGE; break; case 'D': /* Ptt me.page = -1; */ a_delrange(&me, sess->backup_dir); me.page = A_INVALID_PAGE; break; case 'd': a_delete(&me, sess->backup_dir); me.page = A_INVALID_PAGE; break; case 'H': a_hideitem(&me); me.page = A_INVALID_PAGE; break; case 'T': a_newtitle(&me); me.page = A_INVALID_PAGE; break; #ifdef CHESSCOUNTRY case 'L': a_setchesslist(&me); break; #endif } } if (me.level >= SYSOP) { switch (ch) { case 'N': a_showname(&me); me.page = A_INVALID_PAGE; break; } } } free(me.header); return returnvalue; }