作者cache.bbs@cpu.tfcis.org (Gphone實驗室) 看板: itoc
標題[功能] Smart Merge 修文自動合併
時間動力核心 (2009/10/20 Tue 20:41:15)
這個 patch 可以讓使用者在大E編輯文章~存檔的這段過程中
若有其他人推文/wiki編輯時會自動合併內容
不過實際上仍然會有 synchronization 的問題, 以及推文數的漏計
可以再加上 ◆ [功能] 重新計算推文數 這個 patch
author: hrs113355.bbs <AT> xdbbs.twbbs.org
cache.bbs <AT> bbs.ee.ncku.edu.tw
首先新增這個檔案到 /include 中
https://opensvn.csie.org/NCKUEEBBS/bbs/src/include/fnv_hash.h
接下來修改以下的部分:
include/bbs.h
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
...
#include "theme.h" /* custom theme */
#include "proto.h" /* prototype of functions */
+#include "fnv_hash.h" /* for fnv_hash (Smart Merge) */
#endif /* _BBS_H_ */
include/config.h
#define SMerge /* Smart Merge 修文自動合併 */
src/post.c
+/* ----------------------------------------------------- */
+/* Smart Merge 修文自動合併 */
+/* ----------------------------------------------------- */
+
+/* cache.081225: (TODO) refine Smart Merge patch for M3-itoc */
+
+#ifdef SMerge
+/* append data from tail of src (starting point=off) to dst */
+int
+AppendTail(const char *src, const char *dst, int off)
+{
+ int fi, fo, bytes;
+ char buf[8192];
+
+ fi=open(src, O_RDONLY);
+ if(fi<0) return -1;
+
+ fo=open(dst, O_WRONLY | O_APPEND | O_CREAT, 0600);
+ if(fo<0) {close(fi); return -1;}
+ // flock(dst, LOCK_SH);
+
+ if(off > 0)
+ lseek(fi, (off_t)off, SEEK_SET);
+
+ while((bytes=read(fi, buf, sizeof(buf)))>0)
+ {
+ write(fo, buf, bytes);
+ }
+ // flock(dst, LOCK_UN);
+ close(fo);
+ close(fi);
+ return 0;
+}
+
+
+// return: 0 - ok; otherwise - fail.
+static int
+hash_partial_file( char *path, size_t sz, unsigned char output[SMHASHLEN] )
+{
+ int fd;
+ size_t n;
+ unsigned char buf[1024];
+
+ Fnv64_t fnvseed = FNV1_64_INIT;
+ assert(SMHASHLEN == sizeof(fnvseed));
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return 1;
+
+ while( sz > 0 &&
+ (n = read(fd, buf, sizeof(buf))) > 0 )
+ {
+ if (n > sz) n = sz;
+ fnvseed = fnv_64_buf(buf, (int) n, fnvseed);
+ sz -= n;
+ }
+ close(fd);
+
+ if (sz > 0) // file is different
+ return 2;
+
+ memcpy(output, (void*) &fnvseed, sizeof(fnvseed));
+ return HASHPF_RET_OK;
+}
+
+#endif
...
int
post_edit(xo)
XO *xo;
{
char fpath[64];
HDR *hdr;
FILE *fp;
+#ifdef SMerge
+ struct stat st;
+ time_t oldmt, newmt;
+ off_t oldsz, newsz;
+ char genbuf[64];
+ char SmartMerge = 1, DoRecord = 0, MergeDone = 0;
+#endif
hdr = (HDR *) xo_pool + (xo->pos - xo->top);
hdr_fpath(genbuf, xo->dir, hdr);
+
+#ifdef SMerge
+ sprintf(fpath, "tmp/edit.%s.%ld", cuser.userid, time(NULL));
+
+ f_cp(genbuf, fpath, O_APPEND); /* do Copy */
+ stat(fpath, &st);
+ oldsz = st.st_size;
+ stat(genbuf, &st);
+ oldmt = st.st_mtime;
+
+ while (1)
+ {
+ unsigned char oldsum[SMHASHLEN] = {0}, newsum[SMHASHLEN] = {0};
+
+ if (hash_partial_file(fpath, oldsz, oldsum) != HASHPF_RET_OK)
+ SmartMerge = 0;
+
+ if (HAS_PERM(PERM_ALLBOARD)) /* 站長修改 */
+ {
+
+ if(!vedit(fpath, 0))
+ {
+ if(vans("是否留下修改文章記錄?[Y/n] ") != 'n')
+ DoRecord = 1;
+ }
+ else
+ return XO_HEAD;
+ }
+ else if (cuser.userlevel && (is_author(hdr)) ) /* 原作者修改 */
+ {
+ if (!vedit(fpath, 0)) /* 若非取消則加上修改資訊 */
+ DoRecord = 1;
+ else
+ return XO_HEAD;
+ }
+ else /* itoc.010301: 提供使用者修改(但不能儲存)其他人發表的文章 */
+ {
+ #ifdef HAVE_REFUSEMARK
+ if (!chkrestrict(hdr))
+ return XO_NONE;
+ #endif
+ vedit(fpath, -1);
+ return XO_HEAD;
+ }
+
+ stat(genbuf, &st); newmt = st.st_mtime; newsz = st.st_size;
+ if (SmartMerge && newmt == oldmt || newsz < oldsz)
+ SmartMerge = 0;
+ if (SmartMerge && hash_partial_file(genbuf, oldsz, newsum) != HASHPF_RET_OK)
+ SmartMerge = 0;
+ if (SmartMerge && memcmp(oldsum, newsum, sizeof(newsum)) != 0)
+ SmartMerge = 0;
+
+ if (SmartMerge)
+ {
+ SmartMerge = 0;
+
+ clear();
+ move(b_lines-8, 0);
+ outs("\033[1;33m ▲ 檔案已被修改過! ▲\033[m\n\n");
+ outs("進行自動合併 [Smart Merge]...\n\n");
+
+ if (AppendTail(genbuf, fpath, oldsz) == 0)
+ {
+
+ oldmt = newmt;
+ outs("\033[1;32m合併成功\,新修改(或推文)已加入您的文章中。\033[m\n");
+ MergeDone = 1;
+
+ //hrs113355: since smartmerge was still dealing with some
+ //problem about synchronization, we shouldn't show the message
+ //to inform users that there would be no race condition.
+
+ //vmsg("合併過程中異動的推文數將不會被採計");
+
+ //cache.090127 (TODO) add a score counter
+
+ }
+ else
+ {
+ outs("\033[1;31m自動合併失敗。 請改用人工手動編輯合併。\033[m");
+ vmsg("合併失敗");
+ }
+ }
+ if (oldmt != newmt)
+ {
+ int c = 0;
+
+ clear();
+ move(b_lines-8, 0);
+ outs("\033[1;33m ▲ 檔案已被修改過! ▲\033[m\n\n");
+
+ outs("可能是您在編輯的過程中有人進行推文或修文。\n\n"
+ "您可以選擇直接覆蓋\檔案(y)、放棄(n),\n"
+ "或是\033[1;37m重新編輯\033[m(新文會被貼到剛編的檔案後面)(e)。\n");
+ c = vans("要直接覆蓋\檔案/取消/重新編輯? [Y/n/e]");
+
+ if (c == 'n')
+ return XO_HEAD;
+
+ if (c == 'e')
+ {
+ FILE *fp, *src;
+
+ /* merge new and old stuff */
+ fp = fopen(fpath, "at");
+ src = fopen(genbuf, "rt");
+
+ if(!fp)
+ {
+ vmsg("抱歉,檔案已損毀。");
+ if(src) fclose(src);
+ unlink(fpath); // fpath is a temp file
+ return XO_HEAD;
+ }
+
+ if(src)
+ {
+ int c = 0;
+
+ fprintf(fp, MSG_SEPERATOR "\n");
+ fprintf(fp, "以下為被修改過的最新內容: ");
+ fprintf(fp,
+ " (%s)\n",
+ Btime(&newmt));
+ fprintf(fp, MSG_SEPERATOR "\n");
+ while ((c = fgetc(src)) >= 0)
+ fputc(c, fp);
+ fclose(src);
+
+ // update oldsz, old mt records
+ stat(genbuf, &st); oldmt = st.st_mtime; oldsz = st.st_size;
+ }
+ fclose(fp);
+ continue;
+ }
+ }
+
+ //let's do something instead to keep the link with hard-linking posts
+ FILE *fp = fopen(genbuf, "w");
+ f_suck(fp, fpath);
+ fclose(fp);
+ break;
+
+ //f_mv(fpath, genbuf);
+ //break;
+
+ }
+
+ if (DoRecord)
+ {
+ if (fp = fopen(genbuf, "a"))
+ {
+ ve_banner(fp, 1);
+ fclose(fp);
+ }
+
+ btime_update(currbno);
+ if (MergeDone)
+ vmsg("合併完成");
+
+ }
+
+#else//undef SMerge
if (HAS_PERM(PERM_ALLBOARD)) /* 站長修改 */
{
#ifdef HAVE_REFUSEMARK
if (!chkrestrict(hdr))
...
vedit(fpath, -1);
}
+#endif
+
/* return post_head(xo); */
return XO_HEAD; /* itoc.021226: XZ_POST 和 XZ_XPOST 共用 post_edit() */
}
--
=[﹎:�摃�◣��:﹎Origin ]|[ ���O���� cpu.tfcis.org ]|[�搟說�﹎:]=
=[﹊:�摃�╱��:﹊Author ]|[ itlab24.ee.ncku.edu.tw ]|[���插�﹊:]=