精華區beta SetupBBS 關於我們 聯絡資訊
/*-------------------------------------------------------*/ /* record.c ( NTHU CS MapleBBS Ver 2.36 ) */ /*-------------------------------------------------------*/ /* target : binary record file I/O routines */ /* create : 95/03/29 */ /* update : 95/12/15 */ /*-------------------------------------------------------*/ #include "bbs.h" #undef HAVE_MMAP #ifdef HAVE_MMAP #include <sys/mman.h> #endif #define BUFSIZE 256 #ifdef SYSV int flock(fd, op) int fd, op; { switch (op) { case LOCK_EX: return lockf(fd, F_LOCK, 0); case LOCK_UN: return lockf(fd, F_ULOCK, 0); default: return -1; } } #endif #ifdef POSTBUG char bigbuf[10240]; int numtowrite; int bug_possible = 0; saverecords(fpath, size, pos) char *fpath; int size, pos; { int fd; if (!bug_possible) return 0; if ((fd = open(fpath, O_RDONLY)) == -1) return -1; if (pos > 5) numtowrite = 5; else numtowrite = 4; lseek(fd, (pos - numtowrite - 1) * size, L_SET); read(fd, bigbuf, numtowrite * size); } restorerecords(fpath, size, pos) char *fpath; int size, pos; { int fd; if (!bug_possible) return 0; if ((fd = open(fpath, O_WRONLY)) == -1) return -1; flock(fd, LOCK_EX); lseek(fd, (pos - numtowrite - 1) * size, L_SET); safewrite(fd, bigbuf, numtowrite * size); #ifdef HAVE_REPORT report("post bug poison set out!"); #endif flock(fd, LOCK_UN); bigbuf[0] = '\0'; close(fd); } /* 每次寫一點點,以策安全 */ static int safewrite(fd, buf, size) int fd; char *buf; int size; { int cc, sz = size, origsz = size; char *bp = buf; #ifdef POSTBUG if (size == sizeof(fileheader)) { char foo[80]; struct stat stbuf; fileheader *fbuf = (fileheader *) buf; setbpath(foo, fbuf->filename); if (!isalpha(fbuf->filename[0]) || stat(foo, &stbuf) == -1) if (fbuf->filename[0] != 'M' || fbuf->filename[1] != '.') { #ifdef HAVE_REPORT report("safewrite: foiled attempt to write bugged record\n"); #endif return origsz; } } #endif do { cc = write(fd, bp, sz); if ((cc < 0) && (errno != EINTR)) { #ifdef HAVE_REPORT report("safewrite failed!"); #endif return -1; } if (cc > 0) { bp += cc; sz -= cc; } } while (sz > 0); return origsz; } #else #define safewrite write #endif /* POSTBUG */ #if !defined(_BBS_UTIL_C_) long get_num_records(fpath, size) char *fpath; { struct stat st; if (stat(fpath, &st) == -1) return 0; return (st.st_size / size); } get_sum_records(char* fpath, int size) { struct stat st; long ans = 0; FILE* fp; fileheader fhdr; char buf[200], *p; if (!(fp = fopen(fpath, "r"))) return -1; strcpy(buf, fpath); p = strrchr(buf, '/') + 1; while (fread(&fhdr, size, 1, fp) == 1) { strcpy(p, fhdr.filename); if (stat(buf, &st) == 0 && S_ISREG(st.st_mode) && st.st_nlink == 1) ans += st.st_size; } fclose(fp); return ans / 1024; } int get_record(fpath, rptr, size, id) char *fpath; char *rptr; int size, id; { int fd; if ((fd = open(fpath, O_RDONLY, 0)) != -1) { if (lseek(fd, size * (id - 1), SEEK_SET) != -1) { if (read(fd, rptr, size) == size) { close(fd); return 0; } } close(fd); } return -1; } int get_records(fpath, rptr, size, id, number) char *fpath; char *rptr; int size, id, number; { int fd; if ((fd = open(fpath, O_RDONLY, 0)) == -1) return -1; #ifdef HAVE_MMAP { int offset; caddr_t fimage; struct stat stbuf; fstat(fd, &stbuf); fimage = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (fimage == (char *) -1) return -1; offset = size * (id - 1); id = size * number; number = stbuf.st_size - offset; if (id > number) id = number; memcpy(rptr, fimage + offset, n); munmap(fimage, stbuf.st_size); } #else if (lseek(fd, size * (id - 1), SEEK_SET) == -1) { close(fd); return 0; } if ((id = read(fd, rptr, size * number)) == -1) { close(fd); return -1; } close(fd); #endif return (id / size); } int substitute_record(fpath, rptr, size, id) char *fpath; char *rptr; int size, id; { int fd; #ifdef POSTBUG if (size == sizeof(fileheader) && (id > 1) && ((id - 1) % 4 == 0)) saverecords(fpath, size, id); #endif if ((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1) return -1; flock(fd, LOCK_EX); #ifdef HAVE_REPORT if (lseek(fd, size * (id - 1), SEEK_SET) == -1) report("substitute_record failed!!! (lseek)"); if (safewrite(fd, rptr, size) != size) report("substitute_record failed!!! (safewrite)"); #else lseek(fd, (off_t) size * (id - 1), SEEK_SET); safewrite(fd, rptr, size); #endif flock(fd, LOCK_UN); close(fd); #ifdef POSTBUG if (size == sizeof(fileheader) && (id > 1) && ((id - 1) % 4 == 0)) restorerecords(fpath, size, id); #endif return 0; } /* ---------------------------- */ /* new/old/lock file processing */ /* ---------------------------- */ typedef struct /* Ptt*/ { char newfn[256]; char oldfn[256]; char lockfn[256]; } nol; static void nolfilename(n, fpath) nol *n; char *fpath; { sprintf(n->newfn, "%s.new", fpath); sprintf(n->oldfn, "%s.old", fpath); sprintf(n->lockfn, "%s.lock", fpath); } int delete_record(fpath, size, id) char fpath[]; int size, id; { nol my; char abuf[BUFSIZE]; int fdr, fdw, fd; int count; nolfilename(&my, fpath); if ((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1) return -1; flock(fd, LOCK_EX); if ((fdr = open(fpath, O_RDONLY, 0)) == -1) { #ifdef HAVE_REPORT report("delete_record failed!!! (open)"); #endif flock(fd, LOCK_UN); close(fd); return -1; } if ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) { flock(fd, LOCK_UN); #ifdef HAVE_REPORT report("delete_record failed!!! (open tmpfile)"); #endif close(fd); close(fdr); return -1; } count = 1; while (read(fdr, abuf, size) == size) { if (id != count++ && (safewrite(fdw, abuf, size) == -1)) { #ifdef HAVE_REPORT report("delete_record failed!!! (safewrite)"); #endif unlink(my.newfn); close(fdr); close(fdw); flock(fd, LOCK_UN); close(fd); return -1; } } close(fdr); close(fdw); if (Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1) { #ifdef HAVE_REPORT report("delete_record failed!!! (Rename)"); #endif flock(fd, LOCK_UN); close(fd); return -1; } flock(fd, LOCK_UN); close(fd); return 0; } char * title_body(title) char *title; { if (!strncasecmp(title, str_reply, 3)) { title += 3; if (*title == ' ') title++; } return title; } int delete_range(fpath, id1, id2, title) char *fpath; int id1, id2; char *title; { fileheader fhdr; nol my; char fullpath[STRLEN], *t; int fdr, fdw, fd; int count; nolfilename(&my, fpath); if ((fd = open(my.lockfn, O_RDWR | O_CREAT | O_APPEND, 0644)) == -1) return -1; flock(fd, LOCK_EX); if ((fdr = open(fpath, O_RDONLY, 0)) == -1) { flock(fd, LOCK_UN); close(fd); return -1; } if ((fdw = open(my.newfn, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) { close(fdr); flock(fd, LOCK_UN); close(fd); return -1; } count = 1; strcpy(fullpath, fpath); t = (char *) strrchr(fullpath, '/') + 1; while (read(fdr, &fhdr, sizeof(fileheader)) == sizeof(fileheader)) { if ((count < id1 || count > id2 || fhdr.filemode & FILE_MARKED || fhdr.filemode & FILE_DIGEST ) && (!title || strcmp(title_body(title), title_body(fhdr.title)))) { if ((safewrite(fdw, &fhdr, sizeof(fileheader)) == -1)) { close(fdr); close(fdw); unlink(my.newfn); flock(fd, LOCK_UN); close(fd); return -1; } } else { strcpy(t, fhdr.filename); unlink(fullpath); } count++; } close(fdr); close(fdw); if (Rename(fpath, my.oldfn) == -1 || Rename(my.newfn, fpath) == -1) { flock(fd, LOCK_UN); close(fd); return -1; } flock(fd, LOCK_UN); close(fd); return 0; } int update_file(dirname, size, ent, filecheck, fileupdate) char *dirname; int size, ent; int (*filecheck) (); void (*fileupdate) (); { char abuf[BUFSIZE]; int fd; if ((fd = open(dirname, O_RDWR)) == -1) return -1; flock(fd, LOCK_EX); if (lseek(fd, size * (ent - 1), SEEK_SET) != -1) { if (read(fd, abuf, size) == size) if ((*filecheck) (abuf)) { lseek(fd, -(off_t)size, SEEK_CUR); (*fileupdate) (abuf); if (safewrite(fd, abuf, size) != size) { #ifdef HAVE_REPORT report("update_file failed!!! (safewrite)"); #endif flock(fd, LOCK_UN); close(fd); return -1; } flock(fd, LOCK_UN); close(fd); return 0; } } lseek(fd, 0, SEEK_SET); while (read(fd, abuf, size) == size) { if ((*filecheck) (abuf)) { lseek(fd, -(off_t)size, SEEK_CUR); (*fileupdate) (abuf); if (safewrite(fd, abuf, size) == size) { #ifdef HAVE_REPORT report("update_file failed!!! (safewrite)"); #endif flock(fd, LOCK_UN); close(fd); return 0; } break; } } flock(fd, LOCK_UN); close(fd); return -1; } /* woju */ int search_rec(char* dirname, int (*filecheck)()) { fileheader fhdr; FILE *fp; int ans = 0; if (!(fp = fopen(dirname, "r"))) return 0; while (fread(&fhdr, sizeof(fhdr), 1, fp)) { ans++; if ((*filecheck) (&fhdr)) { fclose(fp); return ans; } } fclose(fp); return 0; } int delete_files(char* dirname, int (*filecheck)()) { fileheader fhdr; FILE *fp, *fptmp; int ans = 0; char tmpfname[100]; char genbuf[200]; if (!(fp = fopen(dirname, "r"))) return ans; strcpy(tmpfname, dirname); strcat(tmpfname, "_tmp"); if (!(fptmp = fopen(tmpfname, "w"))) { fclose(fp); return ans; } while (fread(&fhdr, sizeof(fhdr), 1, fp)) if ((*filecheck) (&fhdr)) { ans++; setdirpath(genbuf, dirname, fhdr.filename); unlink(genbuf); } else fwrite(&fhdr, sizeof(fhdr), 1, fptmp); fclose(fp); fclose(fptmp); unlink(dirname); Rename(tmpfname, dirname); return ans; } int delete_file(dirname, size, ent, filecheck) char *dirname; int size, ent; int (*filecheck) (); { char abuf[BUFSIZE]; int fd; struct stat st; long numents; if ((fd = open(dirname, O_RDWR)) == -1) return -1; flock(fd, LOCK_EX); fstat(fd, &st); numents = ((long) st.st_size) / size; if (((long) st.st_size) % size) fprintf(stderr, "align err\n"); if (lseek(fd, size * (ent - 1), SEEK_SET) != -1) { if (read(fd, abuf, size) == size) if ((*filecheck) (abuf)) { int i; for (i = ent; i < numents; i++) { if (lseek(fd, (i) * size, SEEK_SET) == -1) break; if (read(fd, abuf, size) != size) break; if (lseek(fd, (i - 1) * size, SEEK_SET) == -1) break; if (safewrite(fd, abuf, size) != size) break; } ftruncate(fd, (off_t) size * (numents - 1)); flock(fd, LOCK_UN); close(fd); return 0; } } lseek(fd, 0, SEEK_SET); ent = 1; while (read(fd, abuf, size) == size) { if ((*filecheck) (abuf)) { int i; for (i = ent; i < numents; i++) { if (lseek(fd, (i + 1) * size, SEEK_SET) == -1) break; if (read(fd, abuf, size) != size) break; if (lseek(fd, (i) * size, SEEK_SET) == -1) break; if (safewrite(fd, abuf, size) != size) break; } ftruncate(fd, (off_t) size * (numents - 1)); flock(fd, LOCK_UN); close(fd); return 0; } ent++; } flock(fd, LOCK_UN); close(fd); return -1; } int search_record(fpath, rptr, size, fptr, farg) char *fpath; char *rptr; int size; int (*fptr) (); int farg; { int fd; int id = 1; if ((fd = open(fpath, O_RDONLY, 0)) == -1) return 0; while (read(fd, rptr, size) == size) { if ((*fptr) (farg, rptr)) { close(fd); return id; } id++; } close(fd); return 0; } #endif /* !defined(_BBS_UTIL_C_) */ /* woju */ int apply_record(fpath, fptr, size) char *fpath; int (*fptr) (); int size; { char abuf[BUFSIZE]; FILE* fp; if (!(fp = fopen(fpath, "r"))) return -1; while (fread(abuf, 1, size, fp) == size) if ((*fptr) (abuf) == QUIT) { fclose(fp); return QUIT; } fclose(fp); return 0; } /* ------------------------------------------ */ /* mail / post 時,依據時間建立檔案,加上郵戳 */ /* ------------------------------------------ */ /* Input: fpath = directory; Output: fpath = full path; */ void stampfile(fpath, fh) char *fpath; fileheader *fh; { register char *ip = fpath; time_t dtime; struct tm *ptime; int fp; #if 1 if (access(fpath, X_OK | R_OK | W_OK)) mkdir(fpath, 0755); #endif time(&dtime); while (*(++ip)); *ip++ = '/'; do { sprintf(ip, "M.%d.A", ++dtime ); } while ((fp = open(fpath, O_CREAT | O_EXCL | O_WRONLY, 0644)) == -1); close(fp); memset(fh, 0, sizeof(fileheader)); strcpy(fh->filename, ip); ptime = localtime(&dtime); sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday); } /* ===== Added by mgtsai, Sep 10th, '96 ===== */ void stampdir(fpath, fh) char *fpath; fileheader *fh; { register char *ip = fpath; time_t dtime; struct tm *ptime; #if 1 if (access(fpath, X_OK | R_OK | W_OK)) mkdir(fpath, 0755); #endif time(&dtime); while (*(++ip)); *ip++ = '/'; do { sprintf(ip, "D%X", ++dtime & 07777); } while (mkdir(fpath, 0755) == -1); memset(fh, 0, sizeof(fileheader)); strcpy(fh->filename, ip); ptime = localtime(&dtime); sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday); } void stamplink(fpath, fh) char *fpath; fileheader *fh; { register char *ip = fpath; time_t dtime; struct tm *ptime; #if 1 if (access(fpath, X_OK | R_OK | W_OK)) mkdir(fpath, 0755); #endif time(&dtime); while (*(++ip)); *ip++ = '/'; do { sprintf(ip, "S%X", ++dtime & 07777); } while (symlink("temp", fpath) == -1); memset(fh, 0, sizeof(fileheader)); strcpy(fh->filename, ip); ptime = localtime(&dtime); sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday); } /* ===== end ===== */ #if !defined(_BBS_UTIL_C_) extern int bbs_sendmail(char *fpath, char *title, char *receiver); #endif do_append(fpath,record,size) char *fpath; fileheader *record; int size; { int fd; if ((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1) { perror("open"); return -1; } flock(fd, LOCK_EX); lseek(fd, 0, SEEK_END); safewrite(fd, record, size); flock(fd, LOCK_UN); close(fd); return 0; } int append_record(fpath, record, size) char *fpath; fileheader *record; int size; { int fd , m,n; #ifdef POSTBUG int numrecs = (int) get_num_records(fpath, size); bug_possible = 1; if (size == sizeof(fileheader) && numrecs && (numrecs % 4 == 0)) saverecords(fpath, size, numrecs + 1); #endif #if !defined(_BBS_UTIL_C_) /* forward */ if( get_num_records(fpath, sizeof(fileheader)) <= MAXKEEPMAIL * 2) { FILE *fp; char buf[512],address[200]; for(n = strlen(fpath) - 1 ; fpath[n] != '/' && n>0 ; n--); strncpy(buf,fpath,n+1); buf[n+1] = 0; for(m = strlen(buf) - 2 ; buf[m] != '/' && m>0 ; m--); strcat(buf,".forward"); if(fp = fopen(buf,"r")) { fscanf(fp,"%s",address); fclose(fp); if(buf[0] != 0 && buf[0] != ' ') { buf[n+1] = 0; strcat(buf,record->filename); if(fp = fopen(buf,"a")) { buf[n] = 0; fprintf(fp, "\n※ 從實業坊使用者 %s 信箱自動轉寄" "\n◆ From: %s.bbs@ptt.m8.ntu.edu.tw " "\n To : %s", &buf[m+1],&buf[m+1],address); buf[n] = '/'; fclose(fp); } /* reset_tty();*/ record->filemode |= FILE_TAGED; do_append(fpath,record,size); bbs_sendmail(buf,record->title,address); /* restore_tty();*/ return 0; } } } #endif do_append(fpath,record,size); #ifdef POSTBUG if (size == sizeof(fileheader) && numrecs && (numrecs % 4 == 0)) restorerecords(fpath, size, numrecs + 1); bug_possible = 0; #endif return 0; }