Remove dependency to ccnet.

This commit is contained in:
Jonathan Xu 2018-06-26 12:11:35 +08:00
parent 8b60a0f272
commit 2d67426c03
116 changed files with 1240 additions and 26339 deletions

View File

@ -1,12 +1,6 @@
SUBDIRS = cdc index
proc_headers =
$(addprefix processors/, \
objecttx-common.h)
noinst_HEADERS = \
unpack-trees.h \
seaf-tree-walk.h \
diff-simple.h \
seafile-crypt.h \
common.h \
@ -15,16 +9,10 @@ noinst_HEADERS = \
block-mgr.h \
commit-mgr.h \
log.h \
object-list.h \
vc-common.h \
seaf-utils.h \
obj-store.h \
obj-backend.h \
block-backend.h \
block.h \
mq-mgr.h \
seaf-db.h \
merge-new.h \
block-tx-utils.h \
curl-init.h \
$(proc_headers)
curl-init.h

View File

@ -4,7 +4,6 @@
#include "seafile-session.h"
#include "utils.h"
#include "seaf-utils.h"
#include "block-mgr.h"
#include "log.h"

View File

@ -1,305 +0,0 @@
#include "common.h"
#ifndef USE_GPL_CRYPTO
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include "utils.h"
#include "block-tx-utils.h"
/* Utility functions for block transfer protocol. */
/* Encryption related functions. */
void
blocktx_generate_encrypt_key (unsigned char *session_key, int sk_len,
unsigned char *key, unsigned char *iv)
{
EVP_BytesToKey (EVP_aes_256_cbc(), /* cipher mode */
EVP_sha1(), /* message digest */
NULL, /* salt */
session_key,
sk_len,
3, /* iteration times */
key, /* the derived key */
iv); /* IV, initial vector */
}
int
blocktx_encrypt_init (EVP_CIPHER_CTX **ctx,
const unsigned char *key,
const unsigned char *iv)
{
int ret;
/* Prepare CTX for encryption. */
*ctx = EVP_CIPHER_CTX_new ();
ret = EVP_EncryptInit_ex (*ctx,
EVP_aes_256_cbc(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
if (ret == 0) {
EVP_CIPHER_CTX_free (*ctx);
return -1;
}
return 0;
}
int
blocktx_decrypt_init (EVP_CIPHER_CTX **ctx,
const unsigned char *key,
const unsigned char *iv)
{
int ret;
/* Prepare CTX for decryption. */
*ctx = EVP_CIPHER_CTX_new ();
ret = EVP_DecryptInit_ex (*ctx,
EVP_aes_256_cbc(), /* cipher mode */
NULL, /* engine, NULL for default */
key, /* derived key */
iv); /* initial vector */
if (ret == 0) {
EVP_CIPHER_CTX_free (*ctx);
return -1;
}
return 0;
}
/* Sending frame */
int
send_encrypted_data_frame_begin (evutil_socket_t data_fd,
int frame_len)
{
/* Compute data size after encryption.
* Block size is 16 bytes and AES always add one padding block.
*/
int enc_frame_len;
enc_frame_len = ((frame_len >> 4) + 1) << 4;
enc_frame_len = htonl (enc_frame_len);
if (sendn (data_fd, &enc_frame_len, sizeof(int)) < 0) {
seaf_warning ("Failed to send frame length: %s.\n",
evutil_socket_error_to_string(evutil_socket_geterror(data_fd)));
return -1;
}
return 0;
}
int
send_encrypted_data (EVP_CIPHER_CTX *ctx,
evutil_socket_t data_fd,
const void *buf, int len)
{
char out_buf[len + ENC_BLOCK_SIZE];
int out_len;
if (EVP_EncryptUpdate (ctx,
(unsigned char *)out_buf, &out_len,
(unsigned char *)buf, len) == 0) {
seaf_warning ("Failed to encrypt data.\n");
return -1;
}
if (sendn (data_fd, out_buf, out_len) < 0) {
seaf_warning ("Failed to write data: %s.\n",
evutil_socket_error_to_string(evutil_socket_geterror(data_fd)));
return -1;
}
return 0;
}
int
send_encrypted_data_frame_end (EVP_CIPHER_CTX *ctx,
evutil_socket_t data_fd)
{
char out_buf[ENC_BLOCK_SIZE];
int out_len;
if (EVP_EncryptFinal_ex (ctx, (unsigned char *)out_buf, &out_len) == 0) {
seaf_warning ("Failed to encrypt data.\n");
return -1;
}
if (sendn (data_fd, out_buf, out_len) < 0) {
seaf_warning ("Failed to write data: %s.\n",
evutil_socket_error_to_string(evutil_socket_geterror(data_fd)));
return -1;
}
return 0;
}
/* Receiving frame */
static int
handle_frame_content (struct evbuffer *buf, FrameParser *parser)
{
char *frame;
EVP_CIPHER_CTX *ctx;
char *out;
int outlen, outlen2;
int ret = 0;
struct evbuffer *input = buf;
if (evbuffer_get_length (input) < parser->enc_frame_len)
return 0;
if (parser->version == 1)
blocktx_decrypt_init (&ctx, parser->key, parser->iv);
else if (parser->version == 2)
blocktx_decrypt_init (&ctx, parser->key_v2, parser->iv_v2);
frame = g_malloc (parser->enc_frame_len);
out = g_malloc (parser->enc_frame_len + ENC_BLOCK_SIZE);
evbuffer_remove (input, frame, parser->enc_frame_len);
if (EVP_DecryptUpdate (ctx,
(unsigned char *)out, &outlen,
(unsigned char *)frame,
parser->enc_frame_len) == 0) {
seaf_warning ("Failed to decrypt frame content.\n");
ret = -1;
goto out;
}
if (EVP_DecryptFinal_ex (ctx, (unsigned char *)(out + outlen), &outlen2) == 0)
{
seaf_warning ("Failed to decrypt frame content.\n");
ret = -1;
goto out;
}
ret = parser->content_cb (out, outlen + outlen2, parser->cbarg);
out:
g_free (frame);
g_free (out);
parser->enc_frame_len = 0;
EVP_CIPHER_CTX_free (ctx);
return ret;
}
int
handle_one_frame (struct evbuffer *buf, FrameParser *parser)
{
struct evbuffer *input = buf;
if (!parser->enc_frame_len) {
/* Read the length of the encrypted frame first. */
if (evbuffer_get_length (input) < sizeof(int))
return 0;
int frame_len;
evbuffer_remove (input, &frame_len, sizeof(int));
parser->enc_frame_len = ntohl (frame_len);
if (evbuffer_get_length (input) > 0)
return handle_frame_content (buf, parser);
return 0;
} else {
return handle_frame_content (buf, parser);
}
}
static int
handle_frame_fragment_content (struct evbuffer *buf, FrameParser *parser)
{
char *fragment = NULL, *out = NULL;
int fragment_len, outlen;
int ret = 0;
struct evbuffer *input = buf;
fragment_len = evbuffer_get_length (input);
fragment = g_malloc (fragment_len);
evbuffer_remove (input, fragment, fragment_len);
out = g_malloc (fragment_len + ENC_BLOCK_SIZE);
if (EVP_DecryptUpdate (parser->ctx,
(unsigned char *)out, &outlen,
(unsigned char *)fragment, fragment_len) == 0) {
seaf_warning ("Failed to decrypt frame fragment.\n");
ret = -1;
goto out;
}
ret = parser->fragment_cb (out, outlen, 0, parser->cbarg);
if (ret < 0)
goto out;
parser->remain -= fragment_len;
if (parser->remain <= 0) {
if (EVP_DecryptFinal_ex (parser->ctx,
(unsigned char *)out,
&outlen) == 0) {
seaf_warning ("Failed to decrypt frame fragment.\n");
ret = -1;
goto out;
}
ret = parser->fragment_cb (out, outlen, 1, parser->cbarg);
if (ret < 0)
goto out;
EVP_CIPHER_CTX_free (parser->ctx);
parser->enc_init = FALSE;
parser->enc_frame_len = 0;
}
out:
g_free (fragment);
g_free (out);
if (ret < 0) {
EVP_CIPHER_CTX_free (parser->ctx);
parser->enc_init = FALSE;
parser->enc_frame_len = 0;
}
return ret;
}
int
handle_frame_fragments (struct evbuffer *buf, FrameParser *parser)
{
struct evbuffer *input = buf;
if (!parser->enc_frame_len) {
/* Read the length of the encrypted frame first. */
if (evbuffer_get_length (input) < sizeof(int))
return 0;
int frame_len;
evbuffer_remove (input, &frame_len, sizeof(int));
parser->enc_frame_len = ntohl (frame_len);
parser->remain = parser->enc_frame_len;
if (parser->version == 1)
blocktx_decrypt_init (&parser->ctx, parser->key, parser->iv);
else if (parser->version == 2)
blocktx_decrypt_init (&parser->ctx, parser->key_v2, parser->iv_v2);
parser->enc_init = TRUE;
if (evbuffer_get_length (input) > 0)
return handle_frame_fragment_content (buf, parser);
return 0;
} else {
return handle_frame_fragment_content (buf, parser);
}
}
#endif

View File

@ -1,142 +0,0 @@
#ifndef BLOCK_TX_UTILS_H
#define BLOCK_TX_UTILS_H
#include <event2/buffer.h>
#include <event2/util.h>
#include <openssl/evp.h>
/* Common structures and contants shared by the client and server. */
/* We use AES 256 */
#define ENC_KEY_SIZE 32
#define ENC_BLOCK_SIZE 16
#define BLOCK_PROTOCOL_VERSION 2
enum {
STATUS_OK = 0,
STATUS_VERSION_MISMATCH,
STATUS_BAD_REQUEST,
STATUS_ACCESS_DENIED,
STATUS_INTERNAL_SERVER_ERROR,
STATUS_NOT_FOUND,
};
struct _HandshakeRequest {
gint32 version;
gint32 key_len;
char enc_session_key[0];
} __attribute__((__packed__));
typedef struct _HandshakeRequest HandshakeRequest;
struct _HandshakeResponse {
gint32 status;
gint32 version;
} __attribute__((__packed__));
typedef struct _HandshakeResponse HandshakeResponse;
struct _AuthResponse {
gint32 status;
} __attribute__((__packed__));
typedef struct _AuthResponse AuthResponse;
enum {
REQUEST_COMMAND_GET = 0,
REQUEST_COMMAND_PUT,
};
struct _RequestHeader {
gint32 command;
char block_id[40];
} __attribute__((__packed__));
typedef struct _RequestHeader RequestHeader;
struct _ResponseHeader {
gint32 status;
} __attribute__((__packed__));
typedef struct _ResponseHeader ResponseHeader;
/* Utility functions for encryption. */
void
blocktx_generate_encrypt_key (unsigned char *session_key, int sk_len,
unsigned char *key, unsigned char *iv);
int
blocktx_encrypt_init (EVP_CIPHER_CTX **ctx,
const unsigned char *key,
const unsigned char *iv);
int
blocktx_decrypt_init (EVP_CIPHER_CTX **ctx,
const unsigned char *key,
const unsigned char *iv);
/*
* Encrypted data is sent in "frames".
* Format of a frame:
*
* length of data in the frame after encryption + encrypted data.
*
* Each frame can contain three types of contents:
* 1. Auth request or response;
* 2. Block request or response header;
* 3. Block content.
*/
int
send_encrypted_data_frame_begin (evutil_socket_t data_fd,
int frame_len);
int
send_encrypted_data (EVP_CIPHER_CTX *ctx,
evutil_socket_t data_fd,
const void *buf, int len);
int
send_encrypted_data_frame_end (EVP_CIPHER_CTX *ctx,
evutil_socket_t data_fd);
typedef int (*FrameContentCB) (char *, int, void *);
typedef int (*FrameFragmentCB) (char *, int, int, void *);
typedef struct _FrameParser {
int enc_frame_len;
unsigned char key[ENC_KEY_SIZE];
unsigned char iv[ENC_BLOCK_SIZE];
gboolean enc_init;
EVP_CIPHER_CTX *ctx;
unsigned char key_v2[ENC_KEY_SIZE];
unsigned char iv_v2[ENC_BLOCK_SIZE];
int version;
/* Used when parsing fragments */
int remain;
FrameContentCB content_cb;
FrameFragmentCB fragment_cb;
void *cbarg;
} FrameParser;
/* Handle entire frame all at once.
* parser->content_cb() will be called after the entire frame is read.
*/
int
handle_one_frame (struct evbuffer *buf, FrameParser *parser);
/* Handle a frame fragment by fragment.
* parser->fragment_cb() will be called when any amount data is read.
*/
int
handle_frame_fragments (struct evbuffer *buf, FrameParser *parser);
#endif

View File

@ -12,7 +12,6 @@
#include "seafile-session.h"
#include "commit-mgr.h"
#include "seaf-utils.h"
#define MAX_TIME_SKEW 259200 /* 3 days */

View File

@ -3,10 +3,6 @@
#include "utils.h"
#include "log.h"
#ifndef SEAFILE_SERVER
#include "unpack-trees.h"
#endif
DiffEntry *
diff_entry_new (char type, char status, unsigned char *sha1, const char *name)
{
@ -36,7 +32,6 @@ diff_entry_new_from_dirent (char type, char status,
memcpy (de->sha1, sha1, 20);
de->name = path;
#ifdef SEAFILE_CLIENT
if (type == DIFF_TYPE_COMMITS &&
(status == DIFF_STATUS_ADDED ||
status == DIFF_STATUS_MODIFIED ||
@ -47,7 +42,6 @@ diff_entry_new_from_dirent (char type, char status,
de->modifier = g_strdup(dent->modifier);
de->size = dent->size;
}
#endif
return de;
}
@ -59,114 +53,11 @@ diff_entry_free (DiffEntry *de)
if (de->new_name)
g_free (de->new_name);
#ifdef SEAFILE_CLIENT
g_free (de->modifier);
#endif
g_free (de);
}
#ifndef SEAFILE_SERVER
static void
diff_two_cache_entries (struct cache_entry *tree1,
struct cache_entry *tree2,
int diff_type,
GList **results)
{
DiffEntry *de;
if (!tree1) {
if (S_ISDIR(tree2->ce_mode)) {
de = diff_entry_new (diff_type, DIFF_STATUS_DIR_ADDED,
tree2->sha1, tree2->name);
} else {
de = diff_entry_new (diff_type, DIFF_STATUS_ADDED,
tree2->sha1, tree2->name);
}
*results = g_list_prepend (*results, de);
return;
}
if (!tree2) {
if (S_ISDIR(tree1->ce_mode)) {
de = diff_entry_new (diff_type, DIFF_STATUS_DIR_DELETED,
tree1->sha1, tree1->name);
} else {
de = diff_entry_new (diff_type, DIFF_STATUS_DELETED,
tree1->sha1, tree1->name);
}
*results = g_list_prepend (*results, de);
return;
}
if (tree2->ce_mode != tree1->ce_mode || hashcmp(tree2->sha1, tree1->sha1) != 0) {
if (S_ISDIR(tree2->ce_mode)) {
de = diff_entry_new (diff_type, DIFF_STATUS_DELETED,
tree1->sha1, tree1->name);
*results = g_list_prepend (*results, de);
de = diff_entry_new (diff_type, DIFF_STATUS_DIR_ADDED,
tree2->sha1, tree2->name);
*results = g_list_prepend (*results, de);
} else if (S_ISDIR(tree1->ce_mode)) {
de = diff_entry_new (diff_type, DIFF_STATUS_DIR_DELETED,
tree1->sha1, tree1->name);
*results = g_list_prepend (*results, de);
de = diff_entry_new (diff_type, DIFF_STATUS_ADDED,
tree2->sha1, tree2->name);
*results = g_list_prepend (*results, de);
} else {
de = diff_entry_new (diff_type, DIFF_STATUS_MODIFIED,
tree2->sha1, tree2->name);
*results = g_list_prepend (*results, de);
}
}
}
static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
{
struct cache_entry *idx = src[0];
struct cache_entry *tree = src[1];
GList **results = o->unpack_data;
if (idx == o->df_conflict_entry)
idx = NULL;
if (tree == o->df_conflict_entry)
tree = NULL;
diff_two_cache_entries (tree, idx, DIFF_TYPE_INDEX, results);
return 0;
}
int diff_index(const char *repo_id, int version,
struct index_state *istate, SeafDir *root, GList **results)
{
struct tree_desc t;
struct unpack_trees_options opts;
memset(&opts, 0, sizeof(opts));
memcpy (opts.repo_id, repo_id, 36);
opts.version = version;
opts.head_idx = 1;
opts.index_only = 1;
/* Unmerged entries are handled in diff worktree. */
opts.skip_unmerged = 1;
opts.merge = 1;
opts.fn = oneway_diff;
opts.unpack_data = results;
opts.src_index = istate;
opts.dst_index = NULL;
fill_tree_descriptor(repo_id, version, &t, root->dir_id);
int ret = unpack_trees(1, &t, &opts);
tree_desc_free (&t);
return ret;
}
#endif /* not SEAFILE_SERVER */
inline static gboolean
dirent_same (SeafDirent *denta, SeafDirent *dentb)
{
@ -456,20 +347,12 @@ diff_commits (SeafCommit *commit1, SeafCommit *commit2, GList **results,
data.fold_dir_diff = fold_dir_diff;
memset (&opt, 0, sizeof(opt));
#ifdef SEAFILE_SERVER
memcpy (opt.store_id, repo->store_id, 36);
#else
memcpy (opt.store_id, repo->id, 36);
#endif
opt.version = repo->version;
opt.file_cb = twoway_diff_files;
opt.dir_cb = twoway_diff_dirs;
opt.data = &data;
#ifdef SEAFILE_SERVER
seaf_repo_unref (repo);
#endif
roots[0] = commit1->root_id;
roots[1] = commit2->root_id;
@ -608,20 +491,12 @@ diff_merge (SeafCommit *merge, GList **results, gboolean fold_dir_diff)
data.fold_dir_diff = fold_dir_diff;
memset (&opt, 0, sizeof(opt));
#ifdef SEAFILE_SERVER
memcpy (opt.store_id, repo->store_id, 36);
#else
memcpy (opt.store_id, repo->id, 36);
#endif
opt.version = repo->version;
opt.file_cb = threeway_diff_files;
opt.dir_cb = threeway_diff_dirs;
opt.data = &data;
#ifdef SEAFILE_SERVER
seaf_repo_unref (repo);
#endif
roots[0] = merge->root_id;
roots[1] = parent1->root_id;
roots[2] = parent2->root_id;

View File

@ -2,8 +2,6 @@
#include "common.h"
#include <ccnet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
@ -19,7 +17,6 @@
#include "fs-mgr.h"
#include "block-mgr.h"
#include "utils.h"
#include "seaf-utils.h"
#define DEBUG_FLAG SEAFILE_DEBUG_OTHER
#include "log.h"
#include "../common/seafile-crypt.h"

View File

@ -1,589 +0,0 @@
#include "seafile-session.h"
#include "merge-new.h"
#include "vc-common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_MERGE
#include "log.h"
static int
merge_trees_recursive (const char *store_id, int version,
int n, SeafDir *trees[],
const char *basedir,
MergeOptions *opt);
static char *
merge_conflict_filename (const char *store_id, int version,
MergeOptions *opt,
const char *basedir,
const char *filename)
{
char *path = NULL, *modifier = NULL, *conflict_name = NULL;
gint64 mtime;
SeafCommit *commit;
path = g_strconcat (basedir, filename, NULL);
int rc = get_file_modifier_mtime (opt->remote_repo_id,
store_id,
version,
opt->remote_head,
path,
&modifier, &mtime);
if (rc < 0) {
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
opt->remote_repo_id,
version,
opt->remote_head);
if (!commit) {
seaf_warning ("Failed to find remote head %s:%s.\n",
opt->remote_repo_id, opt->remote_head);
goto out;
}
modifier = g_strdup(commit->creator_name);
mtime = (gint64)time(NULL);
seaf_commit_unref (commit);
}
conflict_name = gen_conflict_path (filename, modifier, mtime);
out:
g_free (path);
g_free (modifier);
return conflict_name;
}
static char *
merge_conflict_dirname (const char *store_id, int version,
MergeOptions *opt,
const char *basedir,
const char *dirname)
{
char *modifier = NULL, *conflict_name = NULL;
SeafCommit *commit;
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
opt->remote_repo_id, version,
opt->remote_head);
if (!commit) {
seaf_warning ("Failed to find remote head %s:%s.\n",
opt->remote_repo_id, opt->remote_head);
goto out;
}
modifier = g_strdup(commit->creator_name);
seaf_commit_unref (commit);
conflict_name = gen_conflict_path (dirname, modifier, (gint64)time(NULL));
out:
g_free (modifier);
return conflict_name;
}
static int
merge_entries (const char *store_id, int version,
int n, SeafDirent *dents[],
const char *basedir,
GList **dents_out,
MergeOptions *opt)
{
SeafDirent *files[3];
int i;
memset (files, 0, sizeof(files[0])*n);
for (i = 0; i < n; ++i) {
if (dents[i] && S_ISREG(dents[i]->mode))
files[i] = dents[i];
}
/* If we're running 2-way merge, or the caller requires not to
* actually merge contents, just call the callback function.
*/
if (n == 2 || !opt->do_merge)
return opt->callback (basedir, files, opt);
/* Otherwise, we're doing a real 3-way merge of the trees.
* It means merge files and handle any conflicts.
*/
SeafDirent *base, *head, *remote;
char *conflict_name;
base = files[0];
head = files[1];
remote = files[2];
if (head && remote) {
if (strcmp (head->id, remote->id) == 0) {
seaf_debug ("%s%s: files match\n", basedir, head->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
} else if (base && strcmp (base->id, head->id) == 0) {
seaf_debug ("%s%s: unchanged in head, changed in remote\n",
basedir, head->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
} else if (base && strcmp (base->id, remote->id) == 0) {
seaf_debug ("%s%s: unchanged in remote, changed in head\n",
basedir, head->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
} else {
/* File content conflict. */
seaf_debug ("%s%s: files conflict\n", basedir, head->name);
conflict_name = merge_conflict_filename(store_id, version,
opt,
basedir,
head->name);
if (!conflict_name)
return -1;
/* Change remote entry name in place. So opt->callback
* will see the conflict name, not the original name.
*/
g_free (remote->name);
remote->name = conflict_name;
remote->name_len = strlen (remote->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
opt->conflict = TRUE;
}
} else if (base && !head && remote) {
if (strcmp (base->id, remote->id) != 0) {
if (dents[1] != NULL) {
/* D/F conflict:
* Head replaces file with dir, while remote change the file.
*/
seaf_debug ("%s%s: DFC, file -> dir, file\n",
basedir, remote->name);
conflict_name = merge_conflict_filename(store_id, version,
opt,
basedir,
remote->name);
if (!conflict_name)
return -1;
/* Change the name of remote, keep dir name in head unchanged.
*/
g_free (remote->name);
remote->name = conflict_name;
remote->name_len = strlen (remote->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
opt->conflict = TRUE;
} else {
/* Deleted in head and changed in remote. */
seaf_debug ("%s%s: deleted in head and changed in remote\n",
basedir, remote->name);
/* Keep version of remote. */
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
}
} else {
/* If base and remote match, the file should not be added to
* the merge result.
*/
seaf_debug ("%s%s: file deleted in head, unchanged in remote\n",
basedir, remote->name);
}
} else if (base && head && !remote) {
if (strcmp (base->id, head->id) != 0) {
if (dents[2] != NULL) {
/* D/F conflict:
* Remote replaces file with dir, while head change the file.
*/
seaf_debug ("%s%s: DFC, file -> file, dir\n",
basedir, head->name);
/* We use remote head commit author name as conflict
* suffix of a dir.
*/
conflict_name = merge_conflict_dirname (store_id, version,
opt,
basedir, dents[2]->name);
if (!conflict_name)
return -1;
/* Change remote dir name to conflict name in place. */
g_free (dents[2]->name);
dents[2]->name = conflict_name;
dents[2]->name_len = strlen (dents[2]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
opt->conflict = TRUE;
} else {
/* Deleted in remote and changed in head. */
seaf_debug ("%s%s: deleted in remote and changed in head\n",
basedir, head->name);
/* Keep version of remote. */
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
}
} else {
/* If base and head match, the file should not be added to
* the merge result.
*/
seaf_debug ("%s%s: file deleted in remote, unchanged in head\n",
basedir, head->name);
}
} else if (!base && !head && remote) {
if (!dents[1]) {
/* Added in remote. */
seaf_debug ("%s%s: added in remote\n", basedir, remote->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
} else if (dents[0] != NULL && strcmp(dents[0]->id, dents[1]->id) == 0) {
/* Contents in the dir is not changed.
* The dir will be deleted in merge_directories().
*/
seaf_debug ("%s%s: dir in head will be replaced by file in remote\n",
basedir, remote->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
} else {
/* D/F conflict:
* Contents of the dir is changed in head, while
* remote replace the dir with a file.
*
* Or, head adds a new dir, while remote adds a new file,
* with the same name.
*/
seaf_debug ("%s%s: DFC, dir -> dir, file\n", basedir, remote->name);
conflict_name = merge_conflict_filename(store_id, version,
opt,
basedir,
remote->name);
if (!conflict_name)
return -1;
g_free (remote->name);
remote->name = conflict_name;
remote->name_len = strlen (remote->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(remote));
opt->conflict = TRUE;
}
} else if (!base && head && !remote) {
if (!dents[2]) {
/* Added in remote. */
seaf_debug ("%s%s: added in head\n", basedir, head->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
} else if (dents[0] != NULL && strcmp(dents[0]->id, dents[2]->id) == 0) {
/* Contents in the dir is not changed.
* The dir will be deleted in merge_directories().
*/
seaf_debug ("%s%s: dir in remote will be replaced by file in head\n",
basedir, head->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
} else {
/* D/F conflict:
* Contents of the dir is changed in remote, while
* head replace the dir with a file.
*
* Or, remote adds a new dir, while head adds a new file,
* with the same name.
*/
seaf_debug ("%s%s: DFC, dir -> file, dir\n", basedir, head->name);
conflict_name = merge_conflict_dirname (store_id, version,
opt,
basedir, dents[2]->name);
if (!conflict_name)
return -1;
g_free (dents[2]->name);
dents[2]->name = conflict_name;
dents[2]->name_len = strlen (dents[2]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(head));
opt->conflict = TRUE;
}
} else if (base && !head && !remote) {
/* Don't need to add anything to dents_out. */
seaf_debug ("%s%s: deleted in head and remote\n", basedir, base->name);
}
return 0;
}
static int
merge_directories (const char *store_id, int version,
int n, SeafDirent *dents[],
const char *basedir,
GList **dents_out,
MergeOptions *opt)
{
SeafDir *dir;
SeafDir *sub_dirs[3];
char *dirname = NULL;
char *new_basedir;
int ret = 0;
int dir_mask = 0, i;
SeafDirent *merged_dent;
for (i = 0; i < n; ++i) {
if (dents[i] && S_ISDIR(dents[i]->mode))
dir_mask |= 1 << i;
}
seaf_debug ("dir_mask = %d\n", dir_mask);
if (n == 3 && opt->do_merge) {
switch (dir_mask) {
case 0:
g_return_val_if_reached (-1);
case 1:
/* head and remote are not dirs, nothing to merge. */
seaf_debug ("%s%s: no dir, no need to merge\n", basedir, dents[0]->name);
return 0;
case 2:
/* only head is dir, add to result directly, no need to merge. */
seaf_debug ("%s%s: only head is dir\n", basedir, dents[1]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(dents[1]));
return 0;
case 3:
if (strcmp (dents[0]->id, dents[1]->id) == 0) {
/* Base and head are the same, but deleted in remote. */
seaf_debug ("%s%s: dir deleted in remote\n", basedir, dents[0]->name);
return 0;
}
seaf_debug ("%s%s: dir changed in head but deleted in remote\n",
basedir, dents[1]->name);
break;
case 4:
/* only remote is dir, add to result directly, no need to merge. */
seaf_debug ("%s%s: only remote is dir\n", basedir, dents[2]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(dents[2]));
return 0;
case 5:
if (strcmp (dents[0]->id, dents[2]->id) == 0) {
/* Base and remote are the same, but deleted in head. */
seaf_debug ("%s%s: dir deleted in head\n", basedir, dents[0]->name);
return 0;
}
seaf_debug ("%s%s: dir changed in remote but deleted in head\n",
basedir, dents[2]->name);
break;
case 6:
case 7:
if (strcmp (dents[1]->id, dents[2]->id) == 0) {
/* Head and remote match. */
seaf_debug ("%s%s: dir is the same in head and remote\n",
basedir, dents[1]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(dents[1]));
return 0;
} else if (dents[0] && strcmp(dents[0]->id, dents[1]->id) == 0) {
seaf_debug ("%s%s: dir changed in remote but unchanged in head\n",
basedir, dents[1]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(dents[2]));
return 0;
} else if (dents[0] && strcmp(dents[0]->id, dents[2]->id) == 0) {
seaf_debug ("%s%s: dir changed in head but unchanged in remote\n",
basedir, dents[1]->name);
*dents_out = g_list_prepend (*dents_out, seaf_dirent_dup(dents[1]));
return 0;
}
seaf_debug ("%s%s: dir is changed in both head and remote, "
"merge recursively\n", basedir, dents[1]->name);
break;
default:
g_return_val_if_reached (-1);
}
}
memset (sub_dirs, 0, sizeof(sub_dirs[0])*n);
for (i = 0; i < n; ++i) {
if (dents[i] != NULL && S_ISDIR(dents[i]->mode)) {
dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr,
store_id, version,
dents[i]->id);
if (!dir) {
seaf_warning ("Failed to find dir %s:%s.\n", store_id, dents[i]->id);
ret = -1;
goto free_sub_dirs;
}
opt->visit_dirs++;
sub_dirs[i] = dir;
dirname = dents[i]->name;
}
}
new_basedir = g_strconcat (basedir, dirname, "/", NULL);
ret = merge_trees_recursive (store_id, version, n, sub_dirs, new_basedir, opt);
g_free (new_basedir);
if (n == 3 && opt->do_merge) {
if (dir_mask == 3 || dir_mask == 6 || dir_mask == 7) {
merged_dent = seaf_dirent_dup (dents[1]);
memcpy (merged_dent->id, opt->merged_tree_root, 40);
*dents_out = g_list_prepend (*dents_out, merged_dent);
} else if (dir_mask == 5) {
merged_dent = seaf_dirent_dup (dents[2]);
memcpy (merged_dent->id, opt->merged_tree_root, 40);
*dents_out = g_list_prepend (*dents_out, merged_dent);
}
}
free_sub_dirs:
for (i = 0; i < n; ++i)
seaf_dir_free (sub_dirs[i]);
return ret;
}
static gint
compare_dirents (gconstpointer a, gconstpointer b)
{
const SeafDirent *denta = a, *dentb = b;
return strcmp (dentb->name, denta->name);
}
static int
merge_trees_recursive (const char *store_id, int version,
int n, SeafDir *trees[],
const char *basedir,
MergeOptions *opt)
{
GList *ptrs[3];
SeafDirent *dents[3];
int i;
SeafDirent *dent;
char *first_name;
gboolean done;
int ret = 0;
SeafDir *merged_tree;
GList *merged_dents = NULL;
for (i = 0; i < n; ++i) {
if (trees[i])
ptrs[i] = trees[i]->entries;
else
ptrs[i] = NULL;
}
while (1) {
first_name = NULL;
memset (dents, 0, sizeof(dents[0])*n);
done = TRUE;
/* Find the "largest" name, assuming dirents are sorted. */
for (i = 0; i < n; ++i) {
if (ptrs[i] != NULL) {
done = FALSE;
dent = ptrs[i]->data;
if (!first_name)
first_name = dent->name;
else if (strcmp(dent->name, first_name) > 0)
first_name = dent->name;
}
}
if (done)
break;
/*
* Setup dir entries for all names that equal to first_name
*/
int n_files = 0, n_dirs = 0;
for (i = 0; i < n; ++i) {
if (ptrs[i] != NULL) {
dent = ptrs[i]->data;
if (strcmp(first_name, dent->name) == 0) {
if (S_ISREG(dent->mode))
++n_files;
else if (S_ISDIR(dent->mode))
++n_dirs;
dents[i] = dent;
ptrs[i] = ptrs[i]->next;
}
}
}
/* Merge entries of this level. */
if (n_files > 0) {
ret = merge_entries (store_id, version,
n, dents, basedir, &merged_dents, opt);
if (ret < 0)
return ret;
}
/* Recurse into sub level. */
if (n_dirs > 0) {
ret = merge_directories (store_id, version,
n, dents, basedir, &merged_dents, opt);
if (ret < 0)
return ret;
}
}
if (n == 3 && opt->do_merge) {
merged_dents = g_list_sort (merged_dents, compare_dirents);
merged_tree = seaf_dir_new (NULL, merged_dents,
dir_version_from_repo_version(version));
memcpy (opt->merged_tree_root, merged_tree->dir_id, 40);
if ((trees[1] && strcmp (trees[1]->dir_id, merged_tree->dir_id) == 0) ||
(trees[2] && strcmp (trees[2]->dir_id, merged_tree->dir_id) == 0)) {
seaf_dir_free (merged_tree);
} else {
ret = seaf_dir_save (seaf->fs_mgr, store_id, version, merged_tree);
seaf_dir_free (merged_tree);
if (ret < 0) {
seaf_warning ("Failed to save merged tree %s:%s.\n", store_id, basedir);
}
}
}
return ret;
}
int
seaf_merge_trees (const char *store_id, int version,
int n, const char *roots[], MergeOptions *opt)
{
SeafDir **trees, *root;
int i, ret;
g_return_val_if_fail (n == 2 || n == 3, -1);
trees = g_new0 (SeafDir *, n);
for (i = 0; i < n; ++i) {
root = seaf_fs_manager_get_seafdir (seaf->fs_mgr, store_id, version, roots[i]);
if (!root) {
seaf_warning ("Failed to find dir %s:%s.\n", store_id, roots[i]);
g_free (trees);
return -1;
}
trees[i] = root;
}
ret = merge_trees_recursive (store_id, version, n, trees, "", opt);
for (i = 0; i < n; ++i)
seaf_dir_free (trees[i]);
g_free (trees);
return ret;
}

View File

@ -1,34 +0,0 @@
#ifndef MERGE_NEW_H
#define MERGE_NEW_H
#include "common.h"
#include "fs-mgr.h"
struct MergeOptions;
typedef int (*MergeCallback) (const char *basedir,
SeafDirent *dirents[],
struct MergeOptions *opt);
typedef struct MergeOptions {
int n_ways; /* only 2 and 3 way merges are supported. */
MergeCallback callback;
void * data;
/* options only used in 3-way merge. */
char remote_repo_id[37];
char remote_head[41];
gboolean do_merge; /* really merge the contents
* and handle conflicts */
char merged_tree_root[41]; /* merge result */
int visit_dirs;
gboolean conflict;
} MergeOptions;
int
seaf_merge_trees (const char *store_id, int version,
int n, const char *roots[], MergeOptions *opt);
#endif

View File

@ -1,174 +1,63 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <ccnet.h>
#include "common.h"
#include "log.h"
#include "utils.h"
#include "mq-mgr.h"
#include "seafile-session.h"
#include "log.h"
typedef struct _SeafMqManagerPriv SeafMqManagerPriv;
struct _SeafMqManagerPriv {
CcnetMqclientProc *mqclient_proc;
CcnetTimer *timer;
/* keep it in memory since we always use the same message */
CcnetMessage *heartbeat_msg;
};
#define HEARTBEAT_INTERVAL 2 /* 2s */
static int heartbeat_pulse (void *vmanager);
typedef struct SeafMqManagerPriv {
// chan <-> async_queue
GHashTable *chans;
} SeafMqManagerPriv;
SeafMqManager *
seaf_mq_manager_new (SeafileSession *seaf)
seaf_mq_manager_new ()
{
CcnetClient *client = seaf->session;
SeafMqManager *mgr;
SeafMqManagerPriv *priv;
mgr = g_new0 (SeafMqManager, 1);
priv = g_new0 (SeafMqManagerPriv, 1);
mgr->seaf = seaf;
mgr->priv = priv;
priv->mqclient_proc = (CcnetMqclientProc *)
ccnet_proc_factory_create_master_processor (client->proc_factory,
"mq-client");
if (!priv->mqclient_proc) {
seaf_warning ("Failed to create mqclient proc.\n");
g_free (mgr);
g_free(priv);
return NULL;
}
SeafMqManager *mgr = g_new0 (SeafMqManager, 1);
mgr->priv = g_new0 (SeafMqManagerPriv, 1);
mgr->priv->chans = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_async_queue_unref);
return mgr;
}
static int
start_mq_client (CcnetMqclientProc *mqclient)
{
if (ccnet_processor_startl ((CcnetProcessor *)mqclient, NULL) < 0) {
ccnet_processor_done ((CcnetProcessor *)mqclient, FALSE);
seaf_warning ("Failed to start mqclient proc\n");
return -1;
}
seaf_message ("[mq client] mq cilent is started\n");
return 0;
}
int
void
seaf_mq_manager_init (SeafMqManager *mgr)
{
SeafMqManagerPriv *priv = mgr->priv;
if (start_mq_client(priv->mqclient_proc) < 0)
return -1;
return 0;
}
int
seaf_mq_manager_start (SeafMqManager *mgr)
{
SeafMqManagerPriv *priv = mgr->priv;
priv->timer = ccnet_timer_new (heartbeat_pulse, mgr,
HEARTBEAT_INTERVAL * 1000);
return 0;
}
static inline CcnetMessage *
create_message (SeafMqManager *mgr, const char *app, const char *body, int flags)
{
CcnetClient *client = mgr->seaf->session;
CcnetMessage *msg;
char *from = client->base.id;
char *to = client->base.id;
msg = ccnet_message_new (from, to, app, body, flags);
return msg;
g_hash_table_replace (mgr->priv->chans, g_strdup (SEAFILE_NOTIFY_CHAN),
g_async_queue_new_full ((GDestroyNotify)json_decref));
}
void
seaf_mq_manager_set_heartbeat_name (SeafMqManager *mgr, const char *app)
seaf_mq_manager_publish_notification (SeafMqManager *mgr, const char *type, const char *content)
{
if (!app)
const char *chan = SEAFILE_NOTIFY_CHAN;
GAsyncQueue *async_queue = g_hash_table_lookup (mgr->priv->chans, chan);
if (!async_queue) {
seaf_warning ("Unkonwn message channel %s.\n", chan);
return;
}
SeafMqManagerPriv *priv = mgr->priv;
if (priv->heartbeat_msg)
if (!type || !content) {
seaf_warning ("type and content should not be NULL.\n");
return;
}
seaf_message ("[mq mgr] publish to heartbeat mq: %s\n", app);
json_t *msg = json_object ();
json_object_set_new (msg, "type", json_string(type));
json_object_set_new (msg, "content", json_string(content));
priv->heartbeat_msg =
create_message (seaf->mq_mgr, app, "heartbeat", 0);
g_async_queue_push (async_queue, msg);
}
/* Wrap around ccnet_message_new since all messages we use are local. */
static inline void
_send_message (SeafMqManager *mgr, CcnetMessage *msg)
json_t *
seaf_mq_manager_pop_message (SeafMqManager *mgr)
{
CcnetMqclientProc *mqclient_proc = mgr->priv->mqclient_proc;
ccnet_mqclient_proc_put_message (mqclient_proc, msg);
}
void
seaf_mq_manager_publish_message (SeafMqManager *mgr,
CcnetMessage *msg)
{
_send_message (mgr, msg);
}
void
seaf_mq_manager_publish_message_full (SeafMqManager *mgr,
const char *app,
const char *body,
int flags)
{
CcnetMessage *msg = create_message (mgr, app, body, flags);
_send_message (mgr, msg);
ccnet_message_free (msg);
}
void
seaf_mq_manager_publish_notification (SeafMqManager *mgr,
const char *type,
const char *content)
{
static const char *app = "seafile.notification";
GString *buf = g_string_new(NULL);
g_string_append_printf (buf, "%s\n%s", type, content);
CcnetMessage *msg = create_message (mgr, app, buf->str, 0);
_send_message (mgr, msg);
g_string_free (buf, TRUE);
ccnet_message_free (msg);
}
void
seaf_mq_manager_publish_event (SeafMqManager *mgr, const char *content)
{
static const char *app = "seaf_server.event";
CcnetMessage *msg = create_message (mgr, app, content, 0);
_send_message (mgr, msg);
ccnet_message_free (msg);
}
static int
heartbeat_pulse (void *vmanager)
{
SeafMqManager *mgr = vmanager;
_send_message (mgr, mgr->priv->heartbeat_msg);
return TRUE;
const char *chan = SEAFILE_NOTIFY_CHAN;
GAsyncQueue *async_queue = g_hash_table_lookup (mgr->priv->chans, chan);
if (!async_queue) {
seaf_warning ("Unkonwn message channel %s.\n", chan);
return NULL;
}
return g_async_queue_try_pop (async_queue);
}

View File

@ -1,61 +1,24 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Mq-manager is responsible for:
*
* - Publishing heartbeat messages every HEARTBEAT_INTERVAL senconds to
* indicate it's alive. If seafile-applet doesn't get the message, it would
* check and try to restart seaf-daemon.
*
* - Provide API for other modules to publish their messages.
*
* Currently we publish these types of messages:
*
* - seafile.heartbeat <>
* - seafile.transfer <start | stop >
* - seafile.repo_sync_done <repo-name>
* - seafile.promt_create_repo <worktree>
* - seafile.repo_created <repo-name>
*
* And subscribe to no messages.
*/
#ifndef SEAF_MQ_MANAGER_H
#define SEAF_MQ_MANAGER_H
struct _CcnetMessage;
#define SEAFILE_NOTIFY_CHAN "seafile.notification"
typedef struct _SeafMqManager SeafMqManager;
struct SeafMqManagerPriv;
struct _SeafMqManager {
struct _SeafileSession *seaf;
struct _SeafMqManagerPriv *priv;
};
typedef struct SeafMqManager {
struct SeafMqManagerPriv *priv;
} SeafMqManager;
SeafMqManager *seaf_mq_manager_new (struct _SeafileSession *seaf);
void seaf_mq_manager_set_heartbeat_name (SeafMqManager *mgr, const char *app);
int seaf_mq_manager_init (SeafMqManager *mgr);
int seaf_mq_manager_start (SeafMqManager *mgr);
void seaf_mq_manager_publish_message (SeafMqManager *mgr,
struct _CcnetMessage *msg);
SeafMqManager *
seaf_mq_manager_new ();
void
seaf_mq_manager_publish_message_full (SeafMqManager *mgr,
const char *app,
const char *body,
int flags);
seaf_mq_manager_init (SeafMqManager *mgr);
void
seaf_mq_manager_publish_notification (SeafMqManager *mgr,
const char *type,
const char *content);
seaf_mq_manager_publish_notification (SeafMqManager *mgr, const char *type, const char *content);
void
seaf_mq_manager_publish_event (SeafMqManager *mgr, const char *content);
json_t *
seaf_mq_manager_pop_message (SeafMqManager *mgr);
#endif

View File

@ -1,148 +0,0 @@
#include "common.h"
#include "log.h"
#include "obj-backend.h"
#ifdef RIAK_BACKEND
#include "riak-client.h"
#include <pthread.h>
typedef struct RiakPriv {
const char *host;
const char *port;
const char *bucket;
int n_write;
GQueue *conn_pool;
pthread_mutex_t lock;
} RiakPriv;
static SeafRiakClient *
get_connection (RiakPriv *priv)
{
SeafRiakClient *connection;
pthread_mutex_lock (&priv->lock);
connection = g_queue_pop_head (priv->conn_pool);
if (!connection)
connection = seaf_riak_client_new (priv->host, priv->port);
pthread_mutex_unlock (&priv->lock);
return connection;
}
static void
return_connection (RiakPriv *priv, SeafRiakClient *connection)
{
pthread_mutex_lock (&priv->lock);
g_queue_push_tail (priv->conn_pool, connection);
pthread_mutex_unlock (&priv->lock);
}
static int
obj_backend_riak_read (ObjBackend *bend,
const char *obj_id,
void **data,
int *len)
{
SeafRiakClient *conn = get_connection (bend->priv);
RiakPriv *priv = bend->priv;
int ret;
ret = seaf_riak_client_get (conn, priv->bucket, obj_id, data, len);
return_connection (priv, conn);
return ret;
}
static int
obj_backend_riak_write (ObjBackend *bend,
const char *obj_id,
void *data,
int len)
{
SeafRiakClient *conn = get_connection (bend->priv);
RiakPriv *priv = bend->priv;
int ret;
ret = seaf_riak_client_put (conn, priv->bucket, obj_id, data, len,
priv->n_write);
return_connection (priv, conn);
return ret;
}
static gboolean
obj_backend_riak_exists (ObjBackend *bend,
const char *obj_id)
{
SeafRiakClient *conn = get_connection (bend->priv);
RiakPriv *priv = bend->priv;
gboolean ret;
ret = seaf_riak_client_query (conn, priv->bucket, obj_id);
return_connection (priv, conn);
return ret;
}
static void
obj_backend_riak_delete (ObjBackend *bend,
const char *obj_id)
{
SeafRiakClient *conn = get_connection (bend->priv);
RiakPriv *priv = bend->priv;
seaf_riak_client_delete (conn, priv->bucket, obj_id, priv->n_write);
return_connection (priv, conn);
}
ObjBackend *
obj_backend_riak_new (const char *host,
const char *port,
const char *bucket,
const char *write_policy)
{
ObjBackend *bend;
RiakPriv *priv;
bend = g_new0(ObjBackend, 1);
priv = g_new0(RiakPriv, 1);
bend->priv = priv;
priv->host = g_strdup (host);
priv->port = g_strdup (port);
priv->bucket = g_strdup (bucket);
if (strcmp (write_policy, "quorum") == 0)
priv->n_write = RIAK_QUORUM;
else if (strcmp (write_policy, "all") == 0)
priv->n_write = RIAK_ALL;
else
g_return_val_if_reached (NULL);
priv->conn_pool = g_queue_new ();
pthread_mutex_init (&priv->lock, NULL);
bend->read = obj_backend_riak_read;
bend->write = obj_backend_riak_write;
bend->exists = obj_backend_riak_exists;
bend->delete = obj_backend_riak_delete;
return bend;
}
#else
ObjBackend *
obj_backend_riak_new (const char *host,
const char *port,
const char *bucket,
const char *write_policy)
{
seaf_warning ("Riak backend is not enabled.\n");
return NULL;
}
#endif /* RIAK_BACKEND */

View File

@ -2,7 +2,6 @@
#include "log.h"
#include <ccnet/cevent.h>
#include "seafile-session.h"
#include "utils.h"
@ -10,65 +9,11 @@
#include "obj-backend.h"
#include "obj-store.h"
#define MAX_READER_THREADS 2
#define MAX_WRITER_THREADS 2
#define MAX_STAT_THREADS 2
typedef struct AsyncTask {
guint32 rw_id;
char obj_id[41];
void *data;
int len;
gboolean need_sync;
gboolean success;
} AsyncTask;
typedef struct OSCallbackStruct {
char repo_id[37];
int version;
OSAsyncCallback cb;
void *cb_data;
} OSCallbackStruct;
struct SeafObjStore {
ObjBackend *bend;
CEventManager *ev_mgr;
/* For async read. */
guint32 next_rd_id;
GThreadPool *read_tpool;
GHashTable *readers;
guint32 read_ev_id;
/* For async write. */
guint32 next_wr_id;
GThreadPool *write_tpool;
GHashTable *writers;
guint32 write_ev_id;
/* For async stat. */
guint32 next_st_id;
GThreadPool *stat_tpool;
GHashTable *stats;
guint32 stat_ev_id;
};
typedef struct SeafObjStore SeafObjStore;
static void
reader_thread (void *data, void *user_data);
static void
writer_thread (void *data, void *user_data);
static void
stat_thread (void *data, void *user_data);
static void
on_read_done (CEvent *event, void *data);
static void
on_write_done (CEvent *event, void *data);
static void
on_stat_done (CEvent *event, void *data);
extern ObjBackend *
obj_backend_fs_new (const char *seaf_dir, const char *obj_type);
@ -90,75 +35,11 @@ seaf_obj_store_new (SeafileSession *seaf, const char *obj_type)
return store;
}
static int
async_init (SeafObjStore *obj_store, CEventManager *ev_mgr)
{
GError *error = NULL;
obj_store->ev_mgr = ev_mgr;
obj_store->read_tpool = g_thread_pool_new (reader_thread,
obj_store,
MAX_READER_THREADS,
FALSE,
&error);
if (error) {
seaf_warning ("Failed to start reader thread pool: %s.\n", error->message);
g_clear_error (&error);
return -1;
}
obj_store->readers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, g_free);
obj_store->read_ev_id = cevent_manager_register (ev_mgr,
on_read_done,
obj_store);
obj_store->write_tpool = g_thread_pool_new (writer_thread,
obj_store,
MAX_WRITER_THREADS,
FALSE,
&error);
if (error) {
seaf_warning ("Failed to start writer thread pool: %s.\n", error->message);
g_clear_error (&error);
return -1;
}
obj_store->writers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, g_free);
obj_store->write_ev_id = cevent_manager_register (ev_mgr,
on_write_done,
obj_store);
obj_store->stat_tpool = g_thread_pool_new (stat_thread,
obj_store,
MAX_STAT_THREADS,
FALSE,
&error);
if (error) {
seaf_warning ("Failed to start statr thread pool: %s.\n", error->message);
g_clear_error (&error);
return -1;
}
obj_store->stats = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, g_free);
obj_store->stat_ev_id = cevent_manager_register (ev_mgr,
on_stat_done,
obj_store);
return 0;
}
int
seaf_obj_store_init (SeafObjStore *obj_store,
gboolean enable_async,
CEventManager *ev_mgr)
{
if (enable_async && async_init (obj_store, ev_mgr) < 0)
return -1;
return 0;
}
@ -255,290 +136,6 @@ seaf_obj_store_copy_obj (struct SeafObjStore *obj_store,
return bend->copy (bend, src_repo_id, src_version, dst_repo_id, dst_version, obj_id);
}
static void
reader_thread (void *data, void *user_data)
{
AsyncTask *task = data;
SeafObjStore *obj_store = user_data;
ObjBackend *bend = obj_store->bend;
OSCallbackStruct *callback;
callback = g_hash_table_lookup (obj_store->readers,
(gpointer)(long)(task->rw_id));
if (callback) {
task->success = TRUE;
if (bend->read (bend, callback->repo_id, callback->version,
task->obj_id, &task->data, &task->len) < 0)
task->success = FALSE;
}
cevent_manager_add_event (obj_store->ev_mgr, obj_store->read_ev_id,
task);
}
static void
stat_thread (void *data, void *user_data)
{
AsyncTask *task = data;
SeafObjStore *obj_store = user_data;
ObjBackend *bend = obj_store->bend;
OSCallbackStruct *callback;
callback = g_hash_table_lookup (obj_store->stats,
(gpointer)(long)(task->rw_id));
if (callback) {
task->success = TRUE;
if (!bend->exists (bend, callback->repo_id, callback->version, task->obj_id))
task->success = FALSE;
}
cevent_manager_add_event (obj_store->ev_mgr, obj_store->stat_ev_id,
task);
}
static void
writer_thread (void *data, void *user_data)
{
AsyncTask *task = data;
SeafObjStore *obj_store = user_data;
ObjBackend *bend = obj_store->bend;
OSCallbackStruct *callback;
callback = g_hash_table_lookup (obj_store->writers,
(gpointer)(long)(task->rw_id));
if (callback) {
task->success = TRUE;
if (bend->write (bend, callback->repo_id, callback->version,
task->obj_id, task->data, task->len, task->need_sync) < 0)
task->success = FALSE;
}
cevent_manager_add_event (obj_store->ev_mgr, obj_store->write_ev_id,
task);
}
static void
on_read_done (CEvent *event, void *user_data)
{
AsyncTask *task = event->data;
SeafObjStore *obj_store = user_data;
OSCallbackStruct *callback;
OSAsyncResult res;
callback = g_hash_table_lookup (obj_store->readers,
(gpointer)(long)(task->rw_id));
if (callback) {
res.rw_id = task->rw_id;
memcpy (res.obj_id, task->obj_id, 41);
res.data = task->data;
res.len = task->len;
res.success = task->success;
callback->cb (&res, callback->cb_data);
}
g_free (task->data);
g_free (task);
}
static void
on_stat_done (CEvent *event, void *user_data)
{
AsyncTask *task = event->data;
SeafObjStore *obj_store = user_data;
OSCallbackStruct *callback;
OSAsyncResult res;
callback = g_hash_table_lookup (obj_store->stats,
(gpointer)(long)(task->rw_id));
if (callback) {
res.rw_id = task->rw_id;
memcpy (res.obj_id, task->obj_id, 41);
res.data = NULL;
res.len = task->len;
res.success = task->success;
callback->cb (&res, callback->cb_data);
}
g_free (task->data);
g_free (task);
}
static void
on_write_done (CEvent *event, void *user_data)
{
AsyncTask *task = event->data;
SeafObjStore *obj_store = user_data;
OSCallbackStruct *callback;
OSAsyncResult res;
callback = g_hash_table_lookup (obj_store->writers,
(gpointer)(long)(task->rw_id));
if (callback) {
res.rw_id = task->rw_id;
memcpy (res.obj_id, task->obj_id, 41);
res.data = task->data;
res.len = task->len;
res.success = task->success;
callback->cb (&res, callback->cb_data);
}
g_free (task->data);
g_free (task);
}
guint32
seaf_obj_store_register_async_read (struct SeafObjStore *obj_store,
const char *repo_id,
int version,
OSAsyncCallback callback,
void *cb_data)
{
guint32 id = obj_store->next_rd_id++;
OSCallbackStruct *cb_struct = g_new0 (OSCallbackStruct, 1);
memcpy (cb_struct->repo_id, repo_id, 36);
cb_struct->version = version;
cb_struct->cb = callback;
cb_struct->cb_data = cb_data;
g_hash_table_insert (obj_store->readers, (gpointer)(long)id, cb_struct);
return id;
}
void
seaf_obj_store_unregister_async_read (struct SeafObjStore *obj_store,
guint32 reader_id)
{
g_hash_table_remove (obj_store->readers, (gpointer)(long)reader_id);
}
int
seaf_obj_store_async_read (struct SeafObjStore *obj_store,
guint32 reader_id,
const char *obj_id)
{
AsyncTask *task = g_new0 (AsyncTask, 1);
GError *error = NULL;
task->rw_id = reader_id;
memcpy (task->obj_id, obj_id, 41);
g_thread_pool_push (obj_store->read_tpool, task, &error);
if (error) {
seaf_warning ("Failed to start aysnc read of %s.\n", obj_id);
return -1;
}
return 0;
}
guint32
seaf_obj_store_register_async_stat (struct SeafObjStore *obj_store,
const char *repo_id,
int version,
OSAsyncCallback callback,
void *cb_data)
{
guint32 id = obj_store->next_st_id++;
OSCallbackStruct *cb_struct = g_new0 (OSCallbackStruct, 1);
memcpy (cb_struct->repo_id, repo_id, 36);
cb_struct->version = version;
cb_struct->cb = callback;
cb_struct->cb_data = cb_data;
g_hash_table_insert (obj_store->stats, (gpointer)(long)id, cb_struct);
return id;
}
void
seaf_obj_store_unregister_async_stat (struct SeafObjStore *obj_store,
guint32 stat_id)
{
g_hash_table_remove (obj_store->stats, (gpointer)(long)stat_id);
}
int
seaf_obj_store_async_stat (struct SeafObjStore *obj_store,
guint32 stat_id,
const char *obj_id)
{
AsyncTask *task = g_new0 (AsyncTask, 1);
GError *error = NULL;
task->rw_id = stat_id;
memcpy (task->obj_id, obj_id, 41);
g_thread_pool_push (obj_store->stat_tpool, task, &error);
if (error) {
seaf_warning ("Failed to start aysnc stat of %s.\n", obj_id);
return -1;
}
return 0;
}
guint32
seaf_obj_store_register_async_write (struct SeafObjStore *obj_store,
const char *repo_id,
int version,
OSAsyncCallback callback,
void *cb_data)
{
guint32 id = obj_store->next_rd_id++;
OSCallbackStruct *cb_struct = g_new0 (OSCallbackStruct, 1);
memcpy (cb_struct->repo_id, repo_id, 36);
cb_struct->version = version;
cb_struct->cb = callback;
cb_struct->cb_data = cb_data;
g_hash_table_insert (obj_store->writers, (gpointer)(long)id, cb_struct);
return id;
}
void
seaf_obj_store_unregister_async_write (struct SeafObjStore *obj_store,
guint32 writer_id)
{
g_hash_table_remove (obj_store->writers, (gpointer)(long)writer_id);
}
int
seaf_obj_store_async_write (struct SeafObjStore *obj_store,
guint32 writer_id,
const char *obj_id,
const void *obj_data,
int data_len,
gboolean need_sync)
{
AsyncTask *task = g_new0 (AsyncTask, 1);
GError *error = NULL;
task->rw_id = writer_id;
memcpy (task->obj_id, obj_id, 41);
task->data = g_memdup (obj_data, data_len);
task->len = data_len;
task->need_sync = need_sync;
g_thread_pool_push (obj_store->write_tpool, task, &error);
if (error) {
seaf_warning ("Failed to start aysnc write of %s.\n", obj_id);
return -1;
}
return 0;
}
int
seaf_obj_store_remove_store (struct SeafObjStore *obj_store,
const char *store_id)

View File

@ -67,73 +67,6 @@ seaf_obj_store_copy_obj (struct SeafObjStore *obj_store,
int dst_version,
const char *obj_id);
/* Asynchronous I/O interface. */
typedef struct OSAsyncResult {
guint32 rw_id;
char obj_id[41];
/* @data is owned by obj-store, don't free it. */
void *data;
int len;
gboolean success;
} OSAsyncResult;
typedef void (*OSAsyncCallback) (OSAsyncResult *res, void *cb_data);
/* Async read */
guint32
seaf_obj_store_register_async_read (struct SeafObjStore *obj_store,
const char *repo_id,
int version,
OSAsyncCallback callback,
void *cb_data);
void
seaf_obj_store_unregister_async_read (struct SeafObjStore *obj_store,
guint32 reader_id);
int
seaf_obj_store_async_read (struct SeafObjStore *obj_store,
guint32 reader_id,
const char *obj_id);
/* Async write */
guint32
seaf_obj_store_register_async_write (struct SeafObjStore *obj_store,
const char *repo_id,
int version,
OSAsyncCallback callback,
void *cb_data);
void
seaf_obj_store_unregister_async_write (struct SeafObjStore *obj_store,
guint32 writer_id);
int
seaf_obj_store_async_write (struct SeafObjStore *obj_store,
guint32 writer_id,
const char *obj_id,
const void *obj_data,
int data_len,
gboolean need_sync);
/* Async stat */
guint32
seaf_obj_store_register_async_stat (struct SeafObjStore *obj_store,
const char *repo_id,
int version,
OSAsyncCallback callback,
void *cb_data);
void
seaf_obj_store_unregister_async_stat (struct SeafObjStore *obj_store,
guint32 stat_id);
int
seaf_obj_store_async_stat (struct SeafObjStore *obj_store,
guint32 stat_id,
const char *obj_id);
int
seaf_obj_store_remove_store (struct SeafObjStore *obj_store,
const char *store_id);

View File

@ -1,55 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include "object-list.h"
ObjectList *
object_list_new ()
{
ObjectList *ol = g_new0 (ObjectList, 1);
ol->obj_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
ol->obj_ids = g_ptr_array_new_with_free_func (g_free);
return ol;
}
void
object_list_free (ObjectList *ol)
{
if (ol->obj_hash)
g_hash_table_destroy (ol->obj_hash);
g_ptr_array_free (ol->obj_ids, TRUE);
g_free (ol);
}
void
object_list_serialize (ObjectList *ol, uint8_t **buffer, uint32_t *len)
{
uint32_t i;
uint32_t offset = 0;
uint8_t *buf;
int ollen = object_list_length(ol);
buf = g_new (uint8_t, 41 * ollen);
for (i = 0; i < ollen; ++i) {
memcpy (&buf[offset], g_ptr_array_index(ol->obj_ids, i), 41);
offset += 41;
}
*buffer = buf;
*len = 41 * ollen;
}
gboolean
object_list_insert (ObjectList *ol, const char *object_id)
{
if (g_hash_table_lookup (ol->obj_hash, object_id))
return FALSE;
char *id = g_strdup(object_id);
g_hash_table_replace (ol->obj_hash, id, id);
g_ptr_array_add (ol->obj_ids, id);
return TRUE;
}

View File

@ -1,42 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef OBJECT_LIST_H
#define OBJECT_LIST_H
#include <glib.h>
typedef struct {
GHashTable *obj_hash;
GPtrArray *obj_ids;
} ObjectList;
ObjectList *
object_list_new ();
void
object_list_free (ObjectList *ol);
void
object_list_serialize (ObjectList *ol, uint8_t **buffer, uint32_t *len);
/**
* Add object to ObjectList.
* Return FALSE if it is already in the list, TRUE otherwise.
*/
gboolean
object_list_insert (ObjectList *ol, const char *object_id);
inline static gboolean
object_list_exists (ObjectList *ol, const char *object_id)
{
return (g_hash_table_lookup(ol->obj_hash, object_id) != NULL);
}
inline static int
object_list_length (ObjectList *ol)
{
return ol->obj_ids->len;
}
#endif

View File

@ -1,52 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef OBJECTTX_COMMON_H
#define OBJECTTX_COMMON_H
#define SC_GET_OBJECT "301"
#define SS_GET_OBJECT "Get Object"
#define SC_OBJECT "302"
#define SS_OBJECT "Object"
#define SC_END "303"
#define SS_END "END"
#define SC_COMMIT_IDS "304"
#define SS_COMMIT_IDS "Commit IDs"
#define SC_ACK "305"
#define SS_ACK "Ack"
#define SC_OBJ_SEG "306"
#define SS_OBJ_SEG "Object Segment"
#define SC_OBJ_SEG_END "307"
#define SS_OBJ_SEG_END "Object Segment End"
#define SC_OBJ_LIST_SEG "308"
#define SS_OBJ_LIST_SEG "Object List Segment"
#define SC_OBJ_LIST_SEG_END "309"
#define SS_OBJ_LIST_SEG_END "Object List Segment End"
#define SC_NOT_FOUND "401"
#define SS_NOT_FOUND "Object not found"
#define SC_BAD_OL "402"
#define SS_BAD_OL "Bad Object List"
#define SC_BAD_OBJECT "403"
#define SS_BAD_OBJECT "Bad Object"
#define SC_ACCESS_DENIED "410"
#define SS_ACCESS_DENIED "Access denied"
/* for fs transfer */
#define SC_ROOT "304"
#define SS_ROOT "FS Root"
#define SC_ROOT_END "305"
#define SS_ROOT_END "FS Root End"
/* max fs object segment size */
#define MAX_OBJ_SEG_SIZE 64000
typedef struct {
char id[41];
uint8_t object[0];
} __attribute__((__packed__)) ObjectPack;
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
#ifndef SEAF_DB_H
#define SEAF_DB_H
enum {
SEAF_DB_TYPE_SQLITE,
SEAF_DB_TYPE_MYSQL,
SEAF_DB_TYPE_PGSQL,
};
typedef struct SeafDB SeafDB;
typedef struct SeafDBRow SeafDBRow;
typedef struct SeafDBTrans SeafDBTrans;
typedef gboolean (*SeafDBRowFunc) (SeafDBRow *, void *);
SeafDB *
seaf_db_new_mysql (const char *host,
const char *port,
const char *user,
const char *passwd,
const char *db,
const char *unix_socket,
gboolean use_ssl,
const char *charset,
int max_connections);
SeafDB *
seaf_db_new_pgsql (const char *host,
const char *user,
const char *passwd,
const char *db_name,
const char *unix_socket);
SeafDB *
seaf_db_new_sqlite (const char *db_path, int max_connections);
void
seaf_db_free (SeafDB *db);
int
seaf_db_type (SeafDB *db);
int
seaf_db_query (SeafDB *db, const char *sql);
gboolean
seaf_db_check_for_existence (SeafDB *db, const char *sql, gboolean *db_err);
int
seaf_db_foreach_selected_row (SeafDB *db, const char *sql,
SeafDBRowFunc callback, void *data);
const char *
seaf_db_row_get_column_text (SeafDBRow *row, guint32 idx);
int
seaf_db_row_get_column_int (SeafDBRow *row, guint32 idx);
gint64
seaf_db_row_get_column_int64 (SeafDBRow *row, guint32 idx);
int
seaf_db_get_int (SeafDB *db, const char *sql);
gint64
seaf_db_get_int64 (SeafDB *db, const char *sql);
char *
seaf_db_get_string (SeafDB *db, const char *sql);
/* Transaction related */
SeafDBTrans *
seaf_db_begin_transaction (SeafDB *db);
void
seaf_db_trans_close (SeafDBTrans *trans);
int
seaf_db_commit (SeafDBTrans *trans);
int
seaf_db_rollback (SeafDBTrans *trans);
int
seaf_db_trans_query (SeafDBTrans *trans, const char *sql, int n, ...);
gboolean
seaf_db_trans_check_for_existence (SeafDBTrans *trans,
const char *sql,
gboolean *db_err,
int n, ...);
int
seaf_db_trans_foreach_selected_row (SeafDBTrans *trans, const char *sql,
SeafDBRowFunc callback, void *data,
int n, ...);
/* Escape a string contant by doubling '\" characters.
*/
char *
seaf_db_escape_string (SeafDB *db, const char *from);
gboolean
pgsql_index_exists (SeafDB *db, const char *index_name);
/* Prepared Statements */
int
seaf_db_statement_query (SeafDB *db, const char *sql, int n, ...);
gboolean
seaf_db_statement_exists (SeafDB *db, const char *sql, gboolean *db_err, int n, ...);
int
seaf_db_statement_foreach_row (SeafDB *db, const char *sql,
SeafDBRowFunc callback, void *data,
int n, ...);
int
seaf_db_statement_get_int (SeafDB *db, const char *sql, int n, ...);
gint64
seaf_db_statement_get_int64 (SeafDB *db, const char *sql, int n, ...);
char *
seaf_db_statement_get_string (SeafDB *db, const char *sql, int n, ...);
#endif

View File

@ -1,135 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include "log.h"
#include "seafile-session.h"
#include "fs-mgr.h"
#include "seaf-tree-walk.h"
#include "utils.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
void
fill_tree_descriptor(const char *repo_id, int version,
struct tree_desc *desc, const char *root_id)
{
SeafDir *dir;
if (!root_id) {
desc->tree = NULL;
return;
}
dir = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr,
repo_id,
version,
root_id);
if (!dir) {
seaf_warning ("Failed to fill tree descriptor with %s.\n", root_id);
desc->tree = NULL;
}
desc->tree = dir;
}
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
{
int len = n->pathlen;
int pathlen = info->pathlen;
path[pathlen + len] = 0;
for (;;) {
memcpy(path + pathlen, n->path, len);
if (!pathlen)
break;
path[--pathlen] = '/';
n = &info->name;
len = n->pathlen;
info = info->prev;
pathlen -= len;
}
return path;
}
int
traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
{
struct name_entry *entries = g_new0 (struct name_entry, n);
GList **ptrs = g_new0 (GList *, n);
int i;
SeafDirent *dent;
char *first_name;
gboolean done;
unsigned long mask = 0, dirmask = 0;
int error = 0, ret;
for (i = 0; i < n; ++i) {
if (t[i].tree)
ptrs[i] = t[i].tree->entries;
else
ptrs[i] = NULL;
}
while (1) {
first_name = NULL;
mask = dirmask = 0;
memset (entries, 0, sizeof(entries[0])*n);
done = TRUE;
/* Find the "largest" name, assuming dirents are sorted. */
for (i = 0; i < n; ++i) {
if (ptrs[i] != NULL) {
done = FALSE;
dent = ptrs[i]->data;
if (!first_name)
first_name = dent->name;
else if (strcmp(dent->name, first_name) > 0)
first_name = dent->name;
}
}
if (done)
break;
/*
* Setup name entries for all names that equals first_name
*/
for (i = 0; i < n; ++i) {
if (ptrs[i] != NULL) {
dent = ptrs[i]->data;
if (strcmp(first_name, dent->name) == 0) {
mask |= 1 << i;
/* We treat empty dirs as a file. */
if (S_ISDIR(dent->mode) &&
memcmp (dent->id, EMPTY_SHA1, 40) != 0)
dirmask |= 1 << i;
hex_to_rawdata (dent->id, entries[i].sha1, 20);
entries[i].path = dent->name;
entries[i].pathlen = dent->name_len;
entries[i].mode = dent->mode;
entries[i].mtime = dent->mtime;
if (S_ISREG(dent->mode)) {
entries[i].modifier = dent->modifier;
}
ptrs[i] = ptrs[i]->next;
}
}
}
ret = info->fn (n, mask, dirmask, entries, info);
if (ret < 0) {
error = ret;
}
}
g_free (entries);
g_free (ptrs);
return error;
}

View File

@ -1,51 +0,0 @@
#ifndef SEAF_TREE_WALK_H
#define SEAF_TREE_WALK_H
#include "fs-mgr.h"
struct name_entry {
unsigned char sha1[20];
const char *path;
int pathlen;
unsigned int mode;
char *modifier;
guint64 mtime;
};
struct tree_desc {
SeafDir *tree;
};
inline static void tree_desc_free (struct tree_desc *t)
{
if (t->tree)
seaf_dir_free (t->tree);
}
struct traverse_info;
typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *);
struct traverse_info {
struct traverse_info *prev;
struct name_entry name;
int pathlen;
unsigned long conflicts;
traverse_callback_t fn;
void *data;
int show_all_errors;
};
void fill_tree_descriptor(const char *repo_id, int version,
struct tree_desc *desc, const char *root_id);
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info);
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n);
static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
{
return info->pathlen + n->pathlen;
}
#endif

View File

@ -1,201 +0,0 @@
#include "common.h"
#include "log.h"
#include "seafile-session.h"
#include "seaf-utils.h"
#include "seaf-db.h"
#include <stdlib.h>
#include <string.h>
char *
seafile_session_get_tmp_file_path (SeafileSession *session,
const char *basename,
char path[])
{
int path_len;
path_len = strlen (session->tmp_file_dir);
memcpy (path, session->tmp_file_dir, path_len + 1);
path[path_len] = '/';
strcpy (path + path_len + 1, basename);
return path;
}
#ifdef SEAFILE_SERVER
#define SQLITE_DB_NAME "seafile.db"
#define DEFAULT_MAX_CONNECTIONS 100
static int
sqlite_db_start (SeafileSession *session)
{
char *db_path;
int max_connections = 0;
max_connections = g_key_file_get_integer (session->config,
"database", "max_connections",
NULL);
if (max_connections <= 0)
max_connections = DEFAULT_MAX_CONNECTIONS;
db_path = g_build_filename (session->seaf_dir, SQLITE_DB_NAME, NULL);
session->db = seaf_db_new_sqlite (db_path, max_connections);
if (!session->db) {
seaf_warning ("Failed to start sqlite db.\n");
return -1;
}
return 0;
}
#define MYSQL_DEFAULT_PORT "3306"
static int
mysql_db_start (SeafileSession *session)
{
char *host, *port, *user, *passwd, *db, *unix_socket, *charset;
gboolean use_ssl = FALSE;
int max_connections = 0;
GError *error = NULL;
host = g_key_file_get_string (session->config, "database", "host", &error);
if (!host) {
seaf_warning ("DB host not set in config.\n");
return -1;
}
port = g_key_file_get_string (session->config, "database", "port", &error);
if (!port) {
port = g_strdup(MYSQL_DEFAULT_PORT);
}
user = g_key_file_get_string (session->config, "database", "user", &error);
if (!user) {
seaf_warning ("DB user not set in config.\n");
return -1;
}
passwd = g_key_file_get_string (session->config, "database", "password", &error);
if (!passwd) {
seaf_warning ("DB passwd not set in config.\n");
return -1;
}
db = g_key_file_get_string (session->config, "database", "db_name", &error);
if (!db) {
seaf_warning ("DB name not set in config.\n");
return -1;
}
unix_socket = g_key_file_get_string (session->config,
"database", "unix_socket", NULL);
use_ssl = g_key_file_get_boolean (session->config,
"database", "use_ssl", NULL);
charset = g_key_file_get_string (session->config,
"database", "connection_charset", NULL);
max_connections = g_key_file_get_integer (session->config,
"database", "max_connections",
NULL);
if (max_connections <= 0)
max_connections = DEFAULT_MAX_CONNECTIONS;
session->db = seaf_db_new_mysql (host, port, user, passwd, db, unix_socket, use_ssl, charset, max_connections);
if (!session->db) {
seaf_warning ("Failed to start mysql db.\n");
return -1;
}
g_free (host);
g_free (port);
g_free (user);
g_free (passwd);
g_free (db);
g_free (unix_socket);
g_free (charset);
if (error)
g_clear_error (&error);
return 0;
}
static int
pgsql_db_start (SeafileSession *session)
{
char *host, *user, *passwd, *db, *unix_socket;
GError *error = NULL;
host = g_key_file_get_string (session->config, "database", "host", &error);
if (!host) {
seaf_warning ("DB host not set in config.\n");
return -1;
}
user = g_key_file_get_string (session->config, "database", "user", &error);
if (!user) {
seaf_warning ("DB user not set in config.\n");
return -1;
}
passwd = g_key_file_get_string (session->config, "database", "password", &error);
if (!passwd) {
seaf_warning ("DB passwd not set in config.\n");
return -1;
}
db = g_key_file_get_string (session->config, "database", "db_name", &error);
if (!db) {
seaf_warning ("DB name not set in config.\n");
return -1;
}
unix_socket = g_key_file_get_string (session->config,
"database", "unix_socket", &error);
session->db = seaf_db_new_pgsql (host, user, passwd, db, unix_socket);
if (!session->db) {
seaf_warning ("Failed to start pgsql db.\n");
return -1;
}
g_free (host);
g_free (user);
g_free (passwd);
g_free (db);
g_free (unix_socket);
return 0;
}
int
load_database_config (SeafileSession *session)
{
char *type;
GError *error = NULL;
int ret = 0;
type = g_key_file_get_string (session->config, "database", "type", &error);
/* Default to use sqlite if not set. */
if (!type || strcasecmp (type, "sqlite") == 0) {
ret = sqlite_db_start (session);
} else if (strcasecmp (type, "mysql") == 0) {
ret = mysql_db_start (session);
} else if (strcasecmp (type, "pgsql") == 0) {
ret = pgsql_db_start (session);
} else {
seaf_warning ("Unsupported db type %s.\n", type);
ret = -1;
}
g_free (type);
return ret;
}
#endif

View File

@ -1,17 +0,0 @@
#ifndef SEAF_UTILS_H
#define SEAF_UTILS_H
struct _SeafileSession;
char *
seafile_session_get_tmp_file_path (struct _SeafileSession *session,
const char *basename,
char path[]);
#ifdef SEAFILE_SERVER
int
load_database_config (struct _SeafileSession *session);
#endif
#endif

View File

@ -1,20 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SYNC_REPO_COMMON
#define SYNC_REPO_COMMON
#define SC_COMMIT_ID "300"
#define SS_COMMIT_ID "Commit ID"
#define SC_NO_REPO "301"
#define SS_NO_REPO "No such repo"
#define SC_NO_BRANCH "302"
#define SS_NO_BRANCH "No such branch"
#define SC_NO_DSYNC "303"
#define SS_NO_DSYNC "Not double sync"
#define SC_REPO_CORRUPT "304"
#define SS_REPO_CORRUPT "Repo corrupted"
#define SC_SERVER_ERROR "401"
#define SS_SERVER_ERROR "Internal server error"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,84 +0,0 @@
#ifndef UNPACK_TREES_H
#define UNPACK_TREES_H
#include "common.h"
#include "utils.h"
#include "seaf-tree-walk.h"
#include "index/index.h"
#include "seafile-crypt.h"
#define MAX_UNPACK_TREES 8
struct unpack_trees_options;
typedef int (*merge_fn_t)(struct cache_entry **src,
struct unpack_trees_options *options);
enum unpack_trees_error_types {
ERROR_WOULD_OVERWRITE = 0,
ERROR_NOT_UPTODATE_FILE,
ERROR_NOT_UPTODATE_DIR,
ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN,
ERROR_WOULD_LOSE_UNTRACKED_REMOVED,
NB_UNPACK_TREES_ERROR_TYPES
};
struct unpack_trees_options {
unsigned int reset,
merge,
update,
index_only,
nontrivial_merge,
trivial_merges_only,
verbose_update,
aggressive,
skip_unmerged,
initial_checkout,
diff_index_cached,
debug_unpack,
skip_sparse_checkout,
gently,
show_all_errors;
char repo_id[37];
int version;
const char *prefix;
const char *base;
int cache_bottom;
merge_fn_t fn;
const char *msgs[NB_UNPACK_TREES_ERROR_TYPES];
/*
* Store error messages in an array, each case
* corresponding to a error message type
*/
GList *unpack_rejects[NB_UNPACK_TREES_ERROR_TYPES];
int head_idx;
int merge_size;
struct cache_entry *df_conflict_entry;
void *unpack_data;
struct index_state *dst_index;
struct index_state *src_index;
struct index_state result;
SeafileCrypt *crypt;
};
extern int unpack_trees(unsigned n, struct tree_desc *t,
struct unpack_trees_options *options);
enum {
OPR_CHECKOUT,
OPR_MERGE,
N_OPR_TYPES,
};
gboolean
get_unpack_trees_error_msgs(struct unpack_trees_options *o, GString *msgbuf, int opr_type);
int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o);
int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o);
int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o);
#endif

View File

@ -151,7 +151,6 @@ AC_SUBST(LIB_ICONV)
LIBEVENT_REQUIRED=2.0
GLIB_REQUIRED=2.16.0
CCNET_REQUIRED=0.9.3
SEARPC_REQUIRED=1.0
JANSSON_REQUIRED=2.2.1
CURL_REQUIRED=7.17
@ -166,10 +165,6 @@ PKG_CHECK_MODULES(GOBJECT, [gobject-2.0 >= $GLIB_REQUIRED])
AC_SUBST(GOBJECT_CFLAGS)
AC_SUBST(GOBJECT_LIBS)
PKG_CHECK_MODULES(CCNET, [libccnet >= $CCNET_REQUIRED])
AC_SUBST(CCNET_CFLAGS)
AC_SUBST(CCNET_LIBS)
PKG_CHECK_MODULES(SEARPC, [libsearpc >= $SEARPC_REQUIRED])
AC_SUBST(SEARPC_CFLAGS)
AC_SUBST(SEARPC_LIBS)

View File

@ -6,7 +6,6 @@ AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \
-I$(top_srcdir)/lib \
-I$(top_builddir)/lib \
-I$(top_srcdir)/common \
@CCNET_CFLAGS@ \
@SEARPC_CFLAGS@ \
@GLIB2_CFLAGS@ \
@MSVC_CFLAGS@ \
@ -17,45 +16,22 @@ AM_CFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \
bin_PROGRAMS = seaf-daemon
proc_headers = $(addprefix processors/, \
check-tx-v3-proc.h \
sendfs-proc.h \
getfs-proc.h \
sendbranch-proc.h \
getcs-proc.h \
sync-repo-proc.h \
getcommit-v2-proc.h \
sendcommit-v3-proc.h \
sendcommit-v3-new-proc.h \
getcs-v2-proc.h \
checkbl-proc.h \
getcommit-v3-proc.h \
checkff-proc.h \
getca-proc.h \
check-protocol-proc.h \
sendcommit-v4-proc.h \
sendfs-v2-proc.h \
getfs-v2-proc.h)
proc_headers += ../common/processors/objecttx-common.h
noinst_HEADERS = \
job-mgr.h \
timer.h \
cevent.h \
repo-mgr.h \
transfer-mgr.h \
status.h sync-mgr.h \
sync-mgr.h \
wt-monitor.h \
merge.h merge-recursive.h vc-utils.h seafile-session.h \
vc-utils.h seafile-session.h \
clone-mgr.h \
wt-monitor-structs.h \
../common/sync-repo-common.h \
block-tx-client.h \
seafile-config.h \
http-tx-mgr.h \
sync-status-tree.h \
filelock-mgr.h \
set-perm.h \
change-set.h \
$(proc_headers)
change-set.h
if LINUX
wt_monitor_src = wt-monitor.c wt-monitor-linux.c wt-monitor-structs.c
@ -70,20 +46,18 @@ wt_monitor_src = wt-monitor.c wt-monitor-macos.c wt-monitor-structs.c
endif
common_src = \
job-mgr.c timer.c cevent.c \
http-tx-mgr.c \
transfer-mgr.c \
../common/unpack-trees.c ../common/seaf-tree-walk.c \
merge.c merge-recursive.c vc-utils.c \
status.c sync-mgr.c seafile-session.c \
vc-utils.c \
sync-mgr.c seafile-session.c \
../common/seafile-crypt.c ../common/diff-simple.c $(wt_monitor_src) \
clone-mgr.c \
seafile-config.c \
../common/branch-mgr.c ../common/fs-mgr.c \
repo-mgr.c ../common/commit-mgr.c \
../common/log.c ../common/object-list.c \
../common/log.c \
../common/rpc-service.c \
../common/vc-common.c \
../common/seaf-utils.c \
../common/obj-store.c \
../common/obj-backend-fs.c \
../common/block-mgr.c \
@ -91,30 +65,10 @@ common_src = \
../common/block-backend-fs.c \
../common/mq-mgr.c \
../common/curl-init.c \
block-tx-client.c \
../common/block-tx-utils.c \
sync-status-tree.c \
filelock-mgr.c \
set-perm.c \
change-set.c \
processors/check-tx-v3-proc.c \
processors/sendfs-proc.c \
processors/getfs-proc.c \
processors/sendbranch-proc.c \
processors/getcs-proc.c \
processors/sync-repo-proc.c \
processors/getcommit-v2-proc.c \
processors/sendcommit-v3-proc.c \
processors/sendcommit-v3-new-proc.c \
processors/getcs-v2-proc.c \
processors/checkbl-proc.c \
processors/getcommit-v3-proc.c \
processors/checkff-proc.c \
processors/getca-proc.c \
processors/check-protocol-proc.c \
processors/sendcommit-v4-proc.c \
processors/sendfs-v2-proc.c \
processors/getfs-v2-proc.c
change-set.c
seaf_daemon_SOURCES = seaf-daemon.c $(common_src)
@ -124,6 +78,6 @@ seaf_daemon_LDADD = $(top_builddir)/lib/libseafile_common.la \
@LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \
$(top_builddir)/common/cdc/libcdc.la \
$(top_builddir)/common/index/libindex.la @LIB_WS32@ @LIB_CRYPT32@ \
@SEARPC_LIBS@ @CCNET_LIBS@ @JANSSON_LIBS@ @LIB_MAC@ @ZLIB_LIBS@ @CURL_LIBS@ @BPWRAPPER_LIBS@
@SEARPC_LIBS@ @JANSSON_LIBS@ @LIB_MAC@ @ZLIB_LIBS@ @CURL_LIBS@ @BPWRAPPER_LIBS@
seaf_daemon_LDFLAGS = @CONSOLE@

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
#ifndef BLOCK_TX_CLIENT_H
#define BLOCK_TX_CLIENT_H
#include "transfer-mgr.h"
typedef void (*BlockTxClientDoneCB) (BlockTxInfo *);
/*
* There are two modes to use block-tx-client:
*
* 1. In upload, the client is set to one-time mode.
* After all blocks are uploaded, the client done callback is called.
*
* 2. In download, the client is set to interactive mode.
* The block tx client first has to connect to the server and do authentication.
* After authentication is done, block-tx-client writes a READY reply to done_pipe.
* Transfer manager waits on the done_pipe for the READY reply.
* Transfer manager then initiates multiple batches of blocks for download.
* After each batch is downloaded, the block client writes to info->done_pipe
* to notify transfer manager.
* After all blocks are downloaded, transfer manager send a END command to
* block client. The block client exits and returns an ENDED response code.
*/
int
block_tx_client_start (BlockTxInfo *info, BlockTxClientDoneCB cb);
enum {
BLOCK_CLIENT_CMD_TRANSFER = 0,
BLOCK_CLIENT_CMD_CANCEL,
BLOCK_CLIENT_CMD_END,
BLOCK_CLIENT_CMD_RESTART,
};
void
block_tx_client_run_command (BlockTxInfo *info, int command);
#endif

106
daemon/cevent.c Normal file
View File

@ -0,0 +1,106 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "include.h"
#include "cevent.h"
#include "seafile-session.h"
#define CEVENT_SIZE (sizeof(CEvent))
typedef struct Handler {
cevent_handler handler;
void *handler_data;
} Handler;
CEventManager* cevent_manager_new ()
{
CEventManager *manager;
manager = g_new0 (CEventManager, 1);
pthread_mutex_init (&manager->mutex, NULL);
manager->handler_table = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, g_free);
return manager;
}
void pipe_callback (evutil_socket_t fd, short event, void *vmgr)
{
CEventManager *manager = (CEventManager *) vmgr;
CEvent *cevent;
char buf[CEVENT_SIZE];
if (seaf_pipe_readn(fd, buf, CEVENT_SIZE) != CEVENT_SIZE) {
return;
}
cevent = (CEvent *)buf;
Handler *h = g_hash_table_lookup (manager->handler_table,
(gconstpointer)(long)cevent->id);
if (h == NULL) {
g_warning ("no handler for event type %d\n", cevent->id);
return;
}
h->handler(cevent, h->handler_data);
}
int cevent_manager_start (CEventManager *manager)
{
if (seaf_pipe(manager->pipefd) < 0) {
g_warning ("pipe error: %s\n", strerror(errno));
return -1;
}
manager->event = event_new (seaf->ev_base, manager->pipefd[0],
EV_READ | EV_PERSIST, pipe_callback, manager);
event_add (manager->event, NULL);
return 0;
}
uint32_t cevent_manager_register (CEventManager *manager,
cevent_handler handler, void *handler_data)
{
uint32_t id;
Handler *h;
h = g_new0(Handler, 1);
h->handler = handler;
h->handler_data = handler_data;
/* Since we're using 32-bit int for id, it may wrap around to 0.
* If some caller persistently use one id, it's handler may be
* overwritten by others.
*/
do {
id = manager->next_id++;
} while (g_hash_table_lookup (manager->handler_table, (gpointer)(long)id));
g_hash_table_insert (manager->handler_table, (gpointer)(long)id, h);
return id;
}
void cevent_manager_unregister (CEventManager *manager, uint32_t id)
{
g_hash_table_remove (manager->handler_table, (gpointer)(long)id);
}
void
cevent_manager_add_event (CEventManager *manager, uint32_t id,
void *data)
{
pthread_mutex_lock (&manager->mutex);
struct CEvent cevent;
char *buf = (char *) &cevent;
cevent.id = id;
cevent.data = data;
if (seaf_pipe_writen(manager->pipefd[1], buf, CEVENT_SIZE) != CEVENT_SIZE) {
g_warning ("add event error\n");
}
pthread_mutex_unlock (&manager->mutex);
}

56
daemon/cevent.h Normal file
View File

@ -0,0 +1,56 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* CEvent is used for send message from a work thread to main thread.
*/
#ifndef CEVENT_H
#define CEVENT_H
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#else
#include <event.h>
#endif
#include <glib.h>
#include <pthread.h>
#include "utils.h"
typedef struct CEvent CEvent;
typedef void (*cevent_handler) (CEvent *event, void *handler_data);
struct CEvent {
uint32_t id;
void *data;
};
typedef struct CEventManager CEventManager;
struct CEventManager {
seaf_pipe_t pipefd[2];
struct event *event;
GHashTable *handler_table;
uint32_t next_id;
pthread_mutex_t mutex;
};
CEventManager* cevent_manager_new ();
int cevent_manager_start (CEventManager *manager);
uint32_t cevent_manager_register (CEventManager *manager,
cevent_handler handler, void *handler_data);
void cevent_manager_unregister (CEventManager *manager, uint32_t id);
void cevent_manager_add_event (CEventManager *manager, uint32_t id,
void *event_data);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -70,10 +70,7 @@ struct _CloneTask {
char *effective_url;
gboolean use_fileserver_port;
int http_protocol_version;
gboolean http_sync;
char server_head_id[41];
gboolean server_side_merge;
};
const char *
@ -86,7 +83,7 @@ struct _SeafCloneManager {
struct _SeafileSession *seaf;
sqlite3 *db;
GHashTable *tasks;
struct CcnetTimer *check_timer;
struct SeafTimer *check_timer;
};
SeafCloneManager *

View File

@ -21,8 +21,6 @@
#include <openssl/ssl.h>
#endif
#include <ccnet/ccnet-client.h>
#include "seafile-config.h"
#include "seafile-session.h"
@ -35,6 +33,8 @@
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include "timer.h"
#define HTTP_OK 200
#define HTTP_BAD_REQUEST 400
#define HTTP_FORBIDDEN 403
@ -90,7 +90,7 @@ struct _HttpTxPriv {
GHashTable *connection_pools; /* host -> connection pool */
pthread_mutex_t pools_lock;
CcnetTimer *reset_bytes_timer;
SeafTimer *reset_bytes_timer;
char *ca_bundle_path;
@ -367,9 +367,9 @@ http_tx_manager_start (HttpTxManager *mgr)
/* TODO: add a timer to clean up unused Http connections. */
mgr->priv->reset_bytes_timer = ccnet_timer_new (reset_bytes,
mgr,
RESET_BYTES_INTERVAL_MSEC);
mgr->priv->reset_bytes_timer = seaf_timer_new (reset_bytes,
mgr,
RESET_BYTES_INTERVAL_MSEC);
return 0;
}
@ -1299,10 +1299,10 @@ http_tx_manager_check_protocol_version (HttpTxManager *manager,
data->callback = callback;
data->user_data = user_data;
int ret = ccnet_job_manager_schedule_job (seaf->job_mgr,
check_protocol_version_thread,
check_protocol_version_done,
data);
int ret = seaf_job_manager_schedule_job (seaf->job_mgr,
check_protocol_version_thread,
check_protocol_version_done,
data);
if (ret < 0) {
g_free (data->host);
g_free (data);
@ -1463,10 +1463,10 @@ http_tx_manager_check_head_commit (HttpTxManager *manager,
data->user_data = user_data;
data->use_fileserver_port = use_fileserver_port;
if (ccnet_job_manager_schedule_job (seaf->job_mgr,
check_head_commit_thread,
check_head_commit_done,
data) < 0) {
if (seaf_job_manager_schedule_job (seaf->job_mgr,
check_head_commit_thread,
check_head_commit_done,
data) < 0) {
g_free (data->host);
g_free (data->token);
g_free (data);
@ -1817,10 +1817,10 @@ http_tx_manager_get_folder_perms (HttpTxManager *manager,
data->user_data = user_data;
data->use_fileserver_port = use_fileserver_port;
if (ccnet_job_manager_schedule_job (seaf->job_mgr,
get_folder_perms_thread,
get_folder_perms_done,
data) < 0) {
if (seaf_job_manager_schedule_job (seaf->job_mgr,
get_folder_perms_thread,
get_folder_perms_done,
data) < 0) {
g_free (data->host);
g_free (data);
return -1;
@ -2093,10 +2093,10 @@ http_tx_manager_get_locked_files (HttpTxManager *manager,
data->user_data = user_data;
data->use_fileserver_port = use_fileserver_port;
if (ccnet_job_manager_schedule_job (seaf->job_mgr,
get_locked_files_thread,
get_locked_files_done,
data) < 0) {
if (seaf_job_manager_schedule_job (seaf->job_mgr,
get_locked_files_thread,
get_locked_files_done,
data) < 0) {
g_free (data->host);
g_free (data);
return -1;
@ -2377,7 +2377,7 @@ check_permission (HttpTxTask *task, Connection *conn)
url = g_strdup_printf ("%s/%srepo/%s/permission-check/?op=%s"
"&client_id=%s&client_name=%s",
task->host, url_prefix, task->repo_id, type,
seaf->session->base.id, client_name);
seaf->client_id, client_name);
g_free (client_name);
} else {
url = g_strdup_printf ("%s/%srepo/%s/permission-check/?op=%s",
@ -2450,10 +2450,10 @@ http_tx_manager_add_upload (HttpTxManager *manager,
g_strdup(repo_id),
task);
if (ccnet_job_manager_schedule_job (seaf->job_mgr,
http_upload_thread,
http_upload_done,
task) < 0) {
if (seaf_job_manager_schedule_job (seaf->job_mgr,
http_upload_thread,
http_upload_done,
task) < 0) {
g_hash_table_remove (manager->priv->upload_tasks, repo_id);
return -1;
}
@ -3826,10 +3826,10 @@ http_tx_manager_add_download (HttpTxManager *manager,
NULL);
task->repo_name = g_strdup(repo_name);
if (ccnet_job_manager_schedule_job (seaf->job_mgr,
http_download_thread,
http_download_done,
task) < 0) {
if (seaf_job_manager_schedule_job (seaf->job_mgr,
http_download_thread,
http_download_done,
task) < 0) {
g_hash_table_remove (manager->priv->download_tasks, repo_id);
return -1;
}
@ -4518,7 +4518,7 @@ http_download_thread (void *vdata)
REPO_PROP_DOWNLOAD_HEAD,
task->head);
int rc = seaf_repo_fetch_and_checkout (NULL, task, TRUE, task->head);
int rc = seaf_repo_fetch_and_checkout (task, task->head);
switch (rc) {
case FETCH_CHECKOUT_SUCCESS:
break;
@ -4644,7 +4644,7 @@ http_tx_manager_cancel_task (HttpTxManager *manager,
}
if (task->runtime_state == HTTP_TASK_RT_STATE_INIT) {
transition_state (task, HTTP_TASK_STATE_CANCELED, TASK_RT_STATE_FINISHED);
transition_state (task, HTTP_TASK_STATE_CANCELED, HTTP_TASK_RT_STATE_FINISHED);
return;
}

149
daemon/job-mgr.c Normal file
View File

@ -0,0 +1,149 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <event2/event.h>
#include <event2/event_compat.h>
#else
#include <event.h>
#endif
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "utils.h"
#include "log.h"
#include "seafile-session.h"
#include "job-mgr.h"
struct _SeafJobManager {
SeafileSession *session;
GThreadPool *thread_pool;
int next_job_id;
};
struct _SeafJob {
SeafJobManager *manager;
int id;
seaf_pipe_t pipefd[2];
JobThreadFunc thread_func;
JobDoneCallback done_func; /* called when the thread is done */
void *data;
/* the done callback should only access this field */
void *result;
};
typedef struct _SeafJob SeafJob;
SeafJob *
seaf_job_new ()
{
SeafJob *job;
job = g_new0 (SeafJob, 1);
return job;
}
void
seaf_job_free (SeafJob *job)
{
g_free (job);
}
static void
job_thread_wrapper (void *vdata, void *unused)
{
SeafJob *job = vdata;
job->result = job->thread_func (job->data);
if (seaf_pipe_writen (job->pipefd[1], "a", 1) != 1) {
seaf_warning ("[Job Manager] write to pipe error: %s\n", strerror(errno));
}
}
static void
job_done_cb (evutil_socket_t fd, short event, void *vdata)
{
SeafJob *job = vdata;
char buf[1];
if (seaf_pipe_readn (job->pipefd[0], buf, 1) != 1) {
seaf_warning ("[Job Manager] read pipe error: %s\n", strerror(errno));
}
seaf_pipe_close (job->pipefd[0]);
seaf_pipe_close (job->pipefd[1]);
if (job->done_func) {
job->done_func (job->result);
}
seaf_job_free (job);
}
int
job_thread_create (SeafJob *job)
{
SeafileSession *session = job->manager->session;
if (seaf_pipe (job->pipefd) < 0) {
seaf_warning ("[Job Manager] pipe error: %s\n", strerror(errno));
return -1;
}
g_thread_pool_push (job->manager->thread_pool, job, NULL);
event_base_once (session->ev_base, job->pipefd[0], EV_READ, job_done_cb, job, NULL);
return 0;
}
SeafJobManager *
seaf_job_manager_new (SeafileSession *session, int max_threads)
{
SeafJobManager *mgr;
mgr = g_new0 (SeafJobManager, 1);
mgr->session = session;
mgr->thread_pool = g_thread_pool_new (job_thread_wrapper,
NULL,
max_threads,
FALSE,
NULL);
return mgr;
}
void
seaf_job_manager_free (SeafJobManager *mgr)
{
g_thread_pool_free (mgr->thread_pool, TRUE, FALSE);
g_free (mgr);
}
int
seaf_job_manager_schedule_job (SeafJobManager *mgr,
JobThreadFunc func,
JobDoneCallback done_func,
void *data)
{
SeafJob *job = seaf_job_new ();
job->id = mgr->next_job_id++;
job->manager = mgr;
job->thread_func = func;
job->done_func = done_func;
job->data = data;
if (job_thread_create (job) < 0) {
seaf_job_free (job);
return -1;
}
return 0;
}

36
daemon/job-mgr.h Normal file
View File

@ -0,0 +1,36 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/**
* Job Manager manages long term jobs. These jobs are run in their
* own threads.
*/
#ifndef SEAF_JOB_MGR_H
#define SEAF_JOB_MGR_H
struct _SeafJobManager;
typedef struct _SeafJobManager SeafJobManager;
struct _SeafileSession;
/*
The thread func should return the result back by
return (void *)result;
The result will be passed to JobDoneCallback.
*/
typedef void* (*JobThreadFunc)(void *data);
typedef void (*JobDoneCallback)(void *result);
SeafJobManager *
seaf_job_manager_new (struct _SeafileSession *session, int max_threads);
void
seaf_job_manager_free (struct _SeafJobManager *mgr);
int
seaf_job_manager_schedule_job (struct _SeafJobManager *mgr,
JobThreadFunc func,
JobDoneCallback done_func,
void *data);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MERGE_RECURSIVE_H
#define MERGE_RECURSIVE_H
#include <glib.h>
#include "commit-mgr.h"
#include "fs-mgr.h"
#include "seafile-crypt.h"
struct merge_options {
char repo_id[37];
int version;
const char *ancestor;
const char *branch1;
const char *branch2;
const char *remote_head;
int call_depth;
char *worktree;
struct index_state *index;
GString *obuf;
GHashTable *current_file_set;
GHashTable *current_directory_set;
gboolean recover_merge;
gboolean force_merge;
SeafileCrypt *crypt;
/* True if we only want to know the files that would be
* updated in this merge, but don't want to update them in the
* worktree.
*/
gboolean collect_blocks_only;
BlockList *bl;
};
int merge_recursive(struct merge_options *o,
const char *h1_root,
const char *h2_root,
const char *ca_root,
int *clean,
char **root_id);
void init_merge_options(struct merge_options *o);
void clear_merge_options(struct merge_options *o);
char *write_tree_from_memory(struct merge_options *o);
#endif

View File

@ -1,432 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include <ccnet.h>
#include "index/index.h"
#include "unpack-trees.h"
#include "merge-recursive.h"
#include "merge.h"
#include "seafile-session.h"
#include "vc-utils.h"
#include "vc-common.h"
#if 0
static int
print_index (struct index_state *istate)
{
int i;
struct cache_entry *ce;
char id[41];
g_message ("Totally %u entries in index, version %u.\n",
istate->cache_nr, istate->version);
for (i = 0; i < istate->cache_nr; ++i) {
ce = istate->cache[i];
rawdata_to_hex (ce->sha1, id, 20);
g_message ("%s, %s, %o, %"G_GUINT64_FORMAT", %s, %d\n",
ce->name, id, ce->ce_mode,
ce->ce_mtime.sec, ce->modifier, ce_stage(ce));
}
return 0;
}
#endif
static int
do_real_merge (SeafRepo *repo,
SeafBranch *head_branch,
SeafCommit *head,
SeafBranch *remote_branch,
SeafCommit *remote,
SeafCommit *common,
gboolean recover_merge,
char **error)
{
struct merge_options opts;
char index_path[SEAF_PATH_MAX];
struct index_state istate;
char *root_id = NULL;
SeafCommit *merged;
int ret = 0, clean;
memset (&istate, 0, sizeof(istate));
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
if (read_index_from (&istate, index_path, repo->version) < 0) {
g_warning ("Failed to load index.\n");
*error = g_strdup ("Internal error.\n");
return -1;
}
init_merge_options (&opts);
memcpy (opts.repo_id, repo->id, 36);
opts.version = repo->version;
opts.index = &istate;
opts.worktree = repo->worktree;
opts.ancestor = "common ancestor";
opts.branch1 = seaf->session->base.user_name;
opts.branch2 = remote->creator_name;
opts.remote_head = remote->commit_id;
opts.recover_merge = recover_merge;
if (repo->encrypted) {
opts.crypt = seafile_crypt_new (repo->enc_version,
repo->enc_key,
repo->enc_iv);
}
ret = merge_recursive (&opts,
head->root_id, remote->root_id, common->root_id,
&clean, &root_id);
if (ret < 0)
goto out;
if (update_index (&istate, index_path) < 0) {
*error = g_strdup ("Internal error.\n");
ret = -1;
goto out;
}
if (clean) {
merged = seaf_commit_new (NULL,
repo->id,
root_id,
repo->email ? repo->email
: seaf->session->base.user_name,
seaf->session->base.id,
"Auto merge by system",
0);
merged->parent_id = g_strdup(head->commit_id);
merged->second_parent_id = g_strdup(remote->commit_id);
merged->new_merge = TRUE;
seaf_repo_to_commit (repo, merged);
if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged) < 0) {
seaf_commit_unref (merged);
*error = g_strdup ("Internal error.\n");
ret = -1;
goto out;
}
seaf_branch_set_commit (head_branch, merged->commit_id);
seaf_branch_manager_update_branch (seaf->branch_mgr, head_branch);
g_debug ("Auto merged.\n");
seaf_commit_unref (merged);
} else {
ret = -1;
g_debug ("Auto merge failed.\n");
}
out:
if (root_id)
g_free (root_id);
g_free (opts.crypt);
clear_merge_options (&opts);
discard_index (&istate);
return ret;
}
static SeafCommit *
get_common_ancestor_commit (const char *repo_id, int version)
{
char ca_id[41], head_id[41];
SeafCommit *commit;
if (seaf_repo_manager_get_common_ancestor (seaf->repo_mgr,
repo_id, ca_id, head_id) < 0) {
g_warning ("Common ancestor commit id is not found in db.\n");
return NULL;
}
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
repo_id, version,
ca_id);
return commit;
}
int
merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
int *merge_status)
{
SeafCommit *common = NULL;
SeafCommit *head = NULL, *remote = NULL;
int ret = 0;
#if 0
SeafRepoMergeInfo minfo;
#endif
g_return_val_if_fail (repo && remote_branch && error, -1);
*merge_status = MERGE_STATUS_UNKNOWN;
#if 0
memset (&minfo, 0, sizeof(minfo));
if (seaf_repo_manager_get_merge_info (repo->manager, repo->id, &minfo) < 0) {
g_warning ("Failed to get merge status of repo %s.\n", repo->id);
return -1;
}
#endif
head = seaf_commit_manager_get_commit (seaf->commit_mgr,
repo->id, repo->version,
repo->head->commit_id);
if (!head) {
*error = g_strdup("Internal error: current branch corrupted.\n");
return -1;
}
remote = seaf_commit_manager_get_commit (seaf->commit_mgr,
repo->id, repo->version,
remote_branch->commit_id);
if (!remote) {
*error = g_strdup("Invalid remote branch.\n");
ret = -1;
goto free_commits;
}
#if 0
/* Are we going to recover from the last interrupted merge? */
if (minfo.in_merge) {
/* We don't need to recover 2 cases, since the last merge was actually finished.
* - "master" and "local" are the same;
* - index is unmerged.
*
* The first case is a clean merge; the second case is unclean merge.
*/
if (strcmp (head->commit_id, remote->commit_id) == 0 ||
seaf_repo_is_index_unmerged (repo)) {
seaf_repo_manager_clear_merge (repo->manager, repo->id);
goto free_commits;
}
}
#endif
/* If not all commits are downloaded, find common ancestor from db;
* otherwise we'll use the old method to calculate
* common ancestor from local history.
*/
if (repo->version > 0)
common = get_common_ancestor_commit (repo->id, repo->version);
else
common = get_merge_base (head, remote);
if (!common) {
g_warning ("Cannot find common ancestor\n");
*error = g_strdup ("Cannot find common ancestor\n");
ret = -1;
goto free_commits;
}
/* We use the same logic for normal merge and recover. */
/* Set in_merge state. */
seaf_repo_manager_set_merge (repo->manager, repo->id, remote_branch->commit_id);
/* printf ("common commit id is %s.\n", common->commit_id); */
if (strcmp(common->commit_id, remote->commit_id) == 0) {
/* We are already up to date. */
g_debug ("Already up to date.\n");
*merge_status = MERGE_STATUS_UPTODATE;
} else if (strcmp(common->commit_id, head->commit_id) == 0) {
*merge_status = MERGE_STATUS_FAST_FORWARD;
/* Fast forward. */
if (seaf_repo_checkout_commit (repo, remote, FALSE, error) < 0) {
ret = -1;
goto out;
}
seaf_branch_set_commit (repo->head, remote->commit_id);
seaf_branch_manager_update_branch (seaf->branch_mgr, repo->head);
/* Repo info on the client is in memory. */
g_free (repo->name);
repo->name = g_strdup(remote->repo_name);
g_free (repo->desc);
repo->desc = g_strdup(remote->repo_desc);
g_debug ("Fast forward.\n");
} else {
/* Not up-to-date and ff, we need a real merge. */
*merge_status = MERGE_STATUS_REAL_MERGE;
ret = do_real_merge (repo,
repo->head, head,
remote_branch, remote, common,
FALSE,
error);
}
out:
/* Clear in_merge state, no matter clean or not. */
seaf_repo_manager_clear_merge (repo->manager, repo->id);
free_commits:
seaf_commit_unref (common);
seaf_commit_unref (remote);
seaf_commit_unref (head);
return ret;
}
/*
* Get the new blocks that need to be checked out if we ff to @remote.
*/
static int
get_new_blocks_ff (SeafRepo *repo,
SeafCommit *head,
SeafCommit *remote,
BlockList **bl)
{
SeafRepoManager *mgr = repo->manager;
char index_path[SEAF_PATH_MAX];
struct tree_desc trees[2];
struct unpack_trees_options topts;
struct index_state istate;
int ret = 0;
memset (&istate, 0, sizeof(istate));
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
if (read_index_from (&istate, index_path, repo->version) < 0) {
g_warning ("Failed to load index.\n");
return -1;
}
fill_tree_descriptor (repo->id, repo->version, &trees[0], head->root_id);
fill_tree_descriptor (repo->id, repo->version, &trees[1], remote->root_id);
memset(&topts, 0, sizeof(topts));
memcpy (topts.repo_id, repo->id, 36);
topts.version = repo->version;
topts.base = repo->worktree;
topts.head_idx = -1;
topts.src_index = &istate;
topts.update = 1;
topts.merge = 1;
topts.fn = twoway_merge;
/* unpack_trees() doesn't update index or worktree. */
if (unpack_trees (2, trees, &topts) < 0) {
g_warning ("Failed to ff to commit %s.\n", remote->commit_id);
ret = -1;
goto out;
}
*bl = block_list_new ();
collect_new_blocks_from_index (repo->id, repo->version, &topts.result, *bl);
out:
tree_desc_free (&trees[0]);
tree_desc_free (&trees[1]);
discard_index (&istate);
discard_index (&topts.result);
return ret;
}
/*
* Get the new blocks that need to be checked out if we do a real merge.
*/
static int
get_new_blocks_merge (SeafRepo *repo,
SeafCommit *head,
SeafCommit *remote,
SeafCommit *common,
BlockList **bl)
{
struct merge_options opts;
char index_path[SEAF_PATH_MAX];
struct index_state istate;
int ret, clean;
memset (&istate, 0, sizeof(istate));
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
if (read_index_from (&istate, index_path, repo->version) < 0) {
g_warning ("Failed to load index.\n");
return -1;
}
init_merge_options (&opts);
memcpy (opts.repo_id, repo->id, 36);
opts.version = repo->version;
opts.index = &istate;
opts.worktree = repo->worktree;
opts.ancestor = "common ancestor";
opts.branch1 = seaf->session->base.user_name;
opts.branch2 = remote->creator_name;
opts.collect_blocks_only = TRUE;
*bl = block_list_new();
opts.bl = *bl;
ret = merge_recursive (&opts,
head->root_id, remote->root_id, common->root_id,
&clean, NULL);
clear_merge_options (&opts);
discard_index (&istate);
return ret;
}
/*
* Get the list of new blocks that would be checked out after
* we merge with a branch headed by @remote.
*
* This function should be called before downloading any block
* if the repo is set to not preserving history. In this case,
* we don't want to download any block that will not be checked
* out to the worktree (i.e. data from any historical commits).
*
* Return 0 if successfully calculate the block list, -1 otherwise.
* If there is no new block to download, *@bl will be set to NULL;
* otherwise it's set to the block list.
*/
int
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl)
{
SeafCommit *common = NULL;
SeafCommit *head = NULL;
int ret = 0;
head = seaf_commit_manager_get_commit (seaf->commit_mgr,
repo->id, repo->version,
repo->head->commit_id);
if (!head) {
g_warning ("current branch corrupted.\n");
return -1;
}
/* If not all commits are downloaded, get common ancestor from db;
* otherwise we'll use the old method to calculate
* common ancestor from local history.
*/
if (repo->version > 0)
common = get_common_ancestor_commit (repo->id, repo->version);
else
common = get_merge_base (head, remote);
if (!common) {
g_warning ("Cannot find common ancestor\n");
ret = -1;
goto out;
}
if (strcmp(common->commit_id, remote->commit_id) == 0) {
/* We are already up to date. No new block. */
*bl = NULL;
} else if (strcmp(common->commit_id, head->commit_id) == 0) {
/* Fast forward. */
ret = get_new_blocks_ff (repo, head, remote, bl);
} else {
/* Not up-to-date and ff, we need a real merge. */
ret = get_new_blocks_merge (repo, head, remote, common, bl);
}
out:
seaf_commit_unref (common);
seaf_commit_unref (head);
return ret;
}

View File

@ -1,18 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MERGE_H
#define MERGE_H
#include "repo-mgr.h"
#include "commit-mgr.h"
#include "branch-mgr.h"
#include "fs-mgr.h"
int
merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
gboolean *real_merge);
int
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl);
#endif

View File

@ -1,75 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include "check-protocol-proc.h"
#define DEBUG_FLAG SEAFILE_DEBUG_SYNC
#include "log.h"
G_DEFINE_TYPE (SeafileCheckProtocolProc, seafile_check_protocol_proc, CCNET_TYPE_PROCESSOR)
static int
check_protocol_start (CcnetProcessor *processor, int argc, char **argv);
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
seafile_check_protocol_proc_class_init (SeafileCheckProtocolProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "seafile-check-protocol";
proc_class->start = check_protocol_start;
proc_class->handle_response = handle_response;
}
static void
seafile_check_protocol_proc_init (SeafileCheckProtocolProc *processor)
{
}
static int
check_protocol_start (CcnetProcessor *processor, int argc, char **argv)
{
if (argc != 0) {
seaf_warning ("[sync-repo] argc should be 0.\n");
ccnet_processor_done (processor, FALSE);
return 0;
}
char buf[256];
snprintf (buf, 256, "remote %s seafile-check-protocol-slave", processor->peer_id);
ccnet_processor_send_request (processor, buf);
return 0;
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileCheckProtocolProc *proc = (SeafileCheckProtocolProc *)processor;
if (memcmp (code, SC_OK, 3) == 0) {
if (content[clen-1] != '\0') {
seaf_warning ("[check-protocol] Response not end with NULL\n");
ccnet_processor_done (processor, FALSE);
return;
}
proc->protocol_version = atoi(content);
ccnet_processor_done (processor, TRUE);
} else
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,31 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_CHECK_PROTOCOL_PROC_H
#define SEAFILE_CHECK_PROTOCOL_PROC_H
#include <glib-object.h>
#include <ccnet.h>
#define SEAFILE_TYPE_CHECK_PROTOCOL_PROC (seafile_check_protocol_proc_get_type ())
#define SEAFILE_CHECK_PROTOCOL_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECK_PROTOCOL_PROC, SeafileCheckProtocolProc))
#define SEAFILE_IS_CHECK_PROTOCOL_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECK_PROTOCOL_PROC))
#define SEAFILE_CHECK_PROTOCOL_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECK_PROTOCOL_PROC, SeafileCheckProtocolProcClass))
#define IS_SEAFILE_CHECK_PROTOCOL_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECK_PROTOCOL_PROC))
#define SEAFILE_CHECK_PROTOCOL_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECK_PROTOCOL_PROC, SeafileCheckProtocolProcClass))
typedef struct _SeafileCheckProtocolProc SeafileCheckProtocolProc;
typedef struct _SeafileCheckProtocolProcClass SeafileCheckProtocolProcClass;
struct _SeafileCheckProtocolProc {
CcnetProcessor parent_instance;
int protocol_version;
};
struct _SeafileCheckProtocolProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_check_protocol_proc_get_type ();
#endif

View File

@ -1,335 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#ifndef USE_GPL_CRYPTO
#include <string.h>
#include <ccnet.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include "seafile-session.h"
#include "vc-common.h"
#include "seafile-crypt.h"
#include "log.h"
#include "utils.h"
#include "check-tx-v3-proc.h"
#define SC_GET_TOKEN "301"
#define SS_GET_TOKEN "Get token"
#define SC_PUT_TOKEN "302"
#define SS_PUT_TOKEN "Put token"
#define SC_GET_VERSION "303"
#define SS_GET_VERSION "Get version"
#define SC_VERSION "304"
#define SS_VERSION "Version"
#define SC_ACCESS_DENIED "401"
#define SS_ACCESS_DENIED "Access denied"
#define SC_PROTOCOL_MISMATCH "405"
#define SS_PROTOCOL_MISMATCH "Protocol version mismatch"
/* Only for upload */
#define SC_QUOTA_ERROR "402"
#define SS_QUOTA_ERROR "Failed to get quota"
#define SC_QUOTA_FULL "403"
#define SS_QUOTA_FULL "storage for the repo's owner is full"
/* Only for download */
#define SC_BAD_REPO "406"
#define SS_BAD_REPO "Repo doesn't exist"
enum {
CHECK_TX_TYPE_UPLOAD,
CHECK_TX_TYPE_DOWNLOAD,
};
G_DEFINE_TYPE (SeafileCheckTxV3Proc, seafile_check_tx_v3_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
CCNET_PROCESSOR_CLASS (seafile_check_tx_v3_proc_parent_class)->release_resource (processor);
}
static void
seafile_check_tx_v3_proc_class_init (SeafileCheckTxV3ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "check-tx-proc-v3";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
}
static void
seafile_check_tx_v3_proc_init (SeafileCheckTxV3Proc *processor)
{
}
/* token -> AES encrypt with session key -> rawdata_to_hex -> output */
static char *
encrypt_token (CcnetProcessor *processor, const char *token)
{
CcnetPeer *peer = NULL;
char *enc_out = NULL;
SeafileCrypt *crypt = NULL;
unsigned char key[16], iv[16];
int len;
char *output = NULL;
if (!token)
goto out;
peer = ccnet_get_peer(seaf->ccnetrpc_client, processor->peer_id);
if (!peer || !peer->session_key) {
seaf_warning ("[check tx v3] peer or peer session key not exist\n");
goto out;
}
EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */
EVP_sha1(), /* message digest */
NULL, /* slat */
(unsigned char*)peer->session_key,
strlen(peer->session_key),
1, /* iteration times */
key, /* the derived key */
iv); /* IV, initial vector */
crypt = seafile_crypt_new (1, key, iv);
/* encrypt the token with session key, including the trailing null byte */
if (seafile_encrypt (&enc_out, &len, token, strlen(token) + 1, crypt) < 0) {
seaf_warning ("[check tx v3] failed to encrypt token\n");
goto out;
}
output = g_malloc (len * 2 + 1);
rawdata_to_hex ((unsigned char *)enc_out, output, len);
output[len * 2] = '\0';
out:
g_free (crypt);
g_free (enc_out);
if (peer)
g_object_unref(peer);
return output;
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
SeafileCheckTxV3Proc *proc = (SeafileCheckTxV3Proc *)processor;
TransferTask *task = proc->task;
char *type, *enc_token;
GString *buf;
if (argc != 1) {
transition_state_to_error (task, TASK_ERR_CHECK_UPLOAD_START);
ccnet_processor_done (processor, FALSE);
return -1;
}
type = argv[0];
if (strcmp (type, "upload") == 0)
proc->type = CHECK_TX_TYPE_UPLOAD;
else
proc->type = CHECK_TX_TYPE_DOWNLOAD;
enc_token = encrypt_token (processor, task->token);
if (!enc_token) {
transition_state_to_error (task, TASK_ERR_CHECK_UPLOAD_START);
ccnet_processor_done (processor, FALSE);
return -1;
}
buf = g_string_new(NULL);
g_string_append_printf (buf,
"remote %s seafile-check-tx-slave-v3 %s %d %s %s %s",
processor->peer_id, type, CURRENT_PROTO_VERSION,
task->repo_id, task->to_branch, enc_token);
ccnet_processor_send_request (processor, buf->str);
g_free (enc_token);
g_string_free (buf, TRUE);
return 0;
}
static void
handle_upload_ok (CcnetProcessor *processor, TransferTask *task,
char *content, int clen)
{
if (clen == 0) {
ccnet_processor_send_update (processor,
SC_GET_TOKEN, SS_GET_TOKEN,
NULL, 0);
return;
}
if (clen != 41 || content[clen-1] != '\0') {
seaf_warning ("Bad response content.\n");
transfer_task_set_error (task, TASK_ERR_UNKNOWN);
ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
/* Ignore the returned remote head id, just use the head of master branch.
* For protocol version >= 6, the complete hitstory is not downloaded, so
* there is no way to check fast forward on the client. For protocol version
* < 6, the server will check fast forward anyway.
*/
SeafBranch *master = seaf_branch_manager_get_branch (seaf->branch_mgr,
task->repo_id, "master");
if (!master) {
seaf_warning ("Cannot find branch master for repo %s.\n", task->repo_id);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
memcpy (task->remote_head, master->commit_id, 40);
seaf_branch_unref (master);
ccnet_processor_send_update (processor,
SC_GET_TOKEN, SS_GET_TOKEN,
NULL, 0);
}
static void
handle_download_ok (CcnetProcessor *processor, TransferTask *task,
char *content, int clen)
{
if (clen != 41 || content[clen-1] != '\0') {
seaf_warning ("Bad response content.\n");
transfer_task_set_error (task, TASK_ERR_UNKNOWN);
ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
memcpy (task->head, content, 41);
ccnet_processor_send_update (processor,
SC_GET_TOKEN, SS_GET_TOKEN,
NULL, 0);
}
static void
set_download_head_info (TransferTask *task)
{
/* If the last download was interrupted in the fetch and checkout stage,
* resume last download.
*/
char *last_head = seaf_repo_manager_get_repo_property (seaf->repo_mgr,
task->repo_id,
REPO_PROP_DOWNLOAD_HEAD);
if (last_head && strcmp (last_head, EMPTY_SHA1) != 0)
memcpy (task->head, last_head, 41);
g_free (last_head);
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileCheckTxV3Proc *proc = (SeafileCheckTxV3Proc *)processor;
TransferTask *task = proc->task;
if (strncmp(code, SC_OK, 3) == 0) {
if (proc->type == CHECK_TX_TYPE_UPLOAD)
handle_upload_ok (processor, task, content, clen);
else
handle_download_ok (processor, task, content, clen);
} else if (strncmp (code, SC_PUT_TOKEN, 3) == 0) {
/* In LAN sync, we don't use session token. */
if (clen == 0) {
ccnet_processor_done (processor, TRUE);
return;
}
if (content[clen-1] != '\0') {
seaf_warning ("Bad response content.\n");
transfer_task_set_error (task, TASK_ERR_UNKNOWN);
ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
task->session_token = g_strdup (content);
ccnet_processor_send_update (processor, SC_GET_VERSION, SS_GET_VERSION,
NULL, 0);
} else if (strncmp (code, SC_VERSION, 3) == 0) {
int server_version = atoi(content);
/* There is a bug in block transfer in version 4, so it's not supported. */
if (server_version == 4)
server_version = 3;
task->protocol_version = MIN (server_version, CURRENT_PROTO_VERSION);
if (task->protocol_version < 5) {
seaf_warning ("Deprecated server protocol version %d.\n",
task->protocol_version);
transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
ccnet_processor_done (processor, FALSE);
return;
}
if (task->repo_version == 0)
task->protocol_version = 5;
else if (task->protocol_version == 5) {
/* Syncing version 1 reop with 2.x server is not supported.
* Actually version 1 repo can only be created by 3.x servers.
* If version 1 repos exist on 2.x server, it means a down-grade
* operation has been performed, which is not supported.
*/
seaf_warning ("Syncing version %d repo with protocol version %d "
"is not supported.\n",
task->repo_version, task->protocol_version);
transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
ccnet_processor_done (processor, FALSE);
return;
}
if (task->protocol_version >= 7 && !task->server_side_merge)
task->protocol_version = 6;
if (task->protocol_version >= 7 && task->type == TASK_TYPE_DOWNLOAD)
set_download_head_info (task);
seaf_message ("repo version is %d, protocol version is %d.\n",
task->repo_version, task->protocol_version);
ccnet_processor_done (processor, TRUE);
} else {
seaf_warning ("[check tx v3] Bad response: %s %s", code, code_msg);
if (strncmp(code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
else if (strncmp(code, SC_QUOTA_ERROR, 3) == 0)
transfer_task_set_error (task, TASK_ERR_CHECK_QUOTA);
else if (strncmp(code, SC_QUOTA_FULL, 3) == 0)
transfer_task_set_error (task, TASK_ERR_QUOTA_FULL);
else if (strncmp(code, SC_PROTOCOL_MISMATCH, 3) == 0)
transfer_task_set_error (task, TASK_ERR_PROTOCOL_VERSION);
else if (strncmp(code, SC_BAD_REPO, 3) == 0)
transfer_task_set_error (task, TASK_ERR_BAD_REPO_ID);
else
transfer_task_set_error (task, TASK_ERR_UNKNOWN);
ccnet_processor_done (processor, FALSE);
}
}
#endif

View File

@ -1,34 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_CHECK_TX_V3_PROC_H
#define SEAFILE_CHECK_TX_V3_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_CHECK_TX_V3_PROC (seafile_check_tx_v3_proc_get_type ())
#define SEAFILE_CHECK_TX_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECK_TX_V3_PROC, SeafileCheckTxV3Proc))
#define SEAFILE_IS_CHECK_TX_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECK_TX_PROC))
#define SEAFILE_CHECK_TX_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECK_TX_V3_PROC, SeafileCheckTxV3ProcClass))
#define IS_SEAFILE_CHECK_TX_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECK_TX_V3_PROC))
#define SEAFILE_CHECK_TX_V3_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECK_TX_V3_PROC, SeafileCheckTxV3ProcClass))
typedef struct _SeafileCheckTxV3Proc SeafileCheckTxV3Proc;
typedef struct _SeafileCheckTxV3ProcClass SeafileCheckTxV3ProcClass;
struct _SeafileCheckTxV3Proc {
CcnetProcessor parent_instance;
int type;
TransferTask *task;
};
struct _SeafileCheckTxV3ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_check_tx_v3_proc_get_type ();
#endif

View File

@ -1,178 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* checkbl-proc start
* --------------------------->
*
* OK
* <--------------------------
*
* Block list segment 1
* -------------------------->
*
* Non-exist block list
* <-------------------------
*
* Block list segment 2
* -------------------------->
*
* Non-exist block list
* <-------------------------
*
* Block list end
* ------------------------->
*
*/
#define SC_BLOCK_LIST "301"
#define SS_BLOCK_LIST "Block list"
#define SC_NEED_BLOCKS "302"
#define SS_NEED_BLOCKS "Needed blocks"
#define SC_BLOCK_LIST_END "303"
#define SS_BLOCK_LIST_END "Block list end"
#include "checkbl-proc.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
typedef struct {
int offset;
} SeafileCheckblProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProcPriv))
#define USE_PRIV \
SeafileCheckblProcPriv *priv = GET_PRIV(processor);
G_DEFINE_TYPE (SeafileCheckblProc, seafile_checkbl_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
/* FILL IT */
CCNET_PROCESSOR_CLASS (seafile_checkbl_proc_parent_class)->release_resource (processor);
}
static void
seafile_checkbl_proc_class_init (SeafileCheckblProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof (SeafileCheckblProcPriv));
}
static void
seafile_checkbl_proc_init (SeafileCheckblProc *processor)
{
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
SeafileCheckblProc *proc = (SeafileCheckblProc *)processor;
TransferTask *task = proc->task;
GString *buf = g_string_new ("");
if (!proc->send_session_token)
g_string_printf (buf, "remote %s seafile-checkbl", processor->peer_id);
else
g_string_printf (buf, "remote %s seafile-checkbl %s",
processor->peer_id, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
return 0;
}
#define BLOCK_LIST_SEGMENT_N_BLOCKS 120
#define BLOCK_LIST_SEGMENT_LEN 40 * 120
static void
send_block_list_segment (CcnetProcessor *processor, BlockList *block_list)
{
USE_PRIV;
int len, limit;
char buf[BLOCK_LIST_SEGMENT_LEN];
char *ptr;
if (priv->offset == block_list->n_blocks) {
ccnet_processor_send_update (processor, SC_BLOCK_LIST_END, SS_BLOCK_LIST_END,
NULL, 0);
ccnet_processor_done (processor, TRUE);
return;
}
len = MIN (block_list->n_blocks - priv->offset, BLOCK_LIST_SEGMENT_N_BLOCKS);
limit = priv->offset + len;
for (ptr = buf; priv->offset < limit; ++(priv->offset)) {
char *block_id = g_ptr_array_index (block_list->block_ids, priv->offset);
memcpy (ptr, block_id, 40);
ptr += 40;
}
seaf_debug ("Send %d block ids in block list segment.\n", len);
ccnet_processor_send_update (processor, SC_BLOCK_LIST, SS_BLOCK_LIST,
buf, len * 40);
}
static void
process_needed_blocks (CcnetProcessor *processor, TransferTask *task,
char *content, int clen)
{
if (clen == 0) {
seaf_debug ("No block is needed on the server.\n");
return;
}
if (clen % 40 != 0) {
seaf_warning ("Bad block list length %d.\n", clen);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
seaf_debug ("%d blocks are needed by the server.\n", clen/40);
int offset = 0;
while (offset < clen) {
char *block_id = g_new (char, 41);
memcpy (block_id, &content[offset], 40);
block_id[40] = 0;
offset += 40;
g_queue_push_tail (task->block_ids, block_id);
}
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileCheckblProc *proc = (SeafileCheckblProc *)processor;
TransferTask *task = proc->task;
if (memcmp (code, SC_OK, 3) == 0) {
send_block_list_segment (processor, task->block_list);
} else if (memcmp (code, SC_NEED_BLOCKS, 3) == 0) {
process_needed_blocks (processor, task, content, clen);
send_block_list_segment (processor, task->block_list);
} else {
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
}
}

View File

@ -1,35 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_CHECKBL_PROC_H
#define SEAFILE_CHECKBL_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_CHECKBL_PROC (seafile_checkbl_proc_get_type ())
#define SEAFILE_CHECKBL_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProc))
#define SEAFILE_IS_CHECKBL_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECKBL_PROC))
#define SEAFILE_CHECKBL_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProcClass))
#define IS_SEAFILE_CHECKBL_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECKBL_PROC))
#define SEAFILE_CHECKBL_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECKBL_PROC, SeafileCheckblProcClass))
typedef struct _SeafileCheckblProc SeafileCheckblProc;
typedef struct _SeafileCheckblProcClass SeafileCheckblProcClass;
struct _SeafileCheckblProc {
CcnetProcessor parent_instance;
TransferTask *task;
gboolean send_session_token;
};
struct _SeafileCheckblProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_checkbl_proc_get_type ();
#endif

View File

@ -1,68 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include "checkff-proc.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
G_DEFINE_TYPE (SeafileCheckffProc, seafile_checkff_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
/* FILL IT */
CCNET_PROCESSOR_CLASS (seafile_checkff_proc_parent_class)->release_resource (processor);
}
static void
seafile_checkff_proc_class_init (SeafileCheckffProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
}
static void
seafile_checkff_proc_init (SeafileCheckffProc *processor)
{
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
char buf[256];
snprintf (buf, sizeof(buf),
"remote %s seafile-checkff %s %s", processor->peer_id,
argv[0], argv[1]);
ccnet_processor_send_request (processor, buf);
return 0;
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileCheckffProc *proc = (SeafileCheckffProc *)processor;
if (memcmp (code, SC_OK, 3) == 0) {
proc->is_fast_forward = (atoi (content) != 0);
ccnet_processor_done (processor, TRUE);
} else {
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
}
}

View File

@ -1,32 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_CHECKFF_PROC_H
#define SEAFILE_CHECKFF_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#define SEAFILE_TYPE_CHECKFF_PROC (seafile_checkff_proc_get_type ())
#define SEAFILE_CHECKFF_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProc))
#define SEAFILE_IS_CHECKFF_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_CHECKFF_PROC))
#define SEAFILE_CHECKFF_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProcClass))
#define IS_SEAFILE_CHECKFF_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_CHECKFF_PROC))
#define SEAFILE_CHECKFF_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_CHECKFF_PROC, SeafileCheckffProcClass))
typedef struct _SeafileCheckffProc SeafileCheckffProc;
typedef struct _SeafileCheckffProcClass SeafileCheckffProcClass;
struct _SeafileCheckffProc {
CcnetProcessor parent_instance;
gboolean is_fast_forward;
};
struct _SeafileCheckffProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_checkff_proc_get_type ();
#endif

View File

@ -1,290 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <ccnet.h>
#include "utils.h"
#include "seaf-utils.h"
#include "seafile-session.h"
#include "getca-proc.h"
/*
seafile-putca <repo_id> <token>
INIT -------------------------->
OK
<-------------------------
REQUEST_SENT
commit id list
-------------------------->
common ancestor id
<--------------------------
*/
#define SC_ID_LIST "301"
#define SS_ID_LIST "Commit id list"
#define SC_ID_LIST_END "302"
#define SS_ID_LIST_END "Commit id list end"
#define SC_CA "303"
#define SS_CA "Common ancestor"
#define SC_ACCESS_DENIED "401"
#define SS_ACCESS_DENIED "Access denied"
#define SC_NO_CA "404"
#define SS_NO_CA "No common ancestor found"
enum {
INIT,
REQUEST_SENT,
};
typedef struct {
char repo_id[41];
char last_uploaded[41];
char last_checkout[41];
GList *commits;
gboolean success;
} SeafileGetcaProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_GETCA_PROC, SeafileGetcaProcPriv))
#define USE_PRIV \
SeafileGetcaProcPriv *priv = GET_PRIV(processor);
static int get_ca_start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
G_DEFINE_TYPE (SeafileGetcaProc, seafile_getca_proc, CCNET_TYPE_PROCESSOR)
static void
release_resource (CcnetProcessor *processor)
{
USE_PRIV;
if (priv->commits)
string_list_free (priv->commits);
CCNET_PROCESSOR_CLASS (seafile_getca_proc_parent_class)->release_resource (processor);
}
static void
seafile_getca_proc_class_init (SeafileGetcaProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getca-proc";
proc_class->start = get_ca_start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof(SeafileGetcaProcPriv));
}
static void
seafile_getca_proc_init (SeafileGetcaProc *processor)
{
}
static int
get_ca_start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf = g_string_new (NULL);
if (argc < 2) {
ccnet_processor_done (processor, FALSE);
return -1;
}
memcpy (priv->repo_id, argv[0], 36);
g_string_printf (buf, "remote %s seafile-putca %s %s",
processor->peer_id, argv[0], argv[1]);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
return 0;
}
static gboolean
traverse_commits_cb (SeafCommit *commit, void *data, gboolean *stop)
{
CcnetProcessor *processor = data;
USE_PRIV;
/* Add commit id to list, including last_uploaded and last checkout,
* because they can also be the common ancestor.
*/
priv->commits = g_list_prepend (priv->commits, g_strdup(commit->commit_id));
if (strcmp (commit->commit_id, priv->last_uploaded) == 0 ||
strcmp (commit->commit_id, priv->last_checkout) == 0) {
*stop = TRUE;
return TRUE;
}
return TRUE;
}
static void *
list_commits_thread (void *data)
{
CcnetProcessor *processor = data;
USE_PRIV;
char *last_uploaded, *last_checkout;
SeafRepo *repo;
last_uploaded = seaf_repo_manager_get_repo_property (seaf->repo_mgr,
priv->repo_id,
REPO_LOCAL_HEAD);
if (!last_uploaded) {
seaf_warning ("Last uploaded commit id is not found in db.\n");
priv->success = FALSE;
return data;
}
memcpy (priv->last_uploaded, last_uploaded, 40);
g_free (last_uploaded);
last_checkout = seaf_repo_manager_get_repo_property (seaf->repo_mgr,
priv->repo_id,
REPO_REMOTE_HEAD);
if (!last_checkout) {
seaf_warning ("Last checkout commit id is not found in db.\n");
priv->success = FALSE;
return data;
}
memcpy (priv->last_checkout, last_checkout, 40);
g_free (last_checkout);
repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id);
if (!repo) {
seaf_warning ("Failed to find repo %s.\n", priv->repo_id);
priv->success = FALSE;
return data;
}
/* Since we don't download all commits, some commits may be missing.
* But those missing commits (and their ancestors) can't be the common ancestor.
*/
priv->success =
seaf_commit_manager_traverse_commit_tree_truncated (seaf->commit_mgr,
repo->id,
repo->version,
repo->head->commit_id,
traverse_commits_cb,
processor, FALSE);
return data;
}
#define MAX_BUFFER_IDS 500
static void
list_commits_done (void *vdata)
{
CcnetProcessor *processor = vdata;
USE_PRIV;
GString *buf;
if (!priv->success) {
ccnet_processor_done (processor, FALSE);
return;
}
buf = g_string_new ("");
GList *ptr;
char *id;
int n = 0;
priv->commits = g_list_reverse (priv->commits);
for (ptr = priv->commits; ptr; ptr = ptr->next) {
id = ptr->data;
g_string_append (buf, id);
++n;
if (n == MAX_BUFFER_IDS) {
seaf_debug ("Sending %d commit ids.\n", n);
ccnet_processor_send_update (processor, SC_ID_LIST, SS_ID_LIST,
buf->str, buf->len + 1);
n = 0;
g_string_free (buf, TRUE);
buf = g_string_new ("");
}
}
if (n != 0) {
seaf_debug ("Sending %d commit ids.\n", n);
ccnet_processor_send_update (processor, SC_ID_LIST, SS_ID_LIST,
buf->str, buf->len + 1);
}
ccnet_processor_send_update (processor, SC_ID_LIST_END, SS_ID_LIST_END,
NULL, 0);
g_string_free (buf, TRUE);
string_list_free (priv->commits);
priv->commits = NULL;
processor->state = REQUEST_SENT;
}
static void
send_commit_id_list (CcnetProcessor *processor)
{
ccnet_processor_thread_create (processor, seaf->job_mgr,
list_commits_thread, list_commits_done,
processor);
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileGetcaProc *proc = (SeafileGetcaProc *)processor;
USE_PRIV;
switch (processor->state) {
case INIT:
if (strncmp(code, SC_OK, 3) == 0) {
send_commit_id_list (processor);
return;
} else if (strncmp (code, SC_ACCESS_DENIED, 3) == 0) {
seaf_warning ("Access denied to repo %.8s.\n", priv->repo_id);
processor->failure = GETCA_PROC_ACCESS_DENIED;
ccnet_processor_done (processor, FALSE);
return;
}
break;
case REQUEST_SENT:
if (strncmp (code, SC_CA, 3) == 0) {
if (clen != 41) {
seaf_warning ("Bad common ancestor id len %d.\n", clen);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN,
NULL, 0);
ccnet_processor_done (processor, FALSE);
}
memcpy (proc->ca_id, content, 40);
ccnet_processor_done (processor, TRUE);
return;
} else if (strncmp (code, SC_NO_CA, 3) == 0) {
seaf_warning ("No common ancestor found for repo %.8s.\n", priv->repo_id);
processor->failure = GETCA_PROC_NO_CA;
ccnet_processor_done (processor, FALSE);
return;
}
break;
default:
g_return_if_reached ();
}
g_warning ("Bad response: %s %s.\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,35 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETCA_PROC_H
#define SEAFILE_GETCA_PROC_H
#include <glib-object.h>
#define SEAFILE_TYPE_GETCA_PROC (seafile_getca_proc_get_type ())
#define SEAFILE_GETCA_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETCA_PROC, SeafileGetcaProc))
#define SEAFILE_IS_GETCA_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETCA_PROC))
#define SEAFILE_GETCA_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETCA_PROC, SeafileGetcaProcClass))
#define IS_SEAFILE_GETCA_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETCA_PROC))
#define SEAFILE_GETCA_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETCA_PROC, SeafileGetcaProcClass))
typedef struct _SeafileGetcaProc SeafileGetcaProc;
typedef struct _SeafileGetcaProcClass SeafileGetcaProcClass;
/* Error code used in processor->failure */
#define GETCA_PROC_ACCESS_DENIED 401
#define GETCA_PROC_NO_CA 404
struct _SeafileGetcaProc {
CcnetProcessor parent_instance;
char ca_id[41];
};
struct _SeafileGetcaProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getca_proc_get_type ();
#endif

View File

@ -1,250 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <ccnet.h>
#include "net.h"
#include "utils.h"
#include "seaf-utils.h"
#include "seafile-session.h"
#include "getcommit-v2-proc.h"
#include "processors/objecttx-common.h"
/*
seafile-putcommit-v2 <HEAD> [END] (END is empty in clone)
INIT -------------------------->
OK
<-------------------------
Object
FETCH_OBJ <-------------------------
...
End
FETCH_OBJ <--------------------------
*/
enum {
INIT,
RECV_OBJECT
};
typedef struct {
guint32 writer_id;
gboolean recv_ended;
int pending_writes;
} SeafileGetcommitV2ProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_GETCOMMIT_V2_PROC, SeafileGetcommitV2ProcPriv))
#define USE_PRIV \
SeafileGetcommitV2ProcPriv *priv = GET_PRIV(processor);
static int get_commit_start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
G_DEFINE_TYPE (SeafileGetcommitV2Proc, seafile_getcommit_v2_proc, CCNET_TYPE_PROCESSOR)
static void
release_resource (CcnetProcessor *processor)
{
USE_PRIV;
seaf_obj_store_unregister_async_write (seaf->commit_mgr->obj_store,
priv->writer_id);
CCNET_PROCESSOR_CLASS (seafile_getcommit_v2_proc_parent_class)->release_resource (processor);
}
static void
seafile_getcommit_v2_proc_class_init (SeafileGetcommitV2ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getcommit-proc-v2";
proc_class->start = get_commit_start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof(SeafileGetcommitV2ProcPriv));
}
static void
seafile_getcommit_v2_proc_init (SeafileGetcommitV2Proc *processor)
{
}
static void
commit_write_cb (OSAsyncResult *res, void *data);
static int
get_commit_start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf = g_string_new (NULL);
TransferTask *task = ((SeafileGetcommitV2Proc *)processor)->tx_task;
SeafBranch *master = NULL;
char *end_commit_id = NULL;
g_return_val_if_fail (task->session_token, -1);
if (!task->is_clone) {
master = seaf_branch_manager_get_branch (seaf->branch_mgr,
task->repo_id,
"master");
if (master != NULL)
end_commit_id = master->commit_id;
}
/* fs_roots can be non-NULL if transfer is resumed from NET_DOWN. */
if (task->fs_roots != NULL)
object_list_free (task->fs_roots);
task->fs_roots = object_list_new ();
priv->writer_id = seaf_obj_store_register_async_write (seaf->commit_mgr->obj_store,
task->repo_id,
task->repo_version,
commit_write_cb, processor);
if (end_commit_id != NULL)
g_string_printf (buf, "remote %s seafile-putcommit-v2 %s %s %s",
processor->peer_id,
task->head, end_commit_id, task->session_token);
else
g_string_printf (buf, "remote %s seafile-putcommit-v2 %s %s",
processor->peer_id,
task->head, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
seaf_branch_unref (master);
return 0;
}
static void
commit_write_cb (OSAsyncResult *res, void *data)
{
CcnetProcessor *processor = data;
USE_PRIV;
TransferTask *task = ((SeafileGetcommitV2Proc *)processor)->tx_task;
SeafCommit *commit;
if (!res->success) {
seaf_warning ("Failed to write commit %.8s.\n", res->obj_id);
transfer_task_set_error (task, TASK_ERR_DOWNLOAD_COMMIT);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
commit = seaf_commit_from_data (res->obj_id, res->data, res->len);
if (!commit) {
seaf_warning ("[getcommit] Bad commit object received.\n");
transfer_task_set_error (task, TASK_ERR_DOWNLOAD_COMMIT);
ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
object_list_insert (task->fs_roots, commit->root_id);
seaf_commit_unref (commit);
if (--(priv->pending_writes) == 0 && priv->recv_ended)
ccnet_processor_done (processor, TRUE);
}
static int
save_commit (CcnetProcessor *processor, ObjectPack *pack, int len)
{
USE_PRIV;
int rc = seaf_obj_store_async_write (seaf->commit_mgr->obj_store,
priv->writer_id,
pack->id,
pack->object,
len - 41,
FALSE);
++(priv->pending_writes);
return rc;
}
static void
receive_commit (CcnetProcessor *processor, char *content, int clen)
{
ObjectPack *pack = (ObjectPack *)content;
if (clen < sizeof(ObjectPack)) {
seaf_warning ("[getcommit] invalid object id.\n");
goto bad;
}
seaf_debug ("[getcommit] recv commit object %.8s\n", pack->id);
if (save_commit (processor, pack, clen) < 0) {
goto bad;
}
return;
bad:
seaf_warning ("[getcommit] Bad commit object received.\n");
transfer_task_set_error (((SeafileGetcommitV2Proc *)processor)->tx_task,
TASK_ERR_DOWNLOAD_COMMIT);
ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
NULL, 0);
ccnet_processor_done (processor, FALSE);
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileGetcommitV2Proc *proc = (SeafileGetcommitV2Proc *)processor;
USE_PRIV;
if (proc->tx_task->state != TASK_STATE_NORMAL) {
ccnet_processor_done (processor, TRUE);
return;
}
switch (processor->state) {
case INIT:
if (strncmp(code, SC_OK, 3) == 0) {
processor->state = RECV_OBJECT;
return;
}
break;
case RECV_OBJECT:
if (strncmp(code, SC_OBJECT, 3) == 0) {
receive_commit (processor, content, clen);
return;
} else if (strncmp (code, SC_END, 3) == 0) {
seaf_debug ("[getcommit] Get commit end.\n");
priv->recv_ended = TRUE;
if (priv->pending_writes == 0)
ccnet_processor_done (processor, TRUE);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,31 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETCOMMIT_V2_PROC_H
#define SEAFILE_GETCOMMIT_V2_PROC_H
#include <glib-object.h>
#define SEAFILE_TYPE_GETCOMMIT_V2_PROC (seafile_getcommit_v2_proc_get_type ())
#define SEAFILE_GETCOMMIT_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETCOMMIT_V2_PROC, SeafileGetcommitV2Proc))
#define SEAFILE_IS_GETCOMMIT_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETCOMMIT_V2_PROC))
#define SEAFILE_GETCOMMIT_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETCOMMIT_V2_PROC, SeafileGetcommitV2ProcClass))
#define IS_SEAFILE_GETCOMMIT_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETCOMMIT_V2_PROC))
#define SEAFILE_GETCOMMIT_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETCOMMIT_V2_PROC, SeafileGetcommitV2ProcClass))
typedef struct _SeafileGetcommitV2Proc SeafileGetcommitV2Proc;
typedef struct _SeafileGetcommitV2ProcClass SeafileGetcommitV2ProcClass;
struct _SeafileGetcommitV2Proc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileGetcommitV2ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getcommit_v2_proc_get_type ();
#endif

View File

@ -1,201 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <ccnet.h>
#include "net.h"
#include "utils.h"
#include "seaf-utils.h"
#include "seafile-session.h"
#include "getcommit-v3-proc.h"
#include "processors/objecttx-common.h"
/*
seafile-putcommit-v3 <HEAD>
INIT -------------------------->
Object
<-------------------------
*/
typedef struct {
guint32 writer_id;
} SeafileGetcommitV3ProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_GETCOMMIT_V3_PROC, SeafileGetcommitV3ProcPriv))
#define USE_PRIV \
SeafileGetcommitV3ProcPriv *priv = GET_PRIV(processor);
static int get_commit_start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
G_DEFINE_TYPE (SeafileGetcommitV3Proc, seafile_getcommit_v3_proc, CCNET_TYPE_PROCESSOR)
static void
release_resource (CcnetProcessor *processor)
{
USE_PRIV;
seaf_obj_store_unregister_async_write (seaf->commit_mgr->obj_store,
priv->writer_id);
CCNET_PROCESSOR_CLASS (seafile_getcommit_v3_proc_parent_class)->release_resource (processor);
}
static void
seafile_getcommit_v3_proc_class_init (SeafileGetcommitV3ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getcommit-proc-v3";
proc_class->start = get_commit_start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof(SeafileGetcommitV3ProcPriv));
}
static void
seafile_getcommit_v3_proc_init (SeafileGetcommitV3Proc *processor)
{
}
static void
commit_write_cb (OSAsyncResult *res, void *data);
static int
get_commit_start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf = g_string_new (NULL);
TransferTask *task = ((SeafileGetcommitV3Proc *)processor)->tx_task;
SeafBranch *master = NULL;
g_return_val_if_fail (task->session_token, -1);
/* fs_roots can be non-NULL if transfer is resumed from NET_DOWN. */
if (task->fs_roots != NULL)
object_list_free (task->fs_roots);
task->fs_roots = object_list_new ();
priv->writer_id = seaf_obj_store_register_async_write (seaf->commit_mgr->obj_store,
task->repo_id,
task->repo_version,
commit_write_cb, processor);
g_string_printf (buf, "remote %s seafile-putcommit-v3 %s %s",
processor->peer_id,
task->head, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
seaf_branch_unref (master);
return 0;
}
static void
commit_write_cb (OSAsyncResult *res, void *data)
{
CcnetProcessor *processor = data;
TransferTask *task = ((SeafileGetcommitV3Proc *)processor)->tx_task;
SeafCommit *commit;
if (!res->success) {
seaf_warning ("Failed to write commit %.8s.\n", res->obj_id);
transfer_task_set_error (task, TASK_ERR_DOWNLOAD_COMMIT);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
commit = seaf_commit_from_data (res->obj_id, res->data, res->len);
if (!commit) {
seaf_warning ("[getcommit] Bad commit object received.\n");
transfer_task_set_error (task, TASK_ERR_DOWNLOAD_COMMIT);
ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
object_list_insert (task->fs_roots, commit->root_id);
seaf_commit_unref (commit);
ccnet_processor_done (processor, TRUE);
}
static int
save_commit (CcnetProcessor *processor, ObjectPack *pack, int len)
{
USE_PRIV;
int rc = seaf_obj_store_async_write (seaf->commit_mgr->obj_store,
priv->writer_id,
pack->id,
pack->object,
len - 41,
FALSE);
return rc;
}
static void
receive_commit (CcnetProcessor *processor, char *content, int clen)
{
ObjectPack *pack = (ObjectPack *)content;
if (clen < sizeof(ObjectPack)) {
seaf_warning ("[getcommit] invalid object id.\n");
goto bad;
}
seaf_debug ("[getcommit] recv commit object %.8s\n", pack->id);
if (save_commit (processor, pack, clen) < 0) {
goto bad;
}
return;
bad:
seaf_warning ("[getcommit] Bad commit object received.\n");
transfer_task_set_error (((SeafileGetcommitV3Proc *)processor)->tx_task,
TASK_ERR_DOWNLOAD_COMMIT);
ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
NULL, 0);
ccnet_processor_done (processor, FALSE);
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileGetcommitV3Proc *proc = (SeafileGetcommitV3Proc *)processor;
if (proc->tx_task->state != TASK_STATE_NORMAL) {
ccnet_processor_done (processor, TRUE);
return;
}
if (strncmp(code, SC_OK, 3) == 0) {
receive_commit (processor, content, clen);
return;
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,31 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETCOMMIT_V3_PROC_H
#define SEAFILE_GETCOMMIT_V3_PROC_H
#include <glib-object.h>
#define SEAFILE_TYPE_GETCOMMIT_V3_PROC (seafile_getcommit_v3_proc_get_type ())
#define SEAFILE_GETCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETCOMMIT_V3_PROC, SeafileGetcommitV3Proc))
#define SEAFILE_IS_GETCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETCOMMIT_V3_PROC))
#define SEAFILE_GETCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETCOMMIT_V3_PROC, SeafileGetcommitV3ProcClass))
#define IS_SEAFILE_GETCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETCOMMIT_V3_PROC))
#define SEAFILE_GETCOMMIT_V3_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETCOMMIT_V3_PROC, SeafileGetcommitV3ProcClass))
typedef struct _SeafileGetcommitV3Proc SeafileGetcommitV3Proc;
typedef struct _SeafileGetcommitV3ProcClass SeafileGetcommitV3ProcClass;
struct _SeafileGetcommitV3Proc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileGetcommitV3ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getcommit_v3_proc_get_type ();
#endif

View File

@ -1,143 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <ccnet.h>
#include "seafile-session.h"
#include "utils.h"
#include "db.h"
#include "getcs-proc.h"
#include "log.h"
G_DEFINE_TYPE (SeafileGetcsProc, seafile_getcs_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
CCNET_PROCESSOR_CLASS (seafile_getcs_proc_parent_class)->release_resource (processor);
}
static void
seafile_getcs_proc_class_init (SeafileGetcsProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getcs-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
}
static void
seafile_getcs_proc_init (SeafileGetcsProc *processor)
{
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
char buf[256];
snprintf (buf, 256, "remote %s seafile-putcs", processor->peer_id);
ccnet_processor_send_request (processor, buf);
return 0;
}
static gint
peer_cmp_func (gconstpointer a, gconstpointer b)
{
const char *id_a = a;
const char *id_b = b;
return (g_strcmp0(id_a, id_b));
}
static void
add_chunk_server (CcnetProcessor *processor, TransferTask *task, char *cs_str)
{
int num;
char *cs_id;
char **tokens;
tokens = strsplit_by_space (cs_str, &num);
if (num < 1)
return;
cs_id = tokens[0];
if (g_list_find_custom (task->chunk_servers, cs_id, peer_cmp_func) != NULL)
goto out;
if (strcmp (cs_id, processor->peer_id) == 0) {
CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client,
processor->peer_id);
g_return_if_fail (peer != NULL);
if (!peer->public_addr) {
seaf_warning ("Public address of relay %s is not set.\n", cs_id);
g_object_unref (peer);
goto out;
}
task->chunk_servers = g_list_prepend (task->chunk_servers,
g_strdup(cs_id));
g_object_unref (peer);
goto out;
}
ccnet_add_peer (processor->session, tokens[0], tokens[1]);
task->chunk_servers = g_list_prepend (task->chunk_servers, g_strdup(cs_id));
out:
free (tokens);
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileGetcsProc *proc = (SeafileGetcsProc *)processor;
char *cs_str;
if (proc->task->state != TASK_STATE_NORMAL) {
g_debug ("Task not running, get-cs proc exits.\n");
ccnet_processor_done (processor, FALSE);
return;
}
if (memcmp (code, SC_OK, 3) != 0) {
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
return;
}
if (content[clen-1] != '\0') {
seaf_warning ("Bad chunk server list format.\n");
ccnet_processor_done (processor, FALSE);
return;
}
cs_str = strtok (content, "\n");
if (cs_str != NULL) {
add_chunk_server (processor, proc->task, cs_str);
} else {
ccnet_processor_done (processor, TRUE);
return;
}
while ((cs_str = strtok(NULL, "\n")) != NULL)
add_chunk_server (processor, proc->task, cs_str);
ccnet_processor_done (processor, TRUE);
}

View File

@ -1,33 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETCS_PROC_H
#define SEAFILE_GETCS_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_GETCS_PROC (seafile_getcs_proc_get_type ())
#define SEAFILE_GETCS_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETCS_PROC, SeafileGetcsProc))
#define SEAFILE_IS_GETCS_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETCS_PROC))
#define SEAFILE_GETCS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETCS_PROC, SeafileGetcsProcClass))
#define IS_SEAFILE_GETCS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETCS_PROC))
#define SEAFILE_GETCS_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETCS_PROC, SeafileGetcsProcClass))
typedef struct _SeafileGetcsProc SeafileGetcsProc;
typedef struct _SeafileGetcsProcClass SeafileGetcsProcClass;
struct _SeafileGetcsProc {
CcnetProcessor parent_instance;
TransferTask *task;
};
struct _SeafileGetcsProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getcs_proc_get_type ();
#endif

View File

@ -1,142 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <ccnet.h>
#include "seafile-session.h"
#include "utils.h"
#include "getcs-v2-proc.h"
#include "log.h"
G_DEFINE_TYPE (SeafileGetcsV2Proc, seafile_getcs_v2_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
CCNET_PROCESSOR_CLASS (seafile_getcs_v2_proc_parent_class)->release_resource (processor);
}
static void
seafile_getcs_v2_proc_class_init (SeafileGetcsV2ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getcs-v2-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
}
static void
seafile_getcs_v2_proc_init (SeafileGetcsV2Proc *processor)
{
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
char buf[256];
snprintf (buf, 256, "remote %s seafile-putcs-v2", processor->peer_id);
ccnet_processor_send_request (processor, buf);
return 0;
}
static int
add_chunk_server (CcnetProcessor *processor, TransferTask *task, char *cs_str)
{
char **tokens;
CcnetPeer *peer;
ChunkServer *cs;
tokens = g_strsplit (cs_str, ":", -1);
if (g_strv_length (tokens) != 2) {
seaf_warning ("Invalid chunk server address format: %s.\n", cs_str);
g_strfreev (tokens);
return -1;
}
peer = ccnet_get_peer (seaf->ccnetrpc_client, processor->peer_id);
if (!peer) {
seaf_warning ("[getcs] Invalid peer %s.\n", processor->peer_id);
g_strfreev (tokens);
return -1;
}
if (!peer->addr_str) {
seaf_warning ("[getcs] Peer doesn't have an address.\n");
g_object_unref (peer);
g_strfreev (tokens);
return -1;
}
cs = g_new0 (ChunkServer, 1);
cs->addr = g_strdup (peer->addr_str);
cs->port = atoi (tokens[1]);
task->chunk_servers = g_list_prepend (task->chunk_servers, cs);
g_strfreev (tokens);
g_object_unref (peer);
return 0;
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileGetcsV2Proc *proc = (SeafileGetcsV2Proc *)processor;
char *cs_str;
if (proc->task->state != TASK_STATE_NORMAL) {
g_debug ("Task not running, get-cs proc exits.\n");
ccnet_processor_done (processor, FALSE);
return;
}
if (memcmp (code, SC_OK, 3) != 0) {
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
return;
}
if (content[clen-1] != '\0') {
seaf_warning ("Bad chunk server list format.\n");
ccnet_processor_done (processor, FALSE);
return;
}
cs_str = strtok (content, "\n");
if (cs_str != NULL) {
if (add_chunk_server (processor, proc->task, cs_str) < 0)
goto error;
} else {
ccnet_processor_done (processor, TRUE);
return;
}
while ((cs_str = strtok(NULL, "\n")) != NULL) {
if (add_chunk_server (processor, proc->task, cs_str) < 0)
goto error;
}
ccnet_processor_done (processor, TRUE);
error:
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,33 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETCS_V2_PROC_H
#define SEAFILE_GETCS_V2_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_GETCS_V2_PROC (seafile_getcs_v2_proc_get_type ())
#define SEAFILE_GETCS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETCS_V2_PROC, SeafileGetcsV2Proc))
#define SEAFILE_IS_GETCS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETCS_V2_PROC))
#define SEAFILE_GETCS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETCS_V2_PROC, SeafileGetcsV2ProcClass))
#define IS_SEAFILE_GETCS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETCS_V2_PROC))
#define SEAFILE_GETCS_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETCS_V2_PROC, SeafileGetcsV2ProcClass))
typedef struct _SeafileGetcsV2Proc SeafileGetcsV2Proc;
typedef struct _SeafileGetcsV2ProcClass SeafileGetcsV2ProcClass;
struct _SeafileGetcsV2Proc {
CcnetProcessor parent_instance;
TransferTask *task;
};
struct _SeafileGetcsV2ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getcs_v2_proc_get_type ();
#endif

View File

@ -1,602 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <ccnet.h>
#include "utils.h"
#include "seaf-utils.h"
#include "seafile-session.h"
#include "commit-mgr.h"
#include "fs-mgr.h"
#include "processors/objecttx-common.h"
#include "getfs-proc.h"
#include "transfer-mgr.h"
/*
* Implementation Notes:
*
* Checking and writing of fs objects are completely asynchronous in this processor.
* - FS object checking is done by a worker thread.
* - Writing of received fs objects is done with the async obj-store API.
*
* At the beginning, all root object id is put into inspect queue. And then
* We start a worker thread to check the first object in the inspect queue.
*
* After the worker thread is done, we send object requests in the main thread.
* And then we start a worker to check the next object in the inspect queue.
*
* After an object is received and store asynchronously into disk, and if the object
* is a directory, we put it into the inspect queue. And then we start a worker
* to check the next object in the inspect queue, if no worker is running.
* This means only 1 worker can be running at the same time. Because we use thread
* pool, there will be no performance problem of creating threads.
*
* The end condition is checked after:
* - worker thread is done
* - an object is written
* The end condition is
* - inspect queue is empty, and
* - no object request is pending, and
* - no worker is running
*/
#define MAX_NUM_BATCH 64
enum {
REQUEST_SENT,
FETCH_OBJECT
};
typedef struct ThreadData {
gint refcnt;
CcnetProcessor *processor;
gboolean is_clone;
int cmd_pipe;
uint32_t cevent_id;
char root_id[41];
GHashTable *fs_objects;
GList *fetch_objs;
char repo_id[37];
int repo_version;
} ThreadData;
typedef struct {
gboolean worker_checking;
gboolean worker_started;
GQueue *inspect_queue; /* objects to check exists */
int pending_objects;
guint32 writer_id;
/* Used by worker thread */
int cmd_pipe[2];
uint32_t cevent_id;
ThreadData *tdata;
char buf[4096];
char *bufptr;
int n_batch;
char *obj_seg;
int obj_seg_len;
} SeafileGetfsProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_GETFS_PROC, SeafileGetfsProcPriv))
#define USE_PRIV \
SeafileGetfsProcPriv *priv = GET_PRIV(processor);
G_DEFINE_TYPE (SeafileGetfsProc, seafile_getfs_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
thread_data_ref (ThreadData *tdata)
{
g_atomic_int_inc (&tdata->refcnt);
}
static void
thread_data_unref (ThreadData *tdata)
{
if (g_atomic_int_dec_and_test (&tdata->refcnt)) {
if (tdata->fetch_objs)
string_list_free (tdata->fetch_objs);
if (tdata->fs_objects)
g_hash_table_destroy (tdata->fs_objects);
g_free (tdata);
}
}
static void
release_resource(CcnetProcessor *processor)
{
USE_PRIV;
g_queue_free (priv->inspect_queue);
g_free (priv->obj_seg);
seaf_obj_store_unregister_async_write (seaf->fs_mgr->obj_store, priv->writer_id);
if (priv->worker_started) {
/* The worker thread will notice the command pipe has been closed and exits.
*/
pipeclose (priv->cmd_pipe[1]);
cevent_manager_unregister (seaf->ev_mgr, priv->cevent_id);
thread_data_unref (priv->tdata);
}
CCNET_PROCESSOR_CLASS (seafile_getfs_proc_parent_class)->release_resource (processor);
}
static void
seafile_getfs_proc_class_init (SeafileGetfsProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getfs-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof (SeafileGetfsProcPriv));
}
static void
seafile_getfs_proc_init (SeafileGetfsProc *processor)
{
}
inline static void
request_object_batch_begin (SeafileGetfsProcPriv *priv)
{
priv->bufptr = priv->buf;
priv->n_batch = 0;
}
inline static void
request_object_batch_flush (CcnetProcessor *processor,
SeafileGetfsProcPriv *priv)
{
if (priv->bufptr == priv->buf)
return;
*priv->bufptr = '\0'; /* add ending '\0' */
priv->bufptr++;
ccnet_processor_send_update (processor, SC_GET_OBJECT, SS_GET_OBJECT,
priv->buf, priv->bufptr - priv->buf);
/* Clean state */
priv->n_batch = 0;
priv->bufptr = priv->buf;
}
inline static void
request_object_batch (CcnetProcessor *processor,
SeafileGetfsProcPriv *priv,
const char *id)
{
memcpy (priv->bufptr, id, 40);
priv->bufptr += 40;
*priv->bufptr = '\n';
priv->bufptr++;
if (++priv->n_batch == MAX_NUM_BATCH)
request_object_batch_flush (processor, priv);
++priv->pending_objects;
}
/*
* Recursively check fs tree rooted at @dir_id. This function returns when
* all non-existent or invalid objects have been put into data->fetch_objs.
*/
static void
check_seafdir (ThreadData *tdata, const char *dir_id)
{
SeafDir *dir = NULL;
GList *ptr;
SeafDirent *dent;
if (!seaf_fs_manager_object_exists(seaf->fs_mgr,
tdata->repo_id,
tdata->repo_version,
dir_id)) {
tdata->fetch_objs = g_list_prepend (tdata->fetch_objs, g_strdup(dir_id));
return;
}
dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr,
tdata->repo_id,
tdata->repo_version,
dir_id);
if (!dir) {
/* corrupt dir object */
tdata->fetch_objs = g_list_prepend (tdata->fetch_objs, g_strdup(dir_id));
return;
}
for (ptr = dir->entries; ptr; ptr = ptr->next) {
dent = ptr->data;
/* Don't check objects that have been checked before. */
if (g_hash_table_lookup (tdata->fs_objects, dent->id))
continue;
g_hash_table_insert (tdata->fs_objects, g_strdup(dent->id), (gpointer)1);
if (!seaf_fs_manager_object_exists(seaf->fs_mgr,
tdata->repo_id,
tdata->repo_version,
dent->id)) {
tdata->fetch_objs = g_list_prepend (tdata->fetch_objs, g_strdup(dent->id));
continue;
}
if (S_ISDIR(dent->mode)) {
check_seafdir (tdata, dent->id);
} else if (S_ISREG (dent->mode) && tdata->is_clone) {
/* Only check seafile object integrity when clone.
* This is for the purpose of recovery.
* In ordinary sync, checking every file object's integrity would
* take too much CPU time.
*/
gboolean ok;
gboolean err = FALSE;
ok = seaf_fs_manager_verify_seafile (seaf->fs_mgr,
tdata->repo_id,
tdata->repo_version,
dent->id, TRUE, &err);
if (!ok && !err) {
seaf_warning ("File object %.8s is corrupt, recover from server.\n",
dent->id);
tdata->fetch_objs = g_list_prepend (tdata->fetch_objs, g_strdup(dent->id));
}
}
}
seaf_dir_free (dir);
}
static gboolean
check_end_condition (SeafileGetfsProcPriv *priv)
{
return (g_queue_get_length (priv->inspect_queue) == 0 &&
priv->pending_objects == 0 &&
!priv->worker_checking);
}
static int
check_fs_tree_from (ThreadData *tdata, const char *root_id);
static void
end_or_check_next_dir (CcnetProcessor *processor, SeafileGetfsProcPriv *priv)
{
if (check_end_condition (priv)) {
seaf_debug ("Get fs end.\n");
ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
ccnet_processor_done (processor, TRUE);
return;
}
if (priv->worker_checking) {
return;
}
/* Trigger checking the next dir. */
char *next_dir_id = g_queue_pop_head (priv->inspect_queue);
if (next_dir_id) {
if (check_fs_tree_from (priv->tdata, next_dir_id) < 0) {
transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task,
TASK_ERR_DOWNLOAD_FS);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
}
g_free (next_dir_id);
}
}
static void *
check_objects_thread (void *vdata)
{
ThreadData *tdata = vdata;
int cmd;
/* Hold one reference for worker thread. */
thread_data_ref (tdata);
while (1) {
int n = piperead (tdata->cmd_pipe, (char*)&cmd, sizeof(cmd));
if (n < 0) {
seaf_warning ("Failed to read commnd pipe: %s.\n", strerror(errno));
goto out;
}
if (n == 0) {
seaf_message ("Getfs proc is done, worker thread exits.\n");
goto out;
}
check_seafdir (tdata, tdata->root_id);
cevent_manager_add_event (seaf->ev_mgr, tdata->cevent_id, tdata);
}
out:
pipeclose (tdata->cmd_pipe);
thread_data_unref (tdata);
return vdata;
}
static void
check_objects_done (CEvent *event, void *unused)
{
ThreadData *tdata = event->data;
CcnetProcessor *processor = tdata->processor;
USE_PRIV;
GList *ptr;
char *obj_id;
priv->worker_checking = FALSE;
request_object_batch_begin (priv);
for (ptr = tdata->fetch_objs; ptr; ptr = ptr->next) {
obj_id = ptr->data;
request_object_batch (processor, priv, obj_id);
g_free (obj_id);
}
request_object_batch_flush (processor, priv);
g_list_free (tdata->fetch_objs);
tdata->fetch_objs = NULL;
end_or_check_next_dir (processor, priv);
}
static int
check_fs_tree_from (ThreadData *tdata, const char *root_id)
{
CcnetProcessor *processor = tdata->processor;
USE_PRIV;
memcpy (tdata->root_id, root_id, 40);
tdata->fetch_objs = NULL;
int cmd = 1;
pipewrite (priv->cmd_pipe[1], (char*)&cmd, sizeof(cmd));
priv->worker_checking = TRUE;
return 0;
}
static void
fs_object_write_cb (OSAsyncResult *res, void *data)
{
CcnetProcessor *processor = data;
TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task;
USE_PRIV;
if (!res->success) {
seaf_warning ("Failed to write object %.8s.\n", res->obj_id);
transfer_task_set_error (task, TASK_ERR_DOWNLOAD_FS);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
seaf_debug ("Written object %.8s.\n", res->obj_id);
--(priv->pending_objects);
int type = seaf_metadata_type_from_data (res->obj_id, res->data, res->len,
(task->repo_version > 0));
if (type == SEAF_METADATA_TYPE_DIR)
g_queue_push_tail (priv->inspect_queue, g_strdup(res->obj_id));
end_or_check_next_dir (processor, priv);
}
static int
save_fs_object (SeafileGetfsProcPriv *priv, ObjectPack *pack, int len)
{
return seaf_obj_store_async_write (seaf->fs_mgr->obj_store,
priv->writer_id,
pack->id,
pack->object,
len - 41,
FALSE);
}
static int
recv_fs_object (CcnetProcessor *processor, char *content, int clen)
{
USE_PRIV;
ObjectPack *pack = (ObjectPack *)content;
/* TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task; */
if (clen < sizeof(ObjectPack)) {
seaf_warning ("[getfs] invalid object id.\n");
goto bad;
}
/* TODO: check fs object integrity. */
if (save_fs_object (priv, pack, clen) < 0) {
goto bad;
}
return 0;
bad:
seaf_warning ("Bad fs object received.\n");
transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task,
TASK_ERR_DOWNLOAD_FS);
ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return -1;
}
static void
recv_fs_object_seg (CcnetProcessor *processor, char *content, int clen)
{
USE_PRIV;
/* Append the received object segment to the end */
priv->obj_seg = g_realloc (priv->obj_seg, priv->obj_seg_len + clen);
memcpy (priv->obj_seg + priv->obj_seg_len, content, clen);
seaf_debug ("Get obj seg: <id= %40s, offset= %d, lenth= %d>\n",
priv->obj_seg, priv->obj_seg_len, clen);
priv->obj_seg_len += clen;
}
static void
process_fs_object_seg (CcnetProcessor *processor)
{
USE_PRIV;
if (recv_fs_object (processor, priv->obj_seg, priv->obj_seg_len) == 0) {
g_free (priv->obj_seg);
priv->obj_seg = NULL;
priv->obj_seg_len = 0;
}
}
static int
start_worker_thread (CcnetProcessor *processor)
{
SeafileGetfsProc *proc = (SeafileGetfsProc *)processor;
USE_PRIV;
ThreadData *tdata;
if (ccnet_pipe (priv->cmd_pipe) < 0)
return -1;
priv->cevent_id = cevent_manager_register (seaf->ev_mgr,
check_objects_done,
processor);
tdata = g_new0 (ThreadData, 1);
tdata->cmd_pipe = priv->cmd_pipe[0];
tdata->cevent_id = priv->cevent_id;
tdata->processor = processor;
tdata->is_clone = proc->tx_task->is_clone;
tdata->fs_objects = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
memcpy (tdata->repo_id, proc->tx_task->repo_id, 36);
tdata->repo_version = proc->tx_task->repo_version;
/* Hold one reference for the main thread. */
thread_data_ref (tdata);
priv->tdata = tdata;
ccnet_job_manager_schedule_job (seaf->job_mgr,
check_objects_thread,
NULL,
tdata);
priv->worker_started = TRUE;
return 0;
}
static void
load_fsroot_list (CcnetProcessor *processor)
{
USE_PRIV;
SeafileGetfsProc *proc = (SeafileGetfsProc *) processor;
ObjectList *ol = proc->tx_task->fs_roots;
int i;
int ollen = object_list_length (ol);
for (i = 0; i < ollen; i++) {
g_queue_push_tail (priv->inspect_queue,
g_strdup(g_ptr_array_index(ol->obj_ids, i)));
}
/* Kick start fs object checking. */
end_or_check_next_dir (processor, priv);
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileGetfsProc *proc = (SeafileGetfsProc *)processor;
TransferTask *task = proc->tx_task;
switch (processor->state) {
case REQUEST_SENT:
if (strncmp(code, SC_OK, 3) == 0) {
if (start_worker_thread (processor) < 0) {
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
load_fsroot_list (processor);
processor->state = FETCH_OBJECT;
return;
}
break;
case FETCH_OBJECT:
if (strncmp(code, SC_OBJ_SEG, 3) == 0) {
recv_fs_object_seg (processor, content, clen);
return;
} else if (strncmp(code, SC_OBJ_SEG_END, 3) == 0) {
recv_fs_object_seg (processor, content, clen);
process_fs_object_seg (processor);
return;
} else if (strncmp(code, SC_OBJECT, 3) == 0) {
recv_fs_object (processor, content, clen);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task;
GString *buf = g_string_new (NULL);
if (task->session_token)
g_string_printf (buf, "remote %s seafile-putfs %s",
processor->peer_id, task->session_token);
else
g_string_printf (buf, "remote %s seafile-putfs",
processor->peer_id);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
processor->state = REQUEST_SENT;
priv->inspect_queue = g_queue_new ();
priv->writer_id = seaf_obj_store_register_async_write (seaf->fs_mgr->obj_store,
task->repo_id,
task->repo_version,
fs_object_write_cb,
processor);
return 0;
}

View File

@ -1,32 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETFS_PROC_H
#define SEAFILE_GETFS_PROC_H
#include <glib-object.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_GETFS_PROC (seafile_getfs_proc_get_type ())
#define SEAFILE_GETFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETFS_PROC, SeafileGetfsProc))
#define SEAFILE_IS_GETFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETFS_PROC))
#define SEAFILE_GETFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETFS_PROC, SeafileGetfsProcClass))
#define IS_SEAFILE_GETFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETFS_PROC))
#define SEAFILE_GETFS_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETFS_PROC, SeafileGetfsProcClass))
typedef struct _SeafileGetfsProc SeafileGetfsProc;
typedef struct _SeafileGetfsProcClass SeafileGetfsProcClass;
struct _SeafileGetfsProc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileGetfsProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getfs_proc_get_type ();
#endif

View File

@ -1,443 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ccnet.h>
#include "utils.h"
#include "seafile-session.h"
#include "fs-mgr.h"
#include "processors/objecttx-common.h"
#include "getfs-v2-proc.h"
#include "seaf-utils.h"
/*
* putfs-v2-proc server-head-id [client-head-id]
* ------------------------------>
* OK
* <-----------------------------
*
* The server uses diff to calculate objects to put
*
* SC_OBJ_LIST_SEG
* <-----------------------------
* ......
* SC_OBJ_LIST_SEG_END
* <-----------------------------
*
* The client calculates the list of objects to get
*
* SC_OBJ_LIST_SEG
* ----------------------------->
* ......
* SC_OBJ
* <----------------------------
* ......
* SC_END
* ----------------------------->
*
* After all objects are written to disk, the client ends the protocol
*/
enum {
INIT = 0,
CHECK_OBJECT_LIST,
GET_OBJECTS,
};
typedef struct {
char *obj_seg;
int obj_seg_len;
gboolean registered;
guint32 writer_id;
/* Used to check object list */
GList *recv_objs;
GList *needed_objs;
int n_pending;
int n_saved;
} SeafileGetfsProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_GETFS_V2_PROC, SeafileGetfsProcPriv))
#define USE_PRIV \
SeafileGetfsProcPriv *priv = GET_PRIV(processor);
G_DEFINE_TYPE (SeafileGetfsV2Proc, seafile_getfs_v2_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
USE_PRIV;
g_free (priv->obj_seg);
if (priv->registered) {
seaf_obj_store_unregister_async_write (seaf->fs_mgr->obj_store,
priv->writer_id);
}
string_list_free (priv->recv_objs);
string_list_free (priv->needed_objs);
CCNET_PROCESSOR_CLASS (seafile_getfs_v2_proc_parent_class)->release_resource (processor);
}
static void
seafile_getfs_v2_proc_class_init (SeafileGetfsV2ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "getfs-v2-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof (SeafileGetfsProcPriv));
}
static void
seafile_getfs_v2_proc_init (SeafileGetfsV2Proc *processor)
{
}
static void
on_fs_write (OSAsyncResult *res, void *cb_data);
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf;
SeafileGetfsV2Proc *proc = (SeafileGetfsV2Proc *)processor;
TransferTask *task = proc->tx_task;
buf = g_string_new (NULL);
if (!task->is_clone) {
SeafBranch *master = seaf_branch_manager_get_branch (seaf->branch_mgr,
task->repo_id,
"master");
if (!master) {
seaf_warning ("Master branch not found for repo %s.\n", task->repo_id);
g_string_free (buf, TRUE);
ccnet_processor_done (processor, FALSE);
return -1;
}
g_string_printf (buf, "remote %s seafile-putfs-v2 %s %s %s",
processor->peer_id, task->session_token,
task->head, master->commit_id);
seaf_branch_unref (master);
} else
g_string_printf (buf, "remote %s seafile-putfs-v2 %s %s",
processor->peer_id, task->session_token,
task->head);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
priv->registered = TRUE;
priv->writer_id = seaf_obj_store_register_async_write (seaf->fs_mgr->obj_store,
task->repo_id,
task->repo_version,
on_fs_write,
processor);
return 0;
}
static void
send_object_list_segment (CcnetProcessor *processor);
static void
on_fs_write (OSAsyncResult *res, void *cb_data)
{
CcnetProcessor *processor = cb_data;
USE_PRIV;
if (!res->success) {
seaf_warning ("[getfs] Failed to write %s.\n", res->obj_id);
ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
seaf_debug ("[getfs] Wrote fs object %s.\n", res->obj_id);
if (++(priv->n_saved) == priv->n_pending)
send_object_list_segment (processor);
}
static int
save_fs_object (CcnetProcessor *processor, ObjectPack *pack, int len)
{
USE_PRIV;
return seaf_obj_store_async_write (seaf->fs_mgr->obj_store,
priv->writer_id,
pack->id,
pack->object,
len - 41,
FALSE);
}
static int
recv_fs_object (CcnetProcessor *processor, char *content, int clen)
{
ObjectPack *pack = (ObjectPack *)content;
/* SeafFSObject *fs_obj = NULL; */
if (clen < sizeof(ObjectPack)) {
seaf_warning ("invalid object id.\n");
goto bad;
}
seaf_debug ("[getfs] Recv fs object %.8s.\n", pack->id);
/* Check object integrity by parsing it. */
/* fs_obj = seaf_fs_object_from_data(pack->id, */
/* pack->object, clen - sizeof(ObjectPack), */
/* (priv->repo_version > 0)); */
/* if (!fs_obj) { */
/* seaf_warning ("Bad fs object %s.\n", pack->id); */
/* goto bad; */
/* } */
/* seaf_fs_object_free (fs_obj); */
if (save_fs_object (processor, pack, clen) < 0) {
goto bad;
}
return 0;
bad:
ccnet_processor_send_update (processor, SC_BAD_OBJECT,
SS_BAD_OBJECT, NULL, 0);
seaf_warning ("[getfs] Bad fs object received.\n");
ccnet_processor_done (processor, FALSE);
/* seaf_fs_object_free (fs_obj); */
return -1;
}
static void
recv_fs_object_seg (CcnetProcessor *processor, char *content, int clen)
{
USE_PRIV;
/* Append the received object segment to the end */
priv->obj_seg = g_realloc (priv->obj_seg, priv->obj_seg_len + clen);
memcpy (priv->obj_seg + priv->obj_seg_len, content, clen);
seaf_debug ("[getfs] Get obj seg: <id= %40s, offset= %d, lenth= %d>\n",
priv->obj_seg, priv->obj_seg_len, clen);
priv->obj_seg_len += clen;
}
static void
process_fs_object_seg (CcnetProcessor *processor)
{
USE_PRIV;
if (recv_fs_object (processor, priv->obj_seg, priv->obj_seg_len) == 0) {
g_free (priv->obj_seg);
priv->obj_seg = NULL;
priv->obj_seg_len = 0;
}
}
static void *
calculate_needed_object_list (void *data)
{
CcnetProcessor *processor = data;
USE_PRIV;
SeafileGetfsV2Proc *proc = (SeafileGetfsV2Proc *)processor;
TransferTask *task = proc->tx_task;
GList *ptr;
char *obj_id;
GHashTable *checked_objs;
int dummy;
checked_objs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (ptr = priv->recv_objs; ptr; ptr = ptr->next) {
obj_id = ptr->data;
if (g_hash_table_lookup (checked_objs, obj_id)) {
g_free (obj_id);
continue;
}
g_hash_table_insert (checked_objs, g_strdup(obj_id), &dummy);
if (!seaf_obj_store_obj_exists (seaf->fs_mgr->obj_store,
task->repo_id, task->repo_version,
obj_id))
priv->needed_objs = g_list_prepend (priv->needed_objs, obj_id);
else
g_free (obj_id);
}
g_hash_table_destroy (checked_objs);
g_list_free (priv->recv_objs);
priv->recv_objs = NULL;
return data;
}
#define OBJECT_LIST_SEGMENT_N 1000
#define OBJECT_LIST_SEGMENT_LEN 40 * 1000
static void
send_object_list_segment (CcnetProcessor *processor)
{
USE_PRIV;
char buf[OBJECT_LIST_SEGMENT_LEN];
if (priv->needed_objs == NULL) {
seaf_debug ("All objects saved. Done.\n");
ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
ccnet_processor_done (processor, TRUE);
return;
}
priv->n_pending = 0;
priv->n_saved = 0;
int i = 0;
char *p = buf;
char *obj_id;
while (priv->needed_objs != NULL) {
obj_id = priv->needed_objs->data;
priv->needed_objs = g_list_delete_link (priv->needed_objs,
priv->needed_objs);
memcpy (p, obj_id, 40);
p += 40;
g_free (obj_id);
if (++i == OBJECT_LIST_SEGMENT_N)
break;
}
if (i > 0) {
seaf_debug ("Send %d object ids.\n", i);
priv->n_pending = i;
ccnet_processor_send_update (processor,
SC_OBJ_LIST_SEG, SS_OBJ_LIST_SEG,
buf, i * 40);
}
}
static void
calculate_needed_object_list_done (void *data)
{
CcnetProcessor *processor = data;
send_object_list_segment (processor);
processor->state = GET_OBJECTS;
}
static void
process_recv_object_list (CcnetProcessor *processor, char *content, int clen)
{
USE_PRIV;
int n, i;
char *p;
char *obj_id;
n = clen/40;
p = content;
seaf_debug ("Recv %d object ids.\n", n);
for (i = 0; i < n; ++i) {
obj_id = g_strndup (p, 40);
priv->recv_objs = g_list_prepend (priv->recv_objs, obj_id);
p += 40;
}
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
switch (processor->state) {
case INIT:
if (strncmp (code, SC_OK, 3) == 0)
processor->state = CHECK_OBJECT_LIST;
else {
seaf_warning ("Bad response: %s %s\n", code, code_msg);
ccnet_processor_done (processor, FALSE);
}
break;
case CHECK_OBJECT_LIST:
if (strncmp (code, SC_OBJ_LIST_SEG, 3) == 0) {
if (clen % 40 != 0) {
seaf_warning ("Invalid object list segment length %d.\n", clen);
ccnet_processor_send_update (processor,
SC_SHUTDOWN, SS_SHUTDOWN,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
process_recv_object_list (processor, content, clen);
} else if (strncmp (code, SC_OBJ_LIST_SEG_END, 3) == 0) {
ccnet_processor_thread_create (processor, seaf->job_mgr,
calculate_needed_object_list,
calculate_needed_object_list_done,
processor);
} else if (strncmp (code, SC_END, 3) == 0) {
/* The server finds nothing to put. */
ccnet_processor_done (processor, TRUE);
} else {
seaf_warning ("Bad response: %s %s\n", code, code_msg);
ccnet_processor_send_update (processor,
SC_BAD_RESPONSE_CODE, SS_BAD_RESPONSE_CODE,
NULL, 0);
ccnet_processor_done (processor, FALSE);
}
break;
case GET_OBJECTS:
if (strncmp(code, SC_OBJ_SEG, 3) == 0) {
recv_fs_object_seg (processor, content, clen);
} else if (strncmp(code, SC_OBJ_SEG_END, 3) == 0) {
recv_fs_object_seg (processor, content, clen);
process_fs_object_seg (processor);
} else if (strncmp(code, SC_OBJECT, 3) == 0) {
recv_fs_object (processor, content, clen);
} else {
seaf_warning ("Bad response: %s %s\n", code, code_msg);
ccnet_processor_send_update (processor,
SC_BAD_RESPONSE_CODE, SS_BAD_RESPONSE_CODE,
NULL, 0);
ccnet_processor_done (processor, FALSE);
}
break;
default:
g_return_if_reached ();
}
}

View File

@ -1,33 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_GETFS_V2_PROC_H
#define SEAFILE_GETFS_V2_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_GETFS_V2_PROC (seafile_getfs_v2_proc_get_type ())
#define SEAFILE_GETFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_GETFS_V2_PROC, SeafileGetfsV2Proc))
#define SEAFILE_IS_GETFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_GETFS_V2_PROC))
#define SEAFILE_GETFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_GETFS_V2_PROC, SeafileGetfsV2ProcClass))
#define IS_SEAFILE_GETFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_GETFS_V2_PROC))
#define SEAFILE_GETFS_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_GETFS_V2_PROC, SeafileGetfsV2ProcClass))
typedef struct _SeafileGetfsV2Proc SeafileGetfsV2Proc;
typedef struct _SeafileGetfsV2ProcClass SeafileGetfsV2ProcClass;
struct _SeafileGetfsV2Proc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileGetfsV2ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_getfs_v2_proc_get_type ();
#endif

View File

@ -1,105 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <string.h>
#include <ccnet.h>
#include "sendbranch-proc.h"
#include "log.h"
#define SC_NOT_FF "402"
#define SS_NOT_FF "Not fast forward"
#define SC_QUOTA_ERROR "403"
#define SS_QUOTA_ERROR "Failed to get quota"
#define SC_QUOTA_FULL "404"
#define SS_QUOTA_FULL "storage for the repo's owner is full"
#define SC_ACCESS_DENIED "410"
#define SS_ACCESS_DENIED "Access denied"
G_DEFINE_TYPE (SeafileSendbranchProc, seafile_sendbranch_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
/* FILL IT */
CCNET_PROCESSOR_CLASS (seafile_sendbranch_proc_parent_class)->release_resource (processor);
}
static void
seafile_sendbranch_proc_class_init (SeafileSendbranchProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
proc_class->name = "sendbranch-proc";
}
static void
seafile_sendbranch_proc_init (SeafileSendbranchProc *processor)
{
}
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
char *repo_id, *branch, *new_head;
GString *buf;
TransferTask *task = ((SeafileSendbranchProc *)processor)->task;
if (argc != 3) {
return -1;
}
repo_id = argv[0];
branch = argv[1];
new_head = argv[2];
buf = g_string_new (NULL);
if (task->protocol_version <= 6)
g_string_printf (buf, "remote %s seafile-recvbranch %s %s %s %s",
processor->peer_id, repo_id, branch, new_head,
task->session_token);
else
g_string_printf (buf, "remote %s seafile-recvbranch-v2 %s %s %s %s",
processor->peer_id, repo_id, branch, new_head,
task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
return 0;
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSendbranchProc *proc = (SeafileSendbranchProc *)processor;
TransferTask *task = proc->task;
if (memcmp (code, SC_OK, 3) == 0) {
ccnet_processor_done (processor, TRUE);
} else {
seaf_warning ("[sendbranch] Bad response: %s.\n", code_msg);
if (strncmp(code, SC_NOT_FF, 3) == 0)
transfer_task_set_error (task, TASK_ERR_NOT_FAST_FORWARD);
else if (strncmp(code, SC_QUOTA_ERROR, 3) == 0)
transfer_task_set_error (task, TASK_ERR_CHECK_QUOTA);
else if (strncmp(code, SC_QUOTA_FULL, 3) == 0)
transfer_task_set_error (task, TASK_ERR_QUOTA_FULL);
else if (strncmp(code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
else
transfer_task_set_error (task, TASK_ERR_UNKNOWN);
ccnet_processor_done (processor, FALSE);
}
}

View File

@ -1,34 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SENDBRANCH_PROC_H
#define SEAFILE_SENDBRANCH_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_SENDBRANCH_PROC (seafile_sendbranch_proc_get_type ())
#define SEAFILE_SENDBRANCH_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SENDBRANCH_PROC, SeafileSendbranchProc))
#define SEAFILE_IS_SENDBRANCH_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SENDBRANCH_PROC))
#define SEAFILE_SENDBRANCH_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SENDBRANCH_PROC, SeafileSendbranchProcClass))
#define IS_SEAFILE_SENDBRANCH_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SENDBRANCH_PROC))
#define SEAFILE_SENDBRANCH_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SENDBRANCH_PROC, SeafileSendbranchProcClass))
typedef struct _SeafileSendbranchProc SeafileSendbranchProc;
typedef struct _SeafileSendbranchProcClass SeafileSendbranchProcClass;
struct _SeafileSendbranchProc {
CcnetProcessor parent_instance;
TransferTask *task;
};
struct _SeafileSendbranchProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sendbranch_proc_get_type ();
#endif

View File

@ -1,331 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <ccnet.h>
#include "net.h"
#include "utils.h"
#include "seafile-session.h"
#include "sendcommit-v3-new-proc.h"
#include "processors/objecttx-common.h"
#include "vc-common.h"
/*
seafile-recvcommit-v3
INIT --------------------->
200 OK
INIT <---------------------
Object
SEND_OBJ ----------------------->
Ack or Bad Object
<---------------------
...
End
----------------------->
*/
enum {
INIT,
SEND_OBJECT
};
typedef struct {
char remote_id[41];
char last_uploaded_id[41];
GList *id_list;
gboolean visited_last_uploaded;
gboolean compute_success;
} SeafileSendcommitProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC, SeafileSendcommitProcPriv))
#define USE_PRIV \
SeafileSendcommitProcPriv *priv = GET_PRIV(processor);
static int send_commit_start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
G_DEFINE_TYPE (SeafileSendcommitV3NewProc, seafile_sendcommit_v3_new_proc, CCNET_TYPE_PROCESSOR)
static void
release_resource (CcnetProcessor *processor)
{
USE_PRIV;
if (priv->id_list != NULL)
string_list_free (priv->id_list);
CCNET_PROCESSOR_CLASS (seafile_sendcommit_v3_new_proc_parent_class)->release_resource (processor);
}
static void
seafile_sendcommit_v3_new_proc_class_init (SeafileSendcommitV3NewProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "sendcommit-v3-new-proc";
proc_class->start = send_commit_start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof (SeafileSendcommitProcPriv));
}
static void
seafile_sendcommit_v3_new_proc_init (SeafileSendcommitV3NewProc *processor)
{
}
static int
send_commit_start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf;
TransferTask *task = ((SeafileSendcommitV3NewProc *)processor)->tx_task;
memcpy (priv->remote_id, task->remote_head, 41);
/* fs_roots can be non-NULL if transfer is resumed from NET_DOWN. */
if (task->fs_roots != NULL)
object_list_free (task->fs_roots);
task->fs_roots = object_list_new ();
if (task->commits != NULL)
object_list_free (task->commits);
task->commits = object_list_new ();
buf = g_string_new (NULL);
g_string_printf (buf, "remote %s seafile-recvcommit-v3 %s %s",
processor->peer_id, task->to_branch, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
return 0;
}
static void
send_commit (CcnetProcessor *processor, const char *object_id)
{
TransferTask *task = ((SeafileSendcommitV3NewProc *)processor)->tx_task;
char *data;
int len;
ObjectPack *pack = NULL;
int pack_size;
if (seaf_obj_store_read_obj (seaf->commit_mgr->obj_store,
task->repo_id, task->repo_version,
object_id, (void**)&data, &len) < 0) {
seaf_warning ("Failed to read commit %s.\n", object_id);
goto fail;
}
pack_size = sizeof(ObjectPack) + len;
pack = malloc (pack_size);
memcpy (pack->id, object_id, 41);
memcpy (pack->object, data, len);
ccnet_processor_send_update (processor, SC_OBJECT, SS_OBJECT,
(char *)pack, pack_size);
seaf_debug ("Send commit %.8s.\n", object_id);
g_free (data);
free (pack);
return;
fail:
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
object_id, 41);
ccnet_processor_done (processor, FALSE);
}
static void
send_one_commit (CcnetProcessor *processor)
{
USE_PRIV;
char *commit_id;
if (!priv->id_list) {
ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
ccnet_processor_done (processor, TRUE);
return;
}
commit_id = priv->id_list->data;
priv->id_list = g_list_delete_link (priv->id_list, priv->id_list);
send_commit (processor, commit_id);
g_free (commit_id);
}
static gboolean
collect_upload_commit_ids (SeafCommit *commit, void *data, gboolean *stop)
{
CcnetProcessor *processor = data;
TransferTask *task = ((SeafileSendcommitV3NewProc *)processor)->tx_task;
USE_PRIV;
if (strcmp (priv->last_uploaded_id, commit->commit_id) == 0) {
priv->visited_last_uploaded = TRUE;
*stop = TRUE;
return TRUE;
}
if (priv->remote_id[0] != 0 &&
strcmp (priv->remote_id, commit->commit_id) == 0) {
*stop = TRUE;
return TRUE;
}
if (commit->parent_id &&
!seaf_commit_manager_commit_exists (seaf->commit_mgr,
commit->repo_id, commit->version,
commit->parent_id)) {
*stop = TRUE;
return TRUE;
}
if (commit->second_parent_id &&
!seaf_commit_manager_commit_exists (seaf->commit_mgr,
commit->repo_id, commit->version,
commit->second_parent_id)) {
*stop = TRUE;
return TRUE;
}
priv->id_list = g_list_prepend (priv->id_list, g_strdup(commit->commit_id));
/* We don't need to send the contents under an empty dir.
*/
if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
object_list_insert (task->fs_roots, commit->root_id);
object_list_insert (task->commits, commit->commit_id);
return TRUE;
}
static void *
compute_upload_commits_thread (void *vdata)
{
CcnetProcessor *processor = vdata;
SeafileSendcommitV3NewProc *proc = (SeafileSendcommitV3NewProc *)processor;
TransferTask *task = proc->tx_task;
USE_PRIV;
gboolean ret;
ret = seaf_commit_manager_traverse_commit_tree_truncated (seaf->commit_mgr,
task->repo_id,
task->repo_version,
task->head,
collect_upload_commit_ids,
processor, FALSE);
if (!ret) {
priv->compute_success = FALSE;
return vdata;
}
/* We have to make sure all commits that need to be uploaded are found locally.
* If we have traversed up to the last uploaded commit, we've traversed all
* needed commits.
*/
if (!priv->visited_last_uploaded) {
seaf_warning ("Not all commit objects need to be uploaded exist locally.\n");
priv->compute_success = FALSE;
return vdata;
}
priv->compute_success = TRUE;
return vdata;
}
static void
compute_upload_commits_done (void *vdata)
{
CcnetProcessor *processor = vdata;
USE_PRIV;
if (!priv->compute_success) {
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
send_one_commit (processor);
}
static void
send_commits (CcnetProcessor *processor, const char *head)
{
SeafileSendcommitV3NewProc *proc = (SeafileSendcommitV3NewProc *)processor;
USE_PRIV;
char *last_uploaded;
last_uploaded = seaf_repo_manager_get_repo_property (seaf->repo_mgr,
proc->tx_task->repo_id,
REPO_LOCAL_HEAD);
if (!last_uploaded || strlen(last_uploaded) != 40) {
seaf_warning ("Last uploaded commit id is not found in db or invalid.\n");
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
memcpy (priv->last_uploaded_id, last_uploaded, 40);
g_free (last_uploaded);
ccnet_processor_thread_create (processor,
seaf->job_mgr,
compute_upload_commits_thread,
compute_upload_commits_done,
processor);
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSendcommitV3NewProc *proc = (SeafileSendcommitV3NewProc *)processor;
TransferTask *task = proc->tx_task;
if (task->state != TASK_STATE_NORMAL) {
ccnet_processor_done (processor, TRUE);
return;
}
switch (processor->state) {
case INIT:
if (memcmp (code, SC_OK, 3) == 0) {
processor->state = SEND_OBJECT;
send_commits (processor, task->head);
return;
}
break;
case SEND_OBJECT:
if (memcmp (code, SC_ACK, 3) == 0) {
send_one_commit (processor);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,31 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SENDCOMMIT_V3_NEW_PROC_H
#define SEAFILE_SENDCOMMIT_V3_NEW_PROC_H
#include <glib-object.h>
#define SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC (seafile_sendcommit_v3_new_proc_get_type ())
#define SEAFILE_SENDCOMMIT_V3_NEW_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC, SeafileSendcommitV3NewProc))
#define SEAFILE_IS_SENDCOMMIT_V3_NEW_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC))
#define SEAFILE_SENDCOMMIT_V3_NEW_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC, SeafileSendcommitV3NewProcClass))
#define IS_SEAFILE_SENDCOMMIT_V3_NEW_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC))
#define SEAFILE_SENDCOMMIT_V3_NEW_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SENDCOMMIT_V3_NEW_PROC, SeafileSendcommitV3NewProcClass))
typedef struct _SeafileSendcommitV3NewProc SeafileSendcommitV3NewProc;
typedef struct _SeafileSendcommitV3NewProcClass SeafileSendcommitV3NewProcClass;
struct _SeafileSendcommitV3NewProc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileSendcommitV3NewProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sendcommit_v3_new_proc_get_type ();
#endif

View File

@ -1,396 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <ccnet.h>
#include "net.h"
#include "utils.h"
#include "seafile-session.h"
#include "sendcommit-v3-proc.h"
#include "processors/objecttx-common.h"
#include "vc-common.h"
/*
seafile-recvcommit-v3
INIT --------------------->
200 OK
INIT <---------------------
Object
SEND_OBJ ----------------------->
Ack or Bad Object
<---------------------
...
End
----------------------->
*/
enum {
INIT,
SEND_OBJECT
};
typedef struct {
char remote_id[41];
GList *id_list;
GHashTable *commit_hash;
gboolean fast_forward;
gboolean compute_success;
} SeafileSendcommitProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_SENDCOMMIT_V3_PROC, SeafileSendcommitProcPriv))
#define USE_PRIV \
SeafileSendcommitProcPriv *priv = GET_PRIV(processor);
static int send_commit_start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
G_DEFINE_TYPE (SeafileSendcommitV3Proc, seafile_sendcommit_v3_proc, CCNET_TYPE_PROCESSOR)
static void
release_resource (CcnetProcessor *processor)
{
USE_PRIV;
if (priv->id_list != NULL)
string_list_free (priv->id_list);
if (priv->commit_hash)
g_hash_table_destroy (priv->commit_hash);
CCNET_PROCESSOR_CLASS (seafile_sendcommit_v3_proc_parent_class)->release_resource (processor);
}
static void
seafile_sendcommit_v3_proc_class_init (SeafileSendcommitV3ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "sendcommit-v3-proc";
proc_class->start = send_commit_start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof (SeafileSendcommitProcPriv));
}
static void
seafile_sendcommit_v3_proc_init (SeafileSendcommitV3Proc *processor)
{
}
static int
send_commit_start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf;
TransferTask *task = ((SeafileSendcommitV3Proc *)processor)->tx_task;
memcpy (priv->remote_id, task->remote_head, 41);
/* fs_roots can be non-NULL if transfer is resumed from NET_DOWN. */
if (task->fs_roots != NULL)
object_list_free (task->fs_roots);
task->fs_roots = object_list_new ();
if (task->commits != NULL)
object_list_free (task->commits);
task->commits = object_list_new ();
buf = g_string_new (NULL);
g_string_printf (buf, "remote %s seafile-recvcommit-v3 %s %s",
processor->peer_id, task->to_branch, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
return 0;
}
static void
send_commit (CcnetProcessor *processor, const char *object_id)
{
TransferTask *task = ((SeafileSendcommitV3Proc *)processor)->tx_task;
char *data;
int len;
ObjectPack *pack = NULL;
int pack_size;
if (seaf_obj_store_read_obj (seaf->commit_mgr->obj_store,
task->repo_id, task->repo_version,
object_id, (void**)&data, &len) < 0) {
seaf_warning ("Failed to read commit %s.\n", object_id);
goto fail;
}
pack_size = sizeof(ObjectPack) + len;
pack = malloc (pack_size);
memcpy (pack->id, object_id, 41);
memcpy (pack->object, data, len);
ccnet_processor_send_update (processor, SC_OBJECT, SS_OBJECT,
(char *)pack, pack_size);
seaf_debug ("Send commit %.8s.\n", object_id);
g_free (data);
free (pack);
return;
fail:
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
object_id, 41);
ccnet_processor_done (processor, FALSE);
}
static void
send_one_commit (CcnetProcessor *processor)
{
USE_PRIV;
char *commit_id;
if (!priv->id_list) {
ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
ccnet_processor_done (processor, TRUE);
return;
}
commit_id = priv->id_list->data;
priv->id_list = g_list_delete_link (priv->id_list, priv->id_list);
send_commit (processor, commit_id);
g_free (commit_id);
}
/* Traverse the commit graph until remote_id is met or a merged commit
* (commit with two parents) is met.
*
* If a merged commit is met before remote_id, that implies that
* we did a real merge when merged with the branch headed by remote_id.
* In this case we'll need more computation to find out the "delta" commits
* between these two branches. Otherwise, if the merge was a fast-forward
* one, it's enough to just send all the commits between our head commit
* and remote_id.
*/
static gboolean
traverse_commit_fast_forward (SeafCommit *commit, void *data, gboolean *stop)
{
CcnetProcessor *processor = data;
TransferTask *task = ((SeafileSendcommitV3Proc *)processor)->tx_task;
USE_PRIV;
if (priv->remote_id[0] != 0 &&
strcmp (priv->remote_id, commit->commit_id) == 0) {
*stop = TRUE;
return TRUE;
}
if (commit->second_parent_id != NULL) {
*stop = TRUE;
priv->fast_forward = FALSE;
return TRUE;
}
priv->id_list = g_list_prepend (priv->id_list, g_strdup(commit->commit_id));
/* We don't need to send the contents under an empty dir.
*/
if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
object_list_insert (task->fs_roots, commit->root_id);
object_list_insert (task->commits, commit->commit_id);
return TRUE;
}
static gboolean
traverse_commit_remote (SeafCommit *commit, void *data, gboolean *stop)
{
CcnetProcessor *processor = data;
USE_PRIV;
char *key;
if (g_hash_table_lookup (priv->commit_hash, commit->commit_id))
return TRUE;
key = g_strdup(commit->commit_id);
g_hash_table_replace (priv->commit_hash, key, key);
return TRUE;
}
static gboolean
compute_delta (SeafCommit *commit, void *data, gboolean *stop)
{
CcnetProcessor *processor = data;
TransferTask *task = ((SeafileSendcommitV3Proc *)processor)->tx_task;
USE_PRIV;
if (!g_hash_table_lookup (priv->commit_hash, commit->commit_id)) {
priv->id_list = g_list_prepend (priv->id_list,
g_strdup(commit->commit_id));
if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
object_list_insert (task->fs_roots, commit->root_id);
object_list_insert (task->commits, commit->commit_id);
} else {
/* Stop traversing down from this commit if it already exists
* in the remote branch.
*/
*stop = TRUE;
}
return TRUE;
}
static int
compute_delta_commits (CcnetProcessor *processor, const char *head)
{
gboolean ret;
TransferTask *task = ((SeafileSendcommitV3Proc *)processor)->tx_task;
USE_PRIV;
string_list_free (priv->id_list);
priv->id_list = NULL;
object_list_free (task->fs_roots);
task->fs_roots = object_list_new ();
object_list_free (task->commits);
task->commits = object_list_new ();
priv->commit_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr,
task->repo_id,
task->repo_version,
priv->remote_id,
traverse_commit_remote,
processor, FALSE);
if (!ret) {
return -1;
}
ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr,
task->repo_id,
task->repo_version,
head,
compute_delta,
processor, FALSE);
if (!ret) {
return -1;
}
return 0;
}
static void *
compute_upload_commits_thread (void *vdata)
{
CcnetProcessor *processor = vdata;
SeafileSendcommitV3Proc *proc = (SeafileSendcommitV3Proc *)processor;
TransferTask *task = proc->tx_task;
USE_PRIV;
gboolean ret;
priv->fast_forward = TRUE;
ret = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr,
task->repo_id,
task->repo_version,
task->head,
traverse_commit_fast_forward,
processor, FALSE);
if (!ret) {
priv->compute_success = FALSE;
return vdata;
}
if (priv->fast_forward) {
priv->compute_success = TRUE;
seaf_debug ("[sendcommt] Send commit after a fast forward merge.\n");
return vdata;
}
seaf_debug ("[sendcommit] Send commit after a real merge.\n");
if (compute_delta_commits (processor, task->head) < 0) {
priv->compute_success = FALSE;
return vdata;
}
priv->compute_success = TRUE;
return vdata;
}
static void
compute_upload_commits_done (void *vdata)
{
CcnetProcessor *processor = vdata;
USE_PRIV;
if (!priv->compute_success) {
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
send_one_commit (processor);
}
static void
send_commits (CcnetProcessor *processor, const char *head)
{
ccnet_processor_thread_create (processor,
seaf->job_mgr,
compute_upload_commits_thread,
compute_upload_commits_done,
processor);
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSendcommitV3Proc *proc = (SeafileSendcommitV3Proc *)processor;
TransferTask *task = proc->tx_task;
if (task->state != TASK_STATE_NORMAL) {
ccnet_processor_done (processor, TRUE);
return;
}
switch (processor->state) {
case INIT:
if (memcmp (code, SC_OK, 3) == 0) {
processor->state = SEND_OBJECT;
send_commits (processor, task->head);
return;
}
break;
case SEND_OBJECT:
if (memcmp (code, SC_ACK, 3) == 0) {
send_one_commit (processor);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,31 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SENDCOMMIT_V3_PROC_H
#define SEAFILE_SENDCOMMIT_V3_PROC_H
#include <glib-object.h>
#define SEAFILE_TYPE_SENDCOMMIT_V3_PROC (seafile_sendcommit_v3_proc_get_type ())
#define SEAFILE_SENDCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SENDCOMMIT_V3_PROC, SeafileSendcommitV3Proc))
#define SEAFILE_IS_SENDCOMMIT_V3_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SENDCOMMIT_V3_PROC))
#define SEAFILE_SENDCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SENDCOMMIT_V3_PROC, SeafileSendcommitV3ProcClass))
#define IS_SEAFILE_SENDCOMMIT_V3_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SENDCOMMIT_V3_PROC))
#define SEAFILE_SENDCOMMIT_V3_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SENDCOMMIT_V3_PROC, SeafileSendcommitV3ProcClass))
typedef struct _SeafileSendcommitV3Proc SeafileSendcommitV3Proc;
typedef struct _SeafileSendcommitV3ProcClass SeafileSendcommitV3ProcClass;
struct _SeafileSendcommitV3Proc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileSendcommitV3ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sendcommit_v3_proc_get_type ();
#endif

View File

@ -1,131 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <ccnet.h>
#include "net.h"
#include "utils.h"
#include "seafile-session.h"
#include "sendcommit-v4-proc.h"
#include "processors/objecttx-common.h"
#include "vc-common.h"
enum {
INIT,
SEND_OBJECT
};
static int send_commit_start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
G_DEFINE_TYPE (SeafileSendcommitV4Proc, seafile_sendcommit_v4_proc, CCNET_TYPE_PROCESSOR)
static void
seafile_sendcommit_v4_proc_class_init (SeafileSendcommitV4ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "sendcommit-v4-proc";
proc_class->start = send_commit_start;
proc_class->handle_response = handle_response;
}
static void
seafile_sendcommit_v4_proc_init (SeafileSendcommitV4Proc *processor)
{
}
static int
send_commit_start (CcnetProcessor *processor, int argc, char **argv)
{
TransferTask *task = ((SeafileSendcommitV4Proc *)processor)->tx_task;
GString *buf;
buf = g_string_new (NULL);
g_string_printf (buf, "remote %s seafile-recvcommit-v3 master %s",
processor->peer_id, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
return 0;
}
static void
send_commit (CcnetProcessor *processor, const char *object_id)
{
TransferTask *task = ((SeafileSendcommitV4Proc *)processor)->tx_task;
char *data;
int len;
ObjectPack *pack = NULL;
int pack_size;
if (seaf_obj_store_read_obj (seaf->commit_mgr->obj_store,
task->repo_id, task->repo_version,
object_id, (void**)&data, &len) < 0) {
seaf_warning ("Failed to read commit %s.\n", object_id);
goto fail;
}
pack_size = sizeof(ObjectPack) + len;
pack = malloc (pack_size);
memcpy (pack->id, object_id, 41);
memcpy (pack->object, data, len);
ccnet_processor_send_update (processor, SC_OBJECT, SS_OBJECT,
(char *)pack, pack_size);
seaf_debug ("Send commit %.8s.\n", object_id);
g_free (data);
free (pack);
return;
fail:
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
object_id, 41);
ccnet_processor_done (processor, FALSE);
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSendcommitV4Proc *proc = (SeafileSendcommitV4Proc *)processor;
TransferTask *task = proc->tx_task;
if (task->state != TASK_STATE_NORMAL) {
ccnet_processor_done (processor, TRUE);
return;
}
switch (processor->state) {
case INIT:
if (memcmp (code, SC_OK, 3) == 0) {
processor->state = SEND_OBJECT;
send_commit (processor, task->head);
return;
}
break;
case SEND_OBJECT:
if (memcmp (code, SC_ACK, 3) == 0) {
ccnet_processor_done (processor, TRUE);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,31 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SENDCOMMIT_V4_PROC_H
#define SEAFILE_SENDCOMMIT_V4_PROC_H
#include <glib-object.h>
#define SEAFILE_TYPE_SENDCOMMIT_V4_PROC (seafile_sendcommit_v4_proc_get_type ())
#define SEAFILE_SENDCOMMIT_V4_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SENDCOMMIT_V4_PROC, SeafileSendcommitV4Proc))
#define SEAFILE_IS_SENDCOMMIT_V4_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SENDCOMMIT_V4_PROC))
#define SEAFILE_SENDCOMMIT_V4_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SENDCOMMIT_V4_PROC, SeafileSendcommitV4ProcClass))
#define IS_SEAFILE_SENDCOMMIT_V4_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SENDCOMMIT_V4_PROC))
#define SEAFILE_SENDCOMMIT_V4_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SENDCOMMIT_V4_PROC, SeafileSendcommitV4ProcClass))
typedef struct _SeafileSendcommitV4Proc SeafileSendcommitV4Proc;
typedef struct _SeafileSendcommitV4ProcClass SeafileSendcommitV4ProcClass;
struct _SeafileSendcommitV4Proc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileSendcommitV4ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sendcommit_v4_proc_get_type ();
#endif

View File

@ -1,288 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* file system synchronization algorithm:
*
* Begins with the root directory object,
*
* seafile-recvfs
* S(INIT -> SEND_ROOT) ---------------------------------> T
* OK
* S(SEND_ROOT) <--------------------------- T
* FS_ROOT
* S(SEND_ROOT) ----------------------------> T
* OK
* S(SEND_ROOT) <---------------------------- T
* FS Root, FS Root End
* S(SEND_ROOT -> SEND_OBJECT) ----------------------------> T
*
* Get Object
* S(SEND_OBJECT) <---------------------------- T
* Object
* S(SEND_OBJECT) ----------------------------> T
* .
* .
* .
* END
* S(SEND_OBJECT) <--------------------------- T
*/
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <ccnet.h>
#include "utils.h"
#include "seafile-session.h"
#include "commit-mgr.h"
#include "fs-mgr.h"
#include "processors/objecttx-common.h"
#include "sendfs-proc.h"
enum {
INIT,
SEND_ROOT,
SEND_OBJECT
};
typedef struct {
guint32 reader_id;
} SeafileSendfsProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_SENDFS_PROC, SeafileSendfsProcPriv))
#define USE_PRIV \
SeafileSendfsProcPriv *priv = GET_PRIV(processor);
G_DEFINE_TYPE (SeafileSendfsProc, seafile_sendfs_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
USE_PRIV;
seaf_obj_store_unregister_async_read (seaf->fs_mgr->obj_store,
priv->reader_id);
CCNET_PROCESSOR_CLASS (seafile_sendfs_proc_parent_class)->release_resource (processor);
}
static void
seafile_sendfs_proc_class_init (SeafileSendfsProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "sendfs-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof(SeafileSendfsProcPriv));
}
static void
seafile_sendfs_proc_init (SeafileSendfsProc *processor)
{
}
static void
fs_object_read_cb (OSAsyncResult *res, void *data);
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf;
SeafileSendfsProc *proc = (SeafileSendfsProc *)processor;
TransferTask *task = proc->tx_task;
buf = g_string_new (NULL);
g_string_printf (buf, "remote %s seafile-recvfs %s",
processor->peer_id, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
processor->state = SEND_ROOT;
proc->last_idx = 0;
priv->reader_id = seaf_obj_store_register_async_read (seaf->fs_mgr->obj_store,
task->repo_id,
task->repo_version,
fs_object_read_cb,
processor);
return 0;
}
static void
send_fs_object (CcnetProcessor *processor,
const char *object_id, char *data, int len)
{
ObjectPack *pack = NULL;
int pack_size;
pack_size = sizeof(ObjectPack) + len;
pack = malloc (pack_size);
memcpy (pack->id, object_id, 41);
memcpy (pack->object, data, len);
if (pack_size <= MAX_OBJ_SEG_SIZE) {
ccnet_processor_send_update (processor, SC_OBJECT, SS_OBJECT,
(char *)pack, pack_size);
} else {
int offset, n;
offset = 0;
while (offset < pack_size) {
n = MIN(pack_size - offset, MAX_OBJ_SEG_SIZE);
if (offset + n < pack_size) {
ccnet_processor_send_update (processor,
SC_OBJ_SEG, SS_OBJ_SEG,
(char *)pack + offset, n);
} else {
ccnet_processor_send_update (processor,
SC_OBJ_SEG_END, SS_OBJ_SEG_END,
(char *)pack + offset, n);
}
seaf_debug ("Sent object %s segment<total = %d, offset = %d, n = %d>\n",
object_id, pack_size, offset, n);
offset += n;
}
}
seaf_debug ("Send fs object %.8s.\n", object_id);
free (pack);
}
static void
fs_object_read_cb (OSAsyncResult *res, void *data)
{
CcnetProcessor *processor = data;
if (!res->success) {
seaf_warning ("Failed to read fs object %.8s.\n", res->obj_id);
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
res->obj_id, 41);
ccnet_processor_done (processor, FALSE);
return;
}
send_fs_object (processor, res->obj_id, res->data, res->len);
}
static void
read_fs_object (CcnetProcessor *processor, const char *obj_id)
{
USE_PRIV;
seaf_obj_store_async_read (seaf->fs_mgr->obj_store,
priv->reader_id,
obj_id);
}
static void
send_fs_objects (CcnetProcessor *processor, char *content, int clen)
{
char *object_id;
int n_objects;
int i;
if (clen % 41 != 1 || content[clen-1] != '\0') {
seaf_warning ("Bad fs object list.\n");
ccnet_processor_send_update (processor, SC_BAD_OL, SS_BAD_OL, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
n_objects = clen/41;
object_id = content;
for (i = 0; i < n_objects; ++i) {
object_id[40] = '\0';
read_fs_object (processor, object_id);
object_id += 41;
}
}
static void
send_fs_roots (CcnetProcessor *processor)
{
SeafileSendfsProc *proc = (SeafileSendfsProc *)processor;
char buf[2096];
char *ptr = buf;
int i, count = 0;
ObjectList *ol = proc->tx_task->fs_roots;
int ollen = object_list_length (ol);
if (proc->last_idx == ollen) {
ccnet_processor_send_update (processor, SC_ROOT_END, SS_ROOT_END,
NULL, 0);
processor->state = SEND_OBJECT;
return;
}
for (i = proc->last_idx; i < ollen; i++) {
memcpy (ptr, g_ptr_array_index(ol->obj_ids, i), 40);
ptr += 40;
*ptr++ = '\n';
if (++count == 48)
break;
}
ccnet_processor_send_update (processor, SC_ROOT, SS_ROOT,
buf, 41 * count);
proc->last_idx = i;
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSendfsProc *proc = (SeafileSendfsProc *)processor;
TransferTask *task = proc->tx_task;
switch (processor->state) {
case SEND_ROOT:
if (strncmp(code, SC_OK, 3) == 0) {
send_fs_roots (processor);
return;
}
break;
case SEND_OBJECT:
if (strncmp(code, SC_GET_OBJECT, 3) == 0) {
send_fs_objects (processor, content, clen);
return;
} else if (strncmp(code, SC_END, 3) == 0) {
seaf_debug ("Send fs objects end.\n");
ccnet_processor_done (processor, TRUE);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,34 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SENDFS_PROC_H
#define SEAFILE_SENDFS_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_SENDFS_PROC (seafile_sendfs_proc_get_type ())
#define SEAFILE_SENDFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SENDFS_PROC, SeafileSendfsProc))
#define SEAFILE_IS_SENDFS_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SENDFS_PROC))
#define SEAFILE_SENDFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SENDFS_PROC, SeafileSendfsProcClass))
#define IS_SEAFILE_SENDFS_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SENDFS_PROC))
#define SEAFILE_SENDFS_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SENDFS_PROC, SeafileSendfsProcClass))
typedef struct _SeafileSendfsProc SeafileSendfsProc;
typedef struct _SeafileSendfsProcClass SeafileSendfsProcClass;
struct _SeafileSendfsProc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
int last_idx; /* used in send root fs to peer */
};
struct _SeafileSendfsProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sendfs_proc_get_type ();
#endif

View File

@ -1,510 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_TRANSFER
#include "log.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <ccnet.h>
#include "utils.h"
#include "seafile-session.h"
#include "commit-mgr.h"
#include "fs-mgr.h"
#include "processors/objecttx-common.h"
#include "sendfs-v2-proc.h"
#include "diff-simple.h"
/*
* recvfs-v2-proc
* ------------------------------>
*
* OK
* <-----------------------------
*
* Calculate send object list
*
* SC_OBJ_LIST_SEG
* ----------------------------->
* SC_OBJ_LIST_SEG
* <----------------------------
* ......
* SC_OBJ_LIST_SEG_END
* ----------------------------->
*
* SC_OBJ
* ----------------------------->
* ......
* After all objects are saved to disk, the server ends the protocol.
* SC_END
* <----------------------------
*/
enum {
INIT = 0,
CHECK_OBJECT_LIST,
SEND_OBJECTS,
};
typedef struct {
GList *send_obj_list;
GList *recv_obj_list;
guint32 reader_id;
gboolean calc_success;
} SeafileSendfsProcPriv;
#define GET_PRIV(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SEAFILE_TYPE_SENDFS_V2_PROC, SeafileSendfsProcPriv))
#define USE_PRIV \
SeafileSendfsProcPriv *priv = GET_PRIV(processor);
G_DEFINE_TYPE (SeafileSendfsV2Proc, seafile_sendfs_v2_proc, CCNET_TYPE_PROCESSOR)
static int start (CcnetProcessor *processor, int argc, char **argv);
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
release_resource(CcnetProcessor *processor)
{
USE_PRIV;
string_list_free (priv->send_obj_list);
string_list_free (priv->recv_obj_list);
seaf_obj_store_unregister_async_read (seaf->fs_mgr->obj_store,
priv->reader_id);
CCNET_PROCESSOR_CLASS (seafile_sendfs_v2_proc_parent_class)->release_resource (processor);
}
static void
seafile_sendfs_v2_proc_class_init (SeafileSendfsV2ProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "sendfs-v2-proc";
proc_class->start = start;
proc_class->handle_response = handle_response;
proc_class->release_resource = release_resource;
g_type_class_add_private (klass, sizeof(SeafileSendfsProcPriv));
}
static void
seafile_sendfs_v2_proc_init (SeafileSendfsV2Proc *processor)
{
}
static void
fs_object_read_cb (OSAsyncResult *res, void *data);
static int
start (CcnetProcessor *processor, int argc, char **argv)
{
USE_PRIV;
GString *buf;
SeafileSendfsV2Proc *proc = (SeafileSendfsV2Proc *)processor;
TransferTask *task = proc->tx_task;
buf = g_string_new (NULL);
g_string_printf (buf, "remote %s seafile-recvfs-v2 %s",
processor->peer_id, task->session_token);
ccnet_processor_send_request (processor, buf->str);
g_string_free (buf, TRUE);
priv->reader_id = seaf_obj_store_register_async_read (seaf->fs_mgr->obj_store,
task->repo_id,
task->repo_version,
fs_object_read_cb,
processor);
return 0;
}
/* Calculate send object list */
typedef struct {
GList **pret;
GHashTable *checked_objs;
} CalcData;
inline static gboolean
dirent_same (SeafDirent *denta, SeafDirent *dentb)
{
return (strcmp (dentb->id, denta->id) == 0 && denta->mode == dentb->mode);
}
static int
collect_file_ids (int n, const char *basedir, SeafDirent *files[], void *vdata)
{
SeafDirent *file1 = files[0];
SeafDirent *file2 = files[1];
CalcData *data = vdata;
GList **pret = data->pret;
int dummy;
if (!file1 || strcmp (file1->id, EMPTY_SHA1) == 0)
return 0;
if (g_hash_table_lookup (data->checked_objs, file1->id))
return 0;
if (!file2 || !dirent_same (file1, file2)) {
*pret = g_list_prepend (*pret, g_strdup(file1->id));
g_hash_table_insert (data->checked_objs, g_strdup(file1->id), &dummy);
}
return 0;
}
static int
collect_dir_ids (int n, const char *basedir, SeafDirent *dirs[], void *vdata,
gboolean *recurse)
{
SeafDirent *dir1 = dirs[0];
SeafDirent *dir2 = dirs[1];
CalcData *data = vdata;
GList **pret = data->pret;
int dummy;
if (!dir1 || strcmp (dir1->id, EMPTY_SHA1) == 0)
return 0;
if (g_hash_table_lookup (data->checked_objs, dir1->id))
return 0;
if (!dir2 || !dirent_same (dir1, dir2)) {
*pret = g_list_prepend (*pret, g_strdup(dir1->id));
g_hash_table_insert (data->checked_objs, g_strdup(dir1->id), &dummy);
}
return 0;
}
static void *
calculate_send_object_list (void *vdata)
{
CcnetProcessor *processor = vdata;
USE_PRIV;
SeafileSendfsV2Proc *proc = (SeafileSendfsV2Proc *)processor;
TransferTask *task = proc->tx_task;
SeafBranch *local = NULL, *master = NULL;
SeafCommit *local_head = NULL, *master_head = NULL;
local = seaf_branch_manager_get_branch (seaf->branch_mgr, task->repo_id, "local");
if (!local) {
seaf_warning ("Branch local not found for repo %.8s.\n", task->repo_id);
priv->calc_success = FALSE;
goto out;
}
master = seaf_branch_manager_get_branch (seaf->branch_mgr, task->repo_id, "master");
if (!master) {
seaf_warning ("Branch master not found for repo %.8s.\n", task->repo_id);
priv->calc_success = FALSE;
goto out;
}
local_head = seaf_commit_manager_get_commit (seaf->commit_mgr,
task->repo_id, task->repo_version,
local->commit_id);
if (!local_head) {
seaf_warning ("Local head commit not found for repo %.8s.\n",
task->repo_id);
priv->calc_success = FALSE;
goto out;
}
master_head = seaf_commit_manager_get_commit (seaf->commit_mgr,
task->repo_id, task->repo_version,
master->commit_id);
if (!master_head) {
seaf_warning ("Master head commit not found for repo %.8s.\n",
task->repo_id);
priv->calc_success = FALSE;
goto out;
}
/* Diff won't traverse the root object itself. */
if (strcmp (local_head->root_id, master_head->root_id) != 0 &&
strcmp (local_head->root_id, EMPTY_SHA1) != 0)
priv->send_obj_list = g_list_prepend (priv->send_obj_list,
g_strdup(local_head->root_id));
CalcData *data = g_new0(CalcData, 1);
data->pret = &priv->send_obj_list;
data->checked_objs = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
DiffOptions opts;
memset (&opts, 0, sizeof(opts));
memcpy (opts.store_id, task->repo_id, 36);
opts.version = task->repo_version;
opts.file_cb = collect_file_ids;
opts.dir_cb = collect_dir_ids;
opts.data = data;
const char *trees[2];
trees[0] = local_head->root_id;
trees[1] = master_head->root_id;
if (diff_trees (2, trees, &opts) < 0) {
seaf_warning ("Failed to diff local and master head for repo %.8s.\n",
task->repo_id);
priv->calc_success = FALSE;
}
g_hash_table_destroy (data->checked_objs);
g_free (data);
priv->calc_success = TRUE;
out:
seaf_branch_unref (local);
seaf_branch_unref (master);
seaf_commit_unref (local_head);
seaf_commit_unref (master_head);
return vdata;
}
static void
send_object_list_segment (CcnetProcessor *processor);
static void
calculate_send_object_list_done (void *vdata)
{
CcnetProcessor *processor = vdata;
USE_PRIV;
if (!priv->calc_success) {
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
if (priv->send_obj_list == NULL) {
seaf_message ("No fs objects to upload. Done.\n");
ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
ccnet_processor_done (processor, TRUE);
return;
}
send_object_list_segment (processor);
}
/* Check object list. */
#define OBJECT_LIST_SEGMENT_N 1000
#define OBJECT_LIST_SEGMENT_LEN 40 * 1000
static void
send_next_object (CcnetProcessor *processor);
static void
send_object_list_segment (CcnetProcessor *processor)
{
USE_PRIV;
char buf[OBJECT_LIST_SEGMENT_LEN];
if (priv->send_obj_list == NULL) {
seaf_debug ("Check object list end.\n");
ccnet_processor_send_update (processor,
SC_OBJ_LIST_SEG_END, SS_OBJ_LIST_SEG_END,
NULL, 0);
send_next_object (processor);
processor->state = SEND_OBJECTS;
return;
}
int i = 0;
char *p = buf;
char *obj_id;
while (priv->send_obj_list != NULL) {
obj_id = priv->send_obj_list->data;
priv->send_obj_list = g_list_delete_link (priv->send_obj_list,
priv->send_obj_list);
memcpy (p, obj_id, 40);
p += 40;
g_free (obj_id);
if (++i == OBJECT_LIST_SEGMENT_N)
break;
}
if (i > 0) {
seaf_debug ("Send %d object ids.\n", i);
ccnet_processor_send_update (processor,
SC_OBJ_LIST_SEG, SS_OBJ_LIST_SEG,
buf, i * 40);
}
}
static void
process_object_list_segment (CcnetProcessor *processor, char *content, int clen)
{
USE_PRIV;
int n, i;
char *p;
if (clen % 40 != 0) {
seaf_warning ("Invalid object list segment length %d.\n", clen);
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
ccnet_processor_done (processor, FALSE);
return;
}
n = clen/40;
p = content;
seaf_debug ("%d objects are needed by the server.\n", n);
for (i = 0; i < n; ++i) {
priv->recv_obj_list = g_list_prepend (priv->recv_obj_list, g_strndup (p, 40));
p += 40;
}
}
/* Send objects */
static void
send_fs_object (CcnetProcessor *processor,
const char *object_id, char *data, int len)
{
ObjectPack *pack = NULL;
int pack_size;
pack_size = sizeof(ObjectPack) + len;
pack = malloc (pack_size);
memcpy (pack->id, object_id, 41);
memcpy (pack->object, data, len);
if (pack_size <= MAX_OBJ_SEG_SIZE) {
ccnet_processor_send_update (processor, SC_OBJECT, SS_OBJECT,
(char *)pack, pack_size);
} else {
int offset, n;
offset = 0;
while (offset < pack_size) {
n = MIN(pack_size - offset, MAX_OBJ_SEG_SIZE);
if (offset + n < pack_size) {
ccnet_processor_send_update (processor,
SC_OBJ_SEG, SS_OBJ_SEG,
(char *)pack + offset, n);
} else {
ccnet_processor_send_update (processor,
SC_OBJ_SEG_END, SS_OBJ_SEG_END,
(char *)pack + offset, n);
}
seaf_debug ("Sent object %s segment<total = %d, offset = %d, n = %d>\n",
object_id, pack_size, offset, n);
offset += n;
}
}
seaf_debug ("Send fs object %.8s.\n", object_id);
free (pack);
}
static void
fs_object_read_cb (OSAsyncResult *res, void *data)
{
CcnetProcessor *processor = data;
if (!res->success) {
seaf_warning ("Failed to read fs object %.8s.\n", res->obj_id);
ccnet_processor_send_update (processor, SC_NOT_FOUND, SS_NOT_FOUND,
res->obj_id, 41);
ccnet_processor_done (processor, FALSE);
return;
}
send_fs_object (processor, res->obj_id, res->data, res->len);
send_next_object (processor);
}
static void
read_fs_object (CcnetProcessor *processor, const char *obj_id)
{
USE_PRIV;
seaf_obj_store_async_read (seaf->fs_mgr->obj_store,
priv->reader_id,
obj_id);
}
static void
send_next_object (CcnetProcessor *processor)
{
USE_PRIV;
char *object_id;
if (priv->recv_obj_list == NULL) {
seaf_debug ("Send fs objects end.\n");
return;
}
object_id = priv->recv_obj_list->data;
priv->recv_obj_list = g_list_delete_link (priv->recv_obj_list,
priv->recv_obj_list);
read_fs_object (processor, object_id);
g_free (object_id);
}
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSendfsV2Proc *proc = (SeafileSendfsV2Proc *)processor;
TransferTask *task = proc->tx_task;
switch (processor->state) {
case INIT:
if (strncmp(code, SC_OK, 3) == 0) {
ccnet_processor_thread_create (processor, seaf->job_mgr,
calculate_send_object_list,
calculate_send_object_list_done,
processor);
processor->state = CHECK_OBJECT_LIST;
return;
}
break;
case CHECK_OBJECT_LIST:
if (strncmp (code, SC_OBJ_LIST_SEG, 3) == 0) {
process_object_list_segment (processor, content, clen);
send_object_list_segment (processor);
return;
}
break;
case SEND_OBJECTS:
if (strncmp (code, SC_END, 3) == 0) {
seaf_debug ("All objects received. Done.\n");
ccnet_processor_done (processor, TRUE);
return;
}
break;
default:
g_return_if_reached ();
}
seaf_warning ("Bad response: %s %s.\n", code, code_msg);
if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,33 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SENDFS_V2_PROC_H
#define SEAFILE_SENDFS_V2_PROC_H
#include <glib-object.h>
#include <ccnet/processor.h>
#include "transfer-mgr.h"
#define SEAFILE_TYPE_SENDFS_V2_PROC (seafile_sendfs_v2_proc_get_type ())
#define SEAFILE_SENDFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SENDFS_V2_PROC, SeafileSendfsV2Proc))
#define SEAFILE_IS_SENDFS_V2_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SENDFS_V2_PROC))
#define SEAFILE_SENDFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SENDFS_V2_PROC, SeafileSendfsV2ProcClass))
#define IS_SEAFILE_SENDFS_V2_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SENDFS_V2_PROC))
#define SEAFILE_SENDFS_V2_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SENDFS_V2_PROC, SeafileSendfsV2ProcClass))
typedef struct _SeafileSendfsV2Proc SeafileSendfsV2Proc;
typedef struct _SeafileSendfsV2ProcClass SeafileSendfsV2ProcClass;
struct _SeafileSendfsV2Proc {
CcnetProcessor parent_instance;
TransferTask *tx_task;
};
struct _SeafileSendfsV2ProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sendfs_v2_proc_get_type ();
#endif

View File

@ -1,131 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "common.h"
#include "seafile-session.h"
#include "repo-mgr.h"
#include "sync-mgr.h"
#include "utils.h"
#include "sync-repo-proc.h"
#include "sync-repo-common.h"
#define DEBUG_FLAG SEAFILE_DEBUG_SYNC
#include "log.h"
/*
client relay
sync-repo-slave <repo-id> <branch>
---------------------------------->
300 <head_commit>
<----------------------------------
or
301 No such repo
<----------------------------------
302 No such branch
<----------------------------------
*/
G_DEFINE_TYPE (SeafileSyncRepoProc, seafile_sync_repo_proc, CCNET_TYPE_PROCESSOR)
static int
sync_repo_start (CcnetProcessor *processor, int argc, char **argv);
static void
handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen);
static void
seafile_sync_repo_proc_class_init (SeafileSyncRepoProcClass *klass)
{
CcnetProcessorClass *proc_class = CCNET_PROCESSOR_CLASS (klass);
proc_class->name = "seafile-sync-repo";
proc_class->start = sync_repo_start;
proc_class->handle_response = handle_response;
}
static void
seafile_sync_repo_proc_init (SeafileSyncRepoProc *processor)
{
}
static int
sync_repo_start (CcnetProcessor *processor, int argc, char **argv)
{
SeafileSyncRepoProc *proc = (SeafileSyncRepoProc *) processor;
if (argc != 0) {
seaf_warning ("[sync-repo] argc should be 0.\n");
ccnet_processor_done (processor, FALSE);
return 0;
}
if (!proc->task) {
seaf_warning ("[sync-repo] Error: not provide info task.\n");
ccnet_processor_done (processor, FALSE);
return 0;
}
char buf[256];
/* Use a virutal "fetch_head" branch that works both on client and server. */
snprintf (buf, 256, "remote %s seafile-sync-repo-slave %s %s",
processor->peer_id, proc->task->info->repo_id, "fetch_head");
ccnet_processor_send_request (processor, buf);
return 0;
}
static void handle_response (CcnetProcessor *processor,
char *code, char *code_msg,
char *content, int clen)
{
SeafileSyncRepoProc *proc = (SeafileSyncRepoProc *)processor;
proc->task->info->deleted_on_relay = FALSE;
proc->task->info->branch_deleted_on_relay = FALSE;
proc->task->info->repo_corrupted = FALSE;
if (memcmp (code, SC_COMMIT_ID, 3) == 0) {
if (content[clen-1] != '\0') {
seaf_warning ("[sync-repo] Response not end with NULL\n");
ccnet_processor_done (processor, FALSE);
return;
}
/* g_debug ("[sync-repo] Get repo head commit %s\n", content); */
if (strlen(content) != 40) {
seaf_debug ("[sync-repo] Invalid commit id\n");
ccnet_processor_done (processor, FALSE);
return;
}
memcpy(proc->task->info->head_commit, content, 41);
ccnet_processor_done (processor, TRUE);
} else if (memcmp (code, SC_NO_REPO, 3) == 0) {
proc->task->info->deleted_on_relay = TRUE;
ccnet_processor_done (processor, TRUE);
} else if (memcmp (code, SC_NO_BRANCH, 3) == 0) {
proc->task->info->branch_deleted_on_relay = TRUE;
ccnet_processor_done (processor, TRUE);
} else if (memcmp (code, SC_REPO_CORRUPT, 3) == 0) {
proc->task->info->repo_corrupted = TRUE;
ccnet_processor_done (processor, TRUE);
} else
ccnet_processor_done (processor, FALSE);
}

View File

@ -1,37 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAFILE_SYNC_REPO_PROC_H
#define SEAFILE_SYNC_REPO_PROC_H
#include <glib-object.h>
#include <ccnet.h>
#define SEAFILE_TYPE_SYNC_REPO_PROC (seafile_sync_repo_proc_get_type ())
#define SEAFILE_SYNC_REPO_PROC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SYNC_REPO_PROC, SeafileSyncRepoProc))
#define SEAFILE_IS_SYNC_REPO_PROC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAFILE_TYPE_SYNC_REPO_PROC))
#define SEAFILE_SYNC_REPO_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SEAFILE_TYPE_SYNC_REPO_PROC, SeafileSyncRepoProcClass))
#define IS_SEAFILE_SYNC_REPO_PROC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAFILE_TYPE_SYNC_REPO_PROC))
#define SEAFILE_SYNC_REPO_PROC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAFILE_TYPE_SYNC_REPO_PROC, SeafileSyncRepoProcClass))
typedef struct _SeafileSyncRepoProc SeafileSyncRepoProc;
typedef struct _SeafileSyncRepoProcClass SeafileSyncRepoProcClass;
struct _SyncTask;
struct _SeafileSyncRepoProc {
CcnetProcessor parent_instance;
struct _SyncTask *task;
};
struct _SeafileSyncRepoProcClass {
CcnetProcessorClass parent_class;
};
GType seafile_sync_repo_proc_get_type ();
void
seafile_sync_repo_proc_set_repo (SeafileSyncRepoProc *processor,
char *repo_id);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -141,55 +141,12 @@ seaf_repo_set_name (SeafRepo *repo, const char *new_name);
GList *
seaf_repo_get_commits (SeafRepo *repo);
int
seaf_repo_index_add (SeafRepo *repo, const char *path);
int
seaf_repo_index_worktree_files (const char *repo_id,
int version,
const char *modifier,
const char *worktree,
const char *passwd,
int enc_version,
const char *random_key,
char *root_id);
int
seaf_repo_index_rm (SeafRepo *repo, const char *path);
char *
seaf_repo_status (SeafRepo *repo);
gboolean
seaf_repo_is_worktree_changed (SeafRepo *repo);
gboolean
seaf_repo_is_index_unmerged (SeafRepo *repo);
char *
seaf_repo_index_commit (SeafRepo *repo, const char *desc,
gboolean is_force_commit,
gboolean is_initial_commit,
GError **error);
int
seaf_repo_checkout (SeafRepo *repo, const char *worktree_parent, char **error);
int
seaf_repo_checkout_commit (SeafRepo *repo, SeafCommit *commit, gboolean recover_merge,
char **error);
enum {
MERGE_STATUS_UNKNOWN = 0,
MERGE_STATUS_UPTODATE,
MERGE_STATUS_FAST_FORWARD,
MERGE_STATUS_REAL_MERGE,
};
int
seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
int *merge_status);
GList *
seaf_repo_diff (SeafRepo *repo, const char *old, const char *new, int fold_dir_diff, char **error);
@ -321,68 +278,6 @@ seaf_repo_manager_set_repo_passwd (SeafRepoManager *manager,
SeafRepo *repo,
const char *passwd);
int
seaf_repo_manager_set_repo_relay_id (SeafRepoManager *mgr,
SeafRepo *repo,
const char *relay_id);
int
seaf_repo_manager_set_merge (SeafRepoManager *manager,
const char *repo_id,
const char *remote_head);
int
seaf_repo_manager_clear_merge (SeafRepoManager *manager,
const char *repo_id);
typedef struct {
gboolean in_merge;
char remote_head[41];
} SeafRepoMergeInfo;
int
seaf_repo_manager_get_merge_info (SeafRepoManager *manager,
const char *repo_id,
SeafRepoMergeInfo *info);
int
seaf_repo_manager_get_common_ancestor (SeafRepoManager *manager,
const char *repo_id,
char *common_ancestor,
char *head_id);
int
seaf_repo_manager_set_common_ancestor (SeafRepoManager *manager,
const char *repo_id,
const char *common_ancestor,
const char *head_id);
typedef struct {
char repo_id[41];
char worktree[SEAF_PATH_MAX];
int total_files;
int finished_files;
gboolean success;
} CheckoutTask;
typedef void (*CheckoutDoneCallback) (CheckoutTask *, SeafRepo *, void *);
int
seaf_repo_manager_add_checkout_task (SeafRepoManager *mgr,
SeafRepo *repo,
const char *worktree,
CheckoutDoneCallback done_cb,
void *cb_data);
CheckoutTask *
seaf_repo_manager_get_checkout_task (SeafRepoManager *mgr,
const char *repo_id);
int
seaf_repo_manager_update_repo_relay_info (SeafRepoManager *mgr,
SeafRepo *repo,
const char *new_addr,
const char *new_port);
int
seaf_repo_manager_update_repos_server_host (SeafRepoManager *mgr,
const char *old_host,
@ -427,9 +322,7 @@ struct _TransferTask;
struct _HttpTxTask;
int
seaf_repo_fetch_and_checkout (struct _TransferTask *task,
struct _HttpTxTask *http_task,
gboolean is_http,
seaf_repo_fetch_and_checkout (struct _HttpTxTask *http_task,
const char *remote_head_id);
gboolean

View File

@ -21,14 +21,11 @@
#include <c_bpwrapper.h>
#endif // HAVE_BREAKPAD_SUPPORT
#include <ccnet.h>
#include <searpc-server.h>
#include <searpc-client.h>
#include <searpc.h>
#include <searpc-named-pipe-transport.h>
#include "seafile-session.h"
#include "seafile-rpc.h"
#include <ccnet/rpcserver-proc.h>
#include <ccnet/threaded-rpcserver-proc.h>
#include "log.h"
#include "utils.h"
#include "vc-utils.h"
@ -45,9 +42,6 @@
SeafileSession *seaf;
SearpcClient *ccnetrpc_client;
SearpcClient *appletrpc_client;
CcnetClient *bind_client;
static const char *short_options = "hvc:d:w:l:D:bg:G:";
static struct option long_options[] = {
@ -73,18 +67,15 @@ static void usage ()
#include "searpc-signature.h"
#include "searpc-marshal.h"
#define SEAFILE_SOCKET_NAME "seafile.sock"
static void
start_rpc_service (CcnetClient *client)
register_rpc_service ()
{
searpc_server_init (register_marshals);
searpc_create_service ("seafile-rpcserver");
ccnet_register_service (client, "seafile-rpcserver", "rpc-inner",
CCNET_TYPE_RPCSERVER_PROC, NULL);
searpc_create_service ("seafile-threaded-rpcserver");
ccnet_register_service (client, "seafile-threaded-rpcserver", "rpc-inner",
CCNET_TYPE_THREADED_RPCSERVER_PROC, NULL);
/* seafile-rpcserver */
searpc_server_register_function ("seafile-rpcserver",
@ -161,21 +152,6 @@ start_rpc_service (CcnetClient *client)
"seafile_get_repo_property",
searpc_signature_string__string_string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_repo_relay_address,
"seafile_get_repo_relay_address",
searpc_signature_string__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_repo_relay_port,
"seafile_get_repo_relay_port",
searpc_signature_string__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_update_repo_relay_info,
"seafile_update_repo_relay_info",
searpc_signature_int__string_string_string());
searpc_server_register_function ("seafile-rpcserver",
seafile_update_repos_server_host,
"seafile_update_repos_server_host",
@ -196,10 +172,6 @@ start_rpc_service (CcnetClient *client)
"seafile_is_auto_sync_enabled",
searpc_signature_int__void());
searpc_server_register_function ("seafile-rpcserver",
seafile_branch_gets,
"seafile_branch_gets",
searpc_signature_objlist__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_gen_default_worktree,
"gen_default_worktree",
@ -208,7 +180,7 @@ start_rpc_service (CcnetClient *client)
seafile_check_path_for_clone,
"seafile_check_path_for_clone",
searpc_signature_int__string());
/* clone means sync with existing folder, download means sync to a new folder. */
searpc_server_register_function ("seafile-rpcserver",
seafile_clone,
@ -244,11 +216,6 @@ start_rpc_service (CcnetClient *client)
"seafile_get_repo",
searpc_signature_object__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_sync_task_list,
"seafile_get_sync_task_list",
searpc_signature_objlist__void());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_repo_sync_task,
"seafile_get_repo_sync_task",
@ -259,25 +226,6 @@ start_rpc_service (CcnetClient *client)
"seafile_get_repo_sync_info",
searpc_signature_object__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_commit,
"seafile_get_commit",
searpc_signature_object__string_int_string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_commit_list,
"seafile_get_commit_list",
searpc_signature_objlist__string_int_int());
searpc_server_register_function ("seafile-rpcserver",
seafile_find_transfer_task,
"seafile_find_transfer_task",
searpc_signature_object__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_checkout_task,
"seafile_get_checkout_task",
searpc_signature_object__string());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_path_sync_status,
"seafile_get_path_sync_status",
@ -313,6 +261,11 @@ start_rpc_service (CcnetClient *client)
"seafile_get_file_sync_errors",
searpc_signature_objlist__int_int());
searpc_server_register_function ("seafile-rpcserver",
seafile_get_sync_notification,
"seafile_get_sync_notification",
searpc_signature_json__void());
/* Need to run in a thread since diff may take long. */
searpc_server_register_function ("seafile-threaded-rpcserver",
seafile_diff,
@ -320,34 +273,45 @@ start_rpc_service (CcnetClient *client)
searpc_signature_objlist__string_string_string_int());
}
static int
start_searpc_server ()
{
register_rpc_service ();
#ifdef WIN32
DWORD bufCharCount = 32767;
char userNameBuf[bufCharCount];
if (GetUserName(userNameBuf, &bufCharCount) == 0) {
seaf_warning ("Failed to get user name, GLE=%lu, required size is %lu\n",
GetLastError(), bufCharCount);
return -1;
}
char *path = g_strdup_printf("\\\\.\\pipe\\seafile_%s", userNameBuf);
#else
char *path = g_build_filename (seaf->seaf_dir, SEAFILE_SOCKET_NAME, NULL);
#endif
SearpcNamedPipeServer *server = searpc_create_named_pipe_server (path);
if (!server) {
seaf_warning ("Failed to create named pipe server.\n");
g_free (path);
return -1;
}
seaf->rpc_socket_path = path;
return searpc_named_pipe_server_start (server);
}
#ifndef WIN32
static void
set_signal_handlers (SeafileSession *session)
{
#ifndef WIN32
signal (SIGPIPE, SIG_IGN);
}
#endif
}
static void
create_sync_rpc_clients (const char *config_dir)
{
CcnetClient *sync_client;
/* sync client and rpc client */
sync_client = ccnet_client_new ();
if ( (ccnet_client_load_confdir(sync_client, NULL, config_dir)) < 0 ) {
seaf_warning ("Read config dir error\n");
exit(1);
}
if (ccnet_client_connect_daemon (sync_client, CCNET_CLIENT_SYNC) < 0)
{
seaf_warning ("Connect to server fail: %s\n", strerror(errno));
exit(1);
}
ccnetrpc_client = ccnet_create_rpc_client (sync_client, NULL, "ccnet-rpcserver");
}
#ifdef WIN32
/* Get the commandline arguments in unicode, then convert them to utf8 */
@ -360,7 +324,7 @@ get_argv_utf8 (int *argc)
wchar_t **argv_w = NULL;
cmdline = GetCommandLineW();
argv_w = CommandLineToArgvW (cmdline, argc);
argv_w = CommandLineToArgvW (cmdline, argc);
if (!argv_w) {
printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError());
return NULL;
@ -375,35 +339,6 @@ get_argv_utf8 (int *argc)
}
#endif
/*
* Bind to an unused service to make sure only one instance of seaf-daemon
* is running.
*/
static gboolean
bind_ccnet_service (const char *config_dir)
{
gboolean ret = TRUE;
bind_client = ccnet_client_new ();
if ( (ccnet_client_load_confdir(bind_client, NULL, config_dir)) < 0 ) {
seaf_warning ("Read config dir error\n");
exit(1);
}
if (ccnet_client_connect_daemon (bind_client, CCNET_CLIENT_SYNC) < 0)
{
seaf_warning ("Connect to server fail: %s\n", strerror(errno));
exit(1);
}
if (!ccnet_register_service_sync (bind_client,
"seafile-dummy-service",
"rpc-inner"))
ret = FALSE;
return ret;
}
int
main (int argc, char **argv)
{
@ -417,6 +352,13 @@ main (int argc, char **argv)
checkdir_with_mkdir(dump_dir);
CBPWrapperExceptionHandler bp_exception_handler = newCBPWrapperExceptionHandler(dump_dir);
#endif
#ifdef WIN32
#define DEFAULT_CONFIG_DIR "~/ccnet"
#else
#define DEFAULT_CONFIG_DIR "~/.ccnet"
#endif
int c;
char *config_dir = DEFAULT_CONFIG_DIR;
char *seafile_dir = NULL;
@ -424,7 +366,6 @@ main (int argc, char **argv)
char *logfile = NULL;
const char *debug_str = NULL;
int daemon_mode = 0;
CcnetClient *client;
char *ccnet_debug_level_str = "info";
char *seafile_debug_level_str = "debug";
@ -434,7 +375,7 @@ main (int argc, char **argv)
argv = get_argv_utf8 (&argc);
#endif
while ((c = getopt_long (argc, argv, short_options,
while ((c = getopt_long (argc, argv, short_options,
long_options, NULL)) != EOF)
{
switch (c) {
@ -525,35 +466,17 @@ main (int argc, char **argv)
exit (1);
}
if (!bind_ccnet_service (config_dir)) {
seaf_warning ("Failed to bind ccnet service\n");
exit (1);
}
/* init ccnet */
client = ccnet_init (NULL, config_dir);
if (!client)
exit (1);
start_rpc_service (client);
create_sync_rpc_clients (config_dir);
appletrpc_client = ccnet_create_async_rpc_client (client, NULL,
"applet-rpcserver");
/* init seafile */
if (seafile_dir == NULL)
seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
if (worktree_dir == NULL)
worktree_dir = g_build_filename (g_get_home_dir(), "seafile", NULL);
seaf = seafile_session_new (seafile_dir, worktree_dir, client);
seaf = seafile_session_new (seafile_dir, worktree_dir, config_dir);
if (!seaf) {
seaf_warning ("Failed to create seafile session.\n");
exit (1);
}
seaf->ccnetrpc_client = ccnetrpc_client;
seaf->appletrpc_client = appletrpc_client;
seaf_message ("starting seafile client "SEAFILE_CLIENT_VERSION"\n");
#if defined(SEAFILE_SOURCE_COMMIT_ID)
@ -564,7 +487,12 @@ main (int argc, char **argv)
g_free (worktree_dir);
g_free (logfile);
#ifndef WIN32
set_signal_handlers (seaf);
#else
WSADATA wsadata;
WSAStartup (0x0101, &wsadata);
#endif
#ifndef USE_GPL_CRYPTO
seafile_curl_init();
@ -572,8 +500,18 @@ main (int argc, char **argv)
seafile_session_prepare (seaf);
seafile_session_start (seaf);
if (start_searpc_server () < 0) {
seaf_warning ("Failed to start searpc server.\n");
exit (1);
}
seaf_message ("rpc server started.\n");
seafile_session_config_set_string (seaf, "wktree", seaf->worktree_dir);
ccnet_main (client);
event_base_loop (seaf->ev_base, 0);
#ifndef USE_GPL_CRYPTO
seafile_curl_deinit();
#endif

View File

@ -6,6 +6,7 @@
#include "seafile-session.h"
#include "db.h"
#define KEY_CLIENT_ID "client_id"
#define KEY_CLIENT_NAME "client_name"
#define KEY_MONITOR_ID "monitor_id"

View File

@ -14,17 +14,21 @@
#include <string.h>
#include <errno.h>
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#else
#include <event.h>
#endif
#include <glib.h>
#include <ccnet.h>
#include <ccnet/cevent.h>
#include <ccnet/ccnet-object.h>
#include <utils.h>
#include "utils.h"
#include "seafile-session.h"
#include "seafile-config.h"
#include "vc-utils.h"
#include "seaf-utils.h"
#include "log.h"
#define MAX_THREADS 50
@ -134,23 +138,20 @@ out:
SeafileSession *
seafile_session_new(const char *seafile_dir,
const char *worktree_dir,
struct _CcnetClient *ccnet_session)
const char *ccnet_dir)
{
char *abs_seafile_dir;
char *abs_worktree_dir;
char *abs_ccnet_dir;
char *tmp_file_dir;
char *db_path;
char *deleted_store;
sqlite3 *config_db;
SeafileSession *session = NULL;
#ifndef SEAF_TOOL
if (!ccnet_session)
return NULL;
#endif
abs_worktree_dir = ccnet_expand_path (worktree_dir);
abs_seafile_dir = ccnet_expand_path (seafile_dir);
abs_ccnet_dir = ccnet_expand_path (ccnet_dir);
tmp_file_dir = g_build_filename (abs_seafile_dir, "tmpfiles", NULL);
db_path = g_build_filename (abs_seafile_dir, "config.db", NULL);
deleted_store = g_build_filename (abs_seafile_dir, "deleted_store", NULL);
@ -183,10 +184,11 @@ seafile_session_new(const char *seafile_dir,
}
session = g_object_new (SEAFILE_TYPE_SESSION, NULL);
session->ev_base = event_base_new ();
session->seaf_dir = abs_seafile_dir;
session->tmp_file_dir = tmp_file_dir;
session->worktree_dir = abs_worktree_dir;
session->session = ccnet_session;
session->ccnet_dir = abs_ccnet_dir;
session->config_db = config_db;
session->deleted_store = deleted_store;
@ -206,9 +208,6 @@ seafile_session_new(const char *seafile_dir,
if (!session->branch_mgr)
goto onerror;
session->transfer_mgr = seaf_transfer_manager_new (session);
if (!session->transfer_mgr)
goto onerror;
session->clone_mgr = seaf_clone_manager_new (session);
if (!session->clone_mgr)
goto onerror;
@ -226,13 +225,12 @@ seafile_session_new(const char *seafile_dir,
if (!session->filelock_mgr)
goto onerror;
session->job_mgr = ccnet_job_manager_new (MAX_THREADS);
ccnet_session->job_mgr = ccnet_job_manager_new (MAX_THREADS);
session->job_mgr = seaf_job_manager_new (session, MAX_THREADS);
session->ev_mgr = cevent_manager_new ();
if (!session->ev_mgr)
goto onerror;
session->mq_mgr = seaf_mq_manager_new (session);
session->mq_mgr = seaf_mq_manager_new ();
if (!session->mq_mgr)
goto onerror;
@ -241,6 +239,7 @@ seafile_session_new(const char *seafile_dir,
onerror:
free (abs_seafile_dir);
free (abs_worktree_dir);
free (abs_ccnet_dir);
g_free (tmp_file_dir);
g_free (db_path);
g_free (deleted_store);
@ -298,15 +297,91 @@ out:
json_decref(json);
}
static char *
generate_client_id ()
{
char *uuid = gen_uuid();
unsigned char buf[20];
char sha1[41];
calculate_sha1 (buf, uuid, 20);
rawdata_to_hex (buf, sha1, 20);
g_free (uuid);
return g_strdup(sha1);
}
static void
read_ccnet_conf (const char *ccnet_dir, char **client_id, char **client_name)
{
char *ccnet_conf_path = g_build_path ("/", ccnet_dir, "ccnet.conf", NULL);
GKeyFile *key_file = g_key_file_new ();
GError *error = NULL;
if (!g_file_test (ccnet_conf_path, G_FILE_TEST_IS_REGULAR))
goto out;
if (!g_key_file_load_from_file (key_file, ccnet_conf_path, 0, &error)) {
seaf_warning ("Failed to read ccnet.conf: %s.\n", error->message);
g_clear_error (&error);
goto out;
}
*client_id = g_key_file_get_string (key_file, "General", "ID", &error);
if (error) {
seaf_warning ("Failed to read client id from ccnet.conf: %s.\n", error->message);
g_clear_error (&error);
goto out;
}
*client_name = g_key_file_get_string (key_file, "General", "NAME", &error);
if (error) {
seaf_warning ("Failed to read client name from ccnet.conf: %s.\n", error->message);
g_clear_error (&error);
goto out;
}
out:
g_free (ccnet_conf_path);
g_key_file_free (key_file);
}
void
seafile_session_prepare (SeafileSession *session)
{
session->client_name = seafile_session_config_get_string (session, KEY_CLIENT_NAME);
if (!session->client_name) {
session->client_name = g_strdup(session->session->base.name);
}
char *client_id = NULL, *client_name = NULL;
/* load config */
read_ccnet_conf (session->ccnet_dir, &client_id, &client_name);
session->client_id = seafile_session_config_get_string (session, KEY_CLIENT_ID);
if (!session->client_id) {
if (client_id) {
session->client_id = g_strdup (client_id);
} else {
session->client_id = generate_client_id();
}
seafile_session_config_set_string (session,
KEY_CLIENT_ID,
session->client_id);
}
session->client_name = seafile_session_config_get_string (session, KEY_CLIENT_NAME);
if (!session->client_name) {
if (client_name) {
session->client_name = g_strdup (client_name);
seafile_session_config_set_string (session,
KEY_CLIENT_NAME,
session->client_name);
} else {
session->client_name = g_strdup("unknown");
}
}
g_free (client_id);
g_free (client_name);
session->sync_extra_temp_file = seafile_session_config_get_bool
(session, KEY_SYNC_EXTRA_TEMP_FILE);
@ -349,8 +424,6 @@ seafile_session_prepare (SeafileSession *session)
#ifndef SEAF_TOOL
seaf_sync_manager_init (session->sync_mgr);
#endif
seaf_mq_manager_set_heartbeat_name (session->mq_mgr,
"seafile.heartbeat");
}
/* static void */
@ -456,11 +529,6 @@ cleanup_job_done (void *vdata)
return;
}
if (seaf_transfer_manager_start (session->transfer_mgr) < 0) {
g_error ("Failed to start transfer manager.\n");
return;
}
if (http_tx_manager_start (session->http_tx_mgr) < 0) {
g_error ("Failed to start http transfer manager.\n");
return;
@ -499,45 +567,16 @@ cleanup_job_done (void *vdata)
static void
on_start_cleanup (SeafileSession *session)
{
ccnet_job_manager_schedule_job (seaf->job_mgr,
on_start_cleanup_job,
cleanup_job_done,
session);
seaf_job_manager_schedule_job (seaf->job_mgr,
on_start_cleanup_job,
cleanup_job_done,
session);
}
void
seafile_session_start (SeafileSession *session)
{
/* MQ must be started to send heartbeat message to applet. */
if (seaf_mq_manager_start (session->mq_mgr) < 0) {
g_error ("Failed to start mq manager.\n");
return;
}
/* Finish cleanup task before anything is run. */
on_start_cleanup (session);
}
#if 0
void
seafile_session_add_event (SeafileSession *session,
const char *type,
const char *first, ...)
{
gchar *body;
va_list args;
va_start (args, first);
body = key_value_list_to_json_v (first, args);
va_end (args);
CcnetEvent *event = g_object_new (CCNET_TYPE_EVENT,
"etype", type,
"body", body, NULL);
ccnet_client_send_event(session->session, (GObject *)event);
g_object_unref (event);
g_free (body);
}
#endif

View File

@ -4,9 +4,8 @@
#define SEAFILE_SESSION_H
#include <glib-object.h>
#include <ccnet/cevent.h>
#include <ccnet/mqclient-proc.h>
#include <ccnet/job-mgr.h>
#include "cevent.h"
#include "job-mgr.h"
#include "block-mgr.h"
#include "fs-mgr.h"
@ -16,7 +15,6 @@
#include "clone-mgr.h"
#include "db.h"
#include "transfer-mgr.h"
#include "sync-mgr.h"
#include "wt-monitor.h"
#include "mq-mgr.h"
@ -24,10 +22,6 @@
#include "http-tx-mgr.h"
#include "filelock-mgr.h"
#include <searpc-client.h>
struct _CcnetClient;
#define SEAFILE_TYPE_SESSION (seafile_session_get_type ())
#define SEAFILE_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAFILE_TYPE_SESSION, SeafileSession))
@ -40,36 +34,37 @@ struct _CcnetClient;
typedef struct _SeafileSession SeafileSession;
typedef struct _SeafileSessionClass SeafileSessionClass;
struct event_base;
struct _SeafileSession {
GObject parent_instance;
struct _CcnetClient *session;
struct event_base *ev_base;
char *client_id;
char *client_name;
SearpcClient *ccnetrpc_client;
SearpcClient *appletrpc_client;
char *seaf_dir;
char *tmp_file_dir;
char *worktree_dir; /* the default directory for
* storing worktrees */
char *ccnet_dir;
sqlite3 *config_db;
char *deleted_store;
char *rpc_socket_path;
SeafBlockManager *block_mgr;
SeafFSManager *fs_mgr;
SeafCommitManager *commit_mgr;
SeafBranchManager *branch_mgr;
SeafRepoManager *repo_mgr;
SeafTransferManager *transfer_mgr;
SeafCloneManager *clone_mgr;
SeafSyncManager *sync_mgr;
SeafWTMonitor *wt_monitor;
SeafMqManager *mq_mgr;
CEventManager *ev_mgr;
CcnetJobManager *job_mgr;
SeafJobManager *job_mgr;
HttpTxManager *http_tx_mgr;
@ -101,7 +96,7 @@ extern SeafileSession *seaf;
SeafileSession *
seafile_session_new(const char *seafile_dir,
const char *worktree_dir,
struct _CcnetClient *ccnet_session);
const char *config_dir);
void
seafile_session_prepare (SeafileSession *session);

View File

@ -1,378 +0,0 @@
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "seafile-session.h"
#include "status.h"
#include "fs-mgr.h"
#include "index/index.h"
#include "diff-simple.h"
#include "vc-utils.h"
#include "utils.h"
#include "cdc/cdc.h"
#include "log.h"
struct dir_entry {
unsigned int len;
char name[0]; /* more */
};
struct dir_struct {
int nr, alloc;
int ignored_nr, ignored_alloc;
enum {
DIR_SHOW_IGNORED = 1<<0,
DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
DIR_NO_GITLINKS = 1<<3,
DIR_COLLECT_IGNORED = 1<<4
} flags;
struct dir_entry **entries;
struct dir_entry **ignored;
};
static struct dir_entry *
dir_entry_new(const char *pathname, int len)
{
struct dir_entry *ent;
ent = malloc(sizeof(*ent) + len + 1);
ent->len = len;
memcpy(ent->name, pathname, len);
ent->name[len] = 0;
return ent;
}
static struct dir_entry *
dir_add_name(struct dir_struct *dir, const char *pathname,
int len, struct index_state *index)
{
if (index_name_exists(index, pathname, len, 0))
return NULL;
ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
}
static inline int
is_dot_or_dotdot(const char *name)
{
return (name[0] == '.' &&
(name[1] == '\0' ||
(name[1] == '.' && name[2] == '\0')));
}
static int
get_dtype(const char *dname, const char *path)
{
SeafStat st;
int dtype = DT_UNKNOWN;
char *realpath = g_build_path (PATH_SEPERATOR, path, dname, NULL);
if (!seaf_stat(realpath, &st)) {
if (S_ISREG(st.st_mode))
dtype = DT_REG;
if (S_ISDIR(st.st_mode))
dtype = DT_DIR;
}
g_free(realpath);
return dtype;
}
static int
read_directory_recursive(struct dir_struct *dir,
const char *base, int baselen,
int check_only,
struct index_state *index,
const char *worktree,
IgnoreFunc ignore_func,
void *data)
{
char *realpath = g_build_path (PATH_SEPERATOR, worktree, base, NULL);
GDir *fdir = g_dir_open (realpath, 0, NULL);
const char *dname;
char *nfc_dname;
int contents = 0;
int dtype;
if (fdir) {
char path[SEAF_PATH_MAX + 1];
memcpy(path, base, baselen);
while ((dname = g_dir_read_name(fdir)) != NULL) {
int len = 0;
#ifdef __APPLE__
nfc_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC);
#else
nfc_dname = g_strdup(dname);
#endif
if (is_dot_or_dotdot(nfc_dname)) {
g_free (nfc_dname);
continue;
}
if (ignore_func (realpath, nfc_dname, data)) {
g_free (nfc_dname);
continue;
}
dtype = get_dtype(nfc_dname, realpath);
switch (dtype) {
case DT_REG:
len = strlen(nfc_dname);
memcpy(path + baselen, nfc_dname, len + 1);
len = strlen(path);
break;
case DT_DIR:
len = strlen(nfc_dname);
memcpy(path + baselen, nfc_dname, len + 1);
memcpy(path + baselen + len, "/", 2);
len = strlen(path);
read_directory_recursive(dir, path, len, 0,
index, worktree, ignore_func, data);
g_free (nfc_dname);
continue;
default: /* DT_UNKNOWN */
len = 0;
break;
}
if(len > 0)
dir_add_name(dir, path, len, index);
g_free (nfc_dname);
}
g_dir_close(fdir);
}
g_free(realpath);
return contents;
}
static int
cmp_name(const void *p1, const void *p2)
{
const struct dir_entry *e1 = *(const struct dir_entry **)p1;
const struct dir_entry *e2 = *(const struct dir_entry **)p2;
return cache_name_compare(e1->name, e1->len,
e2->name, e2->len);
}
static int
read_directory(struct dir_struct *dir,
const char *worktree,
struct index_state *index,
IgnoreFunc ignore_func)
{
GList *ignore_list = NULL;
ignore_list = seaf_repo_load_ignore_files(worktree);
read_directory_recursive(dir, "", 0, 0, index, worktree,
ignore_func, ignore_list);
seaf_repo_free_ignore_files(ignore_list);
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
return dir->nr;
}
void wt_status_collect_untracked(struct index_state *index,
GList **results,
const char *worktree,
IgnoreFunc ignore_func)
{
int i;
struct dir_struct dir;
DiffEntry *de;
memset(&dir, 0, sizeof(dir));
read_directory(&dir, worktree, index, ignore_func);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
unsigned char sha1[20] = { 0 };
de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_ADDED, sha1, ent->name);
*results = g_list_prepend (*results, de);
free(ent);
}
free(dir.entries);
}
void wt_status_collect_changes_worktree(struct index_state *index,
GList **results,
const char *worktree)
{
DiffEntry *de;
int entries, i;
GList *ignore_list = seaf_repo_load_ignore_files (worktree);
entries = index->cache_nr;
for (i = 0; i < entries; i++) {
char *realpath;
SeafStat st;
struct cache_entry *ce = index->cache[i];
int changed = 0;
if (ce_stage(ce)) {
int mask = 0;
mask |= 1 << ce_stage(ce);
while (i < entries) {
struct cache_entry *nce = index->cache[i];
if (strcmp(ce->name, nce->name))
break;
mask |= 1 << ce_stage(nce);
i++;
}
/*
* Compensate for loop update
*/
i--;
de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_UNMERGED,
ce->sha1, ce->name);
de->unmerge_state = diff_unmerged_state (mask);
*results = g_list_prepend (*results, de);
continue;
}
if (ce_uptodate(ce) || ce_skip_worktree(ce))
continue;
realpath = g_build_path (PATH_SEPERATOR, worktree, ce->name, NULL);
if (seaf_stat(realpath, &st) < 0) {
if (errno != ENOENT && errno != ENOTDIR)
changed = -1;
else
changed = 1;
}
if (changed) {
if (changed < 0) {
seaf_warning ("Faile to stat %s: %s\n", ce->name, strerror(errno));
g_free (realpath);
continue;
}
if (ce->ce_ctime.sec == 0) {
g_free (realpath);
continue;
}
de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_DELETED,
ce->sha1, ce->name);
*results = g_list_prepend (*results, de);
g_free (realpath);
continue;
}
if (S_ISDIR (ce->ce_mode)) {
g_free (realpath);
continue;
}
/* Don't check changes to ignored files.
* This can happen when a file is committed and then added to
* ignore.txt. After that changes to this file will not committed,
* and it should be ignored here.
*/
if (seaf_repo_check_ignore_file (ignore_list, realpath)) {
g_free (realpath);
continue;
}
g_free (realpath);
changed = ie_match_stat (ce, &st, 0);
if (!changed) {
ce_mark_uptodate (ce);
continue;
}
de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_MODIFIED,
ce->sha1, ce->name);
*results = g_list_prepend (*results, de);
}
seaf_repo_free_ignore_files (ignore_list);
}
static struct cache_entry *
next_cache_entry(struct index_state *index, int *pos)
{
while (*pos < index->cache_nr) {
struct cache_entry *ce = index->cache[*pos];
(*pos)++;
if (!(ce->ce_flags & CE_UNPACKED))
return ce;
}
return NULL;
}
void
wt_status_collect_changes_index (struct index_state *index,
GList **results,
SeafRepo *repo)
{
SeafFSManager *fs_mgr;
SeafCommit *head;
int pos = 0;
DiffEntry *de;
fs_mgr = repo->manager->seaf->fs_mgr;
head = seaf_commit_manager_get_commit (seaf->commit_mgr,
repo->id, repo->version,
repo->head->commit_id);
if (!head) {
seaf_warning ("Failed to get commit %s:%s.\n",
repo->id, repo->head->commit_id);
return;
}
mark_all_ce_unused (index);
/* if repo is initial, we don't need to check index changes */
if (strncmp(EMPTY_SHA1, head->root_id, 40) != 0) {
SeafDir *root;
/* call diff_index to get status */
root = seaf_fs_manager_get_seafdir (fs_mgr,
repo->id,
repo->version,
head->root_id);
if (!root) {
seaf_warning ("Failed to get root %s:%s.\n",
repo->id, head->root_id);
seaf_commit_unref (head);
return;
}
if (diff_index(repo->id, repo->version, index, root, results) < 0)
seaf_warning("diff index failed\n");
seaf_dir_free (root);
seaf_commit_unref (head);
return;
}
seaf_commit_unref (head);
while (1) {
struct cache_entry *ce = next_cache_entry(index, &pos);
if (!ce || ce_stage(ce))
break;
ce->ce_flags |= CE_UNPACKED;
de = diff_entry_new (DIFF_TYPE_INDEX, DIFF_STATUS_ADDED, ce->sha1, ce->name);
*results = g_list_prepend (*results, de);
}
}

View File

@ -1,28 +0,0 @@
#ifndef STATUS_H
#define STATUS_H
#include <glib.h>
#include "repo-mgr.h"
#include "index/index.h"
#include "diff-simple.h"
typedef gboolean (*IgnoreFunc) (const char *basepath, const char *filename, void *data);
void
wt_status_collect_changes_worktree(struct index_state *index,
GList **results,
const char *worktree);
void
wt_status_collect_untracked(struct index_state *index,
GList **results,
const char *worktree,
IgnoreFunc ignore_func);
void
wt_status_collect_changes_index (struct index_state *index,
GList **results,
SeafRepo *repo);
#endif /* STATUS_H */

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ typedef struct _SyncTask SyncTask;
typedef struct _SeafSyncManager SeafSyncManager;
typedef struct _SeafSyncManagerPriv SeafSyncManagerPriv;
struct CcnetTimer;
struct SeafTimer;
struct _SyncInfo {
char repo_id[41]; /* the repo */
@ -86,12 +86,10 @@ struct _SyncTask {
char *err_detail;
char *tx_id;
char *token;
struct CcnetTimer *commit_timer;
struct SeafTimer *commit_timer;
gboolean server_side_merge;
gboolean uploaded;
gboolean http_sync;
int http_version;
SeafRepo *repo; /* for convenience, only valid when in_sync. */
@ -121,7 +119,6 @@ struct _SeafSyncManager {
gboolean commit_job_running;
int sync_interval;
GHashTable *server_states;
GHashTable *http_server_states;
/* Sent/recv bytes from all transfer tasks in this second.

89
daemon/timer.c Normal file
View File

@ -0,0 +1,89 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#else
#include <event.h>
#endif
#include <sys/time.h>
#include "seafile-session.h"
#include "utils.h"
#include "timer.h"
struct SeafTimer
{
struct event *event;
struct timeval tv;
TimerCB func;
void *user_data;
uint8_t in_callback;
};
static void
timer_callback (evutil_socket_t fd, short event, void *vtimer)
{
int more;
struct SeafTimer *timer = vtimer;
timer->in_callback = 1;
more = (*timer->func) (timer->user_data);
timer->in_callback = 0;
if (more)
evtimer_add (timer->event, &timer->tv);
else
seaf_timer_free (&timer);
}
void
seaf_timer_free (SeafTimer **ptimer)
{
SeafTimer *timer;
/* zero out the argument passed in */
g_return_if_fail (ptimer);
timer = *ptimer;
*ptimer = NULL;
/* destroy the timer directly or via the command queue */
if (timer && !timer->in_callback)
{
event_del (timer->event);
event_free (timer->event);
g_free (timer);
}
}
struct timeval
timeval_from_msec (uint64_t milliseconds)
{
struct timeval ret;
const uint64_t microseconds = milliseconds * 1000;
ret.tv_sec = microseconds / 1000000;
ret.tv_usec = microseconds % 1000000;
return ret;
}
SeafTimer*
seaf_timer_new (TimerCB func,
void *user_data,
uint64_t interval_milliseconds)
{
SeafTimer *timer = g_new0 (SeafTimer, 1);
timer->tv = timeval_from_msec (interval_milliseconds);
timer->func = func;
timer->user_data = user_data;
timer->event = evtimer_new (seaf->ev_base, timer_callback, timer);
evtimer_add (timer->event, &timer->tv);
return timer;
}

28
daemon/timer.h Normal file
View File

@ -0,0 +1,28 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef SEAF_TIMER_H
#define SEAF_TIMER_H
/* return TRUE to reschedule the timer, return FALSE to cancle the timer */
typedef int (*TimerCB) (void *data);
struct SeafTimer;
typedef struct SeafTimer SeafTimer;
/**
* Calls timer_func(user_data) after the specified interval.
* The timer is freed if timer_func returns zero.
* Otherwise, it's called again after the same interval.
*/
SeafTimer* seaf_timer_new (TimerCB func,
void *user_data,
uint64_t timeout_milliseconds);
/**
* Frees a timer and sets the timer pointer to NULL.
*/
void seaf_timer_free (SeafTimer **timer);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,285 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef TRANSFER_MGR_H
#define TRANSFER_MGR_H
#include <glib.h>
#include <ccnet/timer.h>
#include <ccnet/peer.h>
#include "object-list.h"
#include "repo-mgr.h"
#include "fs-mgr.h"
#include "branch-mgr.h"
/*
* Transfer Task.
*/
enum {
TASK_TYPE_DOWNLOAD = 0,
TASK_TYPE_UPLOAD,
};
/**
* The state that can be set by user.
*
* A task in NORMAL state can be canceled;
* A task in RT_STATE_FINISHED can be removed.
*/
enum TaskState {
TASK_STATE_NORMAL = 0,
TASK_STATE_CANCELED,
TASK_STATE_FINISHED,
TASK_STATE_ERROR,
N_TASK_STATE,
};
enum TaskRuntimeState {
TASK_RT_STATE_INIT = 0,
TASK_RT_STATE_CHECK,
TASK_RT_STATE_COMMIT,
TASK_RT_STATE_FS,
TASK_RT_STATE_CHECK_BLOCKS,
TASK_RT_STATE_CHUNK_SERVER,
TASK_RT_STATE_DATA,
TASK_RT_STATE_UPDATE_BRANCH, /* Only used in upload. */
TASK_RT_STATE_FINISHED,
TASK_RT_STATE_NETDOWN,
N_TASK_RT_STATE,
};
enum TaskError {
TASK_OK = 0,
TASK_ERR_UNKNOWN,
TASK_ERR_NO_SERVICE,
TASK_ERR_PROC_PERM_ERR,
TASK_ERR_CHECK_UPLOAD_START,
TASK_ERR_CHECK_DOWNLOAD_START,
TASK_ERR_ACCESS_DENIED,
TASK_ERR_BAD_REPO_ID,
TASK_ERR_UPLOAD_COMMIT_START,
TASK_ERR_DOWNLOAD_COMMIT_START,
TASK_ERR_UPLOAD_COMMIT,
TASK_ERR_DOWNLOAD_COMMIT,
TASK_ERR_UPLOAD_FS_START,
TASK_ERR_DOWNLOAD_FS_START,
TASK_ERR_LOAD_FS,
TASK_ERR_UPLOAD_FS,
TASK_ERR_DOWNLOAD_FS,
TASK_ERR_LOAD_BLOCK_LIST,
TASK_ERR_START_UPDATE_BRANCH,
TASK_ERR_NOT_FAST_FORWARD,
TASK_ERR_QUOTA_FULL,
TASK_ERR_CHECK_QUOTA,
TASK_ERR_PROTOCOL_VERSION,
TASK_ERR_BAD_LOCAL_BRANCH,
TASK_ERR_CHECK_BLOCK_LIST,
TASK_ERR_GET_CHUNK_SERVER,
TASK_ERR_START_BLOCK_CLIENT,
TASK_ERR_UPLOAD_BLOCKS,
TASK_ERR_DOWNLOAD_BLOCKS,
TASK_ERR_DEPRECATED_SERVER,
TASK_ERR_FILES_LOCKED,
N_TASK_ERROR,
};
typedef struct {
char *addr;
int port;
} ChunkServer;
enum {
BLOCK_CLIENT_UNKNOWN = 0,
BLOCK_CLIENT_SUCCESS,
BLOCK_CLIENT_FAILED,
BLOCK_CLIENT_NET_ERROR,
BLOCK_CLIENT_SERVER_ERROR,
BLOCK_CLIENT_CANCELED,
/* result codes only used in interactive mode. */
BLOCK_CLIENT_READY,
BLOCK_CLIENT_ENDED,
};
#define BLOCK_TX_SESSION_KEY_LEN 32
struct _TransferTask;
typedef struct _BlockTxInfo {
struct _TransferTask *task;
ChunkServer *cs;
unsigned char session_key[BLOCK_TX_SESSION_KEY_LEN];
unsigned char *enc_session_key; /* encrypted session_key */
int enc_key_len;
int cmd_pipe[2]; /* used to notify cancel */
int done_pipe[2]; /* notify block transfer done */
int result;
int n_failure;
/* TRUE if the client only transfer one batch of blocks and end.*/
gboolean transfer_once;
gint ready_for_transfer;
} BlockTxInfo;
struct _SeafTransferManager;
struct _TransferTask {
struct _SeafTransferManager *manager;
char tx_id[37];
char repo_id[37];
int repo_version;
char *token;
char *session_token;
int protocol_version;
char *from_branch;
char *to_branch;
char head[41];
char remote_head[41];
int state; /* NORMAL, STOPPED, CANCELED */
int runtime_state;
int last_runtime_state;
int type;
gboolean is_clone; /* TRUE when fetching a new repo. */
char *email;
int error;
char *dest_id;
ObjectList *commits; /* commits need to be uploaded */
ObjectList *fs_roots; /* the root of file systems to be sent/get */
GList *chunk_servers;
BlockList *block_list;
gint tx_bytes; /* bytes transferred in the this second. */
gint last_tx_bytes; /* bytes transferred in the last second. */
/* Fields only used by upload task. */
int n_uploaded;
/* For new block transfer protocol */
BlockTxInfo *tx_info;
GQueue *block_ids;
gboolean server_side_merge;
/* These two fields are only used for new syncing protocol. */
char *passwd;
char *worktree;
/* Used to display download progress for new syncing protocol */
int n_to_download;
int n_downloaded;
gint64 rsize; /* size remain */
gint64 dsize; /* size done */
};
typedef struct _TransferTask TransferTask;
const char *
task_state_to_str (int state);
const char *
task_rt_state_to_str (int rt_state);
const char *
task_error_str (int task_errno);
int
transfer_task_get_rate (TransferTask *task);
int
transfer_task_get_done_blocks (TransferTask *task);
void
transfer_task_set_error (TransferTask *task, int error);
void
transfer_task_set_netdown (TransferTask *task);
void
transition_state_to_error (TransferTask *task, int task_errno);
/*
* Transfer Manager
*/
struct _SeafileSession;
struct _SeafTransferManager {
struct _SeafileSession *seaf;
sqlite3 *db;
GHashTable *download_tasks;
GHashTable *upload_tasks;
CcnetTimer *schedule_timer;
};
typedef struct _SeafTransferManager SeafTransferManager;
SeafTransferManager *seaf_transfer_manager_new (struct _SeafileSession *seaf);
int seaf_transfer_manager_start (SeafTransferManager *manager);
char *
seaf_transfer_manager_add_download (SeafTransferManager *manager,
const char *repo_id,
int repo_version,
const char *peer_id,
const char *from_branch,
const char *to_branch,
const char *token,
gboolean server_side_merge,
const char *passwd,
const char *worktree,
const char *email,
GError **error);
char *
seaf_transfer_manager_add_upload (SeafTransferManager *manager,
const char *repo_id,
int repo_version,
const char *peer_id,
const char *from_branch,
const char *to_branch,
const char *token,
gboolean server_side_merge,
GError **error);
GList*
seaf_transfer_manager_get_upload_tasks (SeafTransferManager *manager);
GList*
seaf_transfer_manager_get_download_tasks (SeafTransferManager *manager);
/* find running tranfer of a repo */
TransferTask*
seaf_transfer_manager_find_transfer_by_repo (SeafTransferManager *manager,
const char *repo_id);
void
seaf_transfer_manager_remove_task (SeafTransferManager *manager,
const char *tx_id,
int task_type);
void
seaf_transfer_manager_cancel_task (SeafTransferManager *manager,
const char *tx_id,
int task_type);
GList *
seaf_transfer_manager_get_clone_heads (SeafTransferManager *mgr);
char *
seaf_transfer_manager_get_clone_head (SeafTransferManager *mgr,
const char *repo_id);
/*
* return the status code of block tx client.
*/
int
seaf_transfer_manager_download_file_blocks (SeafTransferManager *manager,
TransferTask *task,
const char *file_id);
#endif

View File

@ -13,7 +13,6 @@
#include "utils.h"
#include "fs-mgr.h"
#include "merge.h"
#include "vc-utils.h"
#include "vc-common.h"
#include "index/index.h"
@ -281,62 +280,6 @@ out:
#endif /* WIN32 */
static int
unlink_entry (struct cache_entry *ce, struct unpack_trees_options *o)
{
char path[SEAF_PATH_MAX];
SeafStat st;
int base_len = strlen(o->base);
int len = ce_namelen(ce);
int offset;
if (!len) {
seaf_warning ("entry name should not be empty.\n");
return -1;
}
snprintf (path, SEAF_PATH_MAX, "%s/%s", o->base, ce->name);
if (!S_ISDIR(ce->ce_mode)) {
/* file doesn't exist in work tree */
if (seaf_stat (path, &st) < 0 || !S_ISREG(st.st_mode)) {
return 0;
}
/* file has been changed. */
if (!o->reset &&
(ce->current_mtime != st.st_mtime)) {
seaf_warning ("File %s is changed. Skip removing the file.\n", path);
return -1;
}
/* first unlink the file. */
if (seaf_util_unlink (path) < 0) {
seaf_warning ("Failed to remove %s: %s.\n", path, strerror(errno));
return -1;
}
} else {
if (seaf_remove_empty_dir (path) < 0) {
seaf_warning ("Failed to remove dir %s: %s.\n", path, strerror(errno));
return -1;
}
}
/* then remove all empty directories upwards. */
offset = base_len + len;
do {
if (path[offset] == '/') {
path[offset] = '\0';
int ret = seaf_remove_empty_dir (path);
if (ret < 0) {
break;
}
}
} while (--offset > base_len);
return 0;
}
static int
compute_file_id_with_cdc (const char *path, SeafStat *st,
SeafileCrypt *crypt, int repo_version,
@ -399,310 +342,6 @@ compare_file_content (const char *path, SeafStat *st, const unsigned char *ce_sh
}
}
#if defined WIN32 || defined __APPLE__
/*
* If the names are different case-sensitively but the same case-insensitively,
* it's a case conflict.
* Note that the names are in UTF-8, so we use UTF-8 function to compare them.
*/
static gboolean
case_conflict_utf8 (const char *name1, const char *name2)
{
char *casefold1, *casefold2;
gboolean ret;
if (strcmp (name1, name2) == 0)
return FALSE;
casefold1 = g_utf8_casefold (name1, -1);
casefold2 = g_utf8_casefold (name2, -1);
ret = (g_utf8_collate (casefold1, casefold2) == 0);
g_free (casefold1);
g_free (casefold2);
return ret;
}
#ifndef WIN32
static gboolean
case_conflict_exists (const char *dir_path, const char *new_dname,
char **conflict_dname)
{
GDir *dir;
const char *dname;
gboolean is_case_conflict = FALSE;
GError *error = NULL;
/* Don't generate "case conflict" files for a case-conflicted file. */
if (strstr (new_dname, "case conflict") != NULL) {
return is_case_conflict;
}
dir = g_dir_open (dir_path, 0, &error);
if (!dir && error) {
seaf_warning ("Failed to open dir %s: %s.\n", dir_path, error->message);
g_error_free (error);
return FALSE;
}
while (1) {
dname = g_dir_read_name (dir);
if (!dname)
break;
char *norm_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC);
if (case_conflict_utf8 (norm_dname, new_dname)) {
is_case_conflict = TRUE;
*conflict_dname = norm_dname;
break;
}
g_free (norm_dname);
}
g_dir_close (dir);
return is_case_conflict;
}
#else
typedef struct CaseConflictData {
const char *new_dname;
gboolean is_case_conflict;
char *conflict_dname;
} CaseConflictData;
static int
check_case_conflict_cb (wchar_t *parent, WIN32_FIND_DATAW *fdata,
void *user_data, gboolean *stop)
{
CaseConflictData *data = user_data;
char *dname = NULL;
dname = g_utf16_to_utf8 (fdata->cFileName, -1, NULL, NULL, NULL);
if (case_conflict_utf8 (dname, data->new_dname)) {
data->is_case_conflict = TRUE;
data->conflict_dname = g_strdup(dname);
*stop = TRUE;
}
g_free (dname);
return 0;
}
static gboolean
case_conflict_exists (const char *dir_path, const char *new_dname,
char **conflict_dname)
{
wchar_t *dir_path_w;
gboolean is_case_conflict = FALSE;
CaseConflictData data;
/* Don't generate "case conflict" files for a case-conflicted file. */
if (strstr (new_dname, "case conflict") != NULL) {
return is_case_conflict;
}
dir_path_w = win32_long_path (dir_path);
memset (&data, 0, sizeof(data));
data.new_dname = new_dname;
if (traverse_directory_win32 (dir_path_w, check_case_conflict_cb, &data) < 0)
goto out;
is_case_conflict = data.is_case_conflict;
*conflict_dname = data.conflict_dname;
out:
g_free (dir_path_w);
return is_case_conflict;
}
#endif /* WIN32 */
/*
* If files "test (case conflict 1).txt" and "Test (case conflict 2).txt" exist,
* and we have to checkout "TEST.txt", it will be checked out to "TEST
* (case conflict 3).txt".
* To prevent generating too many case conflict files (in case of bug or other
* reasons), no more than 10 case conflict files will be generated for the same
* filename. After that, all later confilcted files will use the last conflict
* file name.
*/
static char *
gen_case_conflict_free_dname (const char *dir_path, const char *dname)
{
char *copy = g_strdup (dname);
GString *buf = g_string_new (NULL);
char ret_dname[256];
char *dot, *ext;
int cnt = 1;
dot = strrchr (copy, '.');
while (cnt < 11) {
if (dot != NULL) {
*dot = '\0';
ext = dot + 1;
snprintf (ret_dname, sizeof(ret_dname), "%s (case conflict %d).%s",
copy, cnt, ext);
g_string_printf (buf, "%s/%s (case conflict %d).%s",
dir_path, copy, cnt, ext);
} else {
snprintf (ret_dname, sizeof(ret_dname), "%s (case conflict %d)",
copy, cnt);
g_string_printf (buf, "%s/%s (case conflict %d)",
dir_path, copy, cnt);
}
if (!seaf_util_exists (buf->str))
break;
g_string_truncate (buf, 0);
++cnt;
}
g_free (copy);
g_string_free (buf, TRUE);
return g_strdup(ret_dname);
}
/*
* @conflict_hash: conflicting_dir_path -> conflict_free_dname
* @no_conflict_hash: a hash table to remember dirs that have no case conflict.
*/
char *
build_case_conflict_free_path (const char *worktree,
const char *ce_name,
GHashTable *conflict_hash,
GHashTable *no_conflict_hash,
gboolean *is_case_conflict,
gboolean is_rename)
{
GString *buf = g_string_new (worktree);
char **components, *ptr;
guint i, n_comps;
static int dummy;
char *conflict_dname = NULL;
components = g_strsplit (ce_name, "/", -1);
n_comps = g_strv_length (components);
for (i = 0; i < n_comps; ++i) {
char *path = NULL, *dname = NULL;
SeafStat st;
ptr = components[i];
path = g_build_path ("/", buf->str, ptr, NULL);
/* If path doesn't exist, case conflict is not possible. */
if (seaf_stat (path, &st) < 0) {
if (i != n_comps - 1) {
if (seaf_util_mkdir (path, 0777) < 0) {
seaf_warning ("Failed to create dir %s.\n", path);
g_free (path);
goto error;
}
}
g_string_append_printf (buf, "/%s", ptr);
g_free (path);
continue;
}
dname = g_hash_table_lookup (conflict_hash, path);
if (dname) {
/* We've detected (and fixed) case conflict for this dir before. */
*is_case_conflict = TRUE;
g_free (path);
g_string_append_printf (buf, "/%s", dname);
continue;
}
if (g_hash_table_lookup (no_conflict_hash, path) != NULL) {
/* We've confirmed this dir has no case conflict before. */
g_free (path);
g_string_append_printf (buf, "/%s", ptr);
continue;
}
/* No luck in the hash tables, we have to run case conflict detection. */
if (!case_conflict_exists (buf->str, ptr, &conflict_dname)) {
/* No case conflict. */
if (i != n_comps - 1)
g_hash_table_insert (no_conflict_hash,
g_strdup(path),
&dummy);
g_free (path);
g_string_append_printf (buf, "/%s", ptr);
continue;
}
*is_case_conflict = TRUE;
/* If case conflict, create a conflict free path and
* remember it in the hash table.
*/
if (!is_rename) {
dname = gen_case_conflict_free_dname (buf->str, ptr);
char *case_conflict_free_path = g_build_path ("/", buf->str, dname, NULL);
if (i != n_comps - 1) {
if (seaf_util_mkdir (case_conflict_free_path, 0777) < 0) {
seaf_warning ("Failed to create dir %s.\n",
case_conflict_free_path);
g_free (path);
g_free (dname);
g_free (case_conflict_free_path);
goto error;
}
g_hash_table_insert (conflict_hash, g_strdup(path), g_strdup(dname));
}
g_string_append_printf (buf, "/%s", dname);
g_free (dname);
g_free (case_conflict_free_path);
} else {
char *src_path = g_build_path ("/", buf->str, conflict_dname, NULL);
if (i != (n_comps - 1) && seaf_util_rename (src_path, path) < 0) {
seaf_warning ("Failed to rename %s to %s: %s.\n",
src_path, path, strerror(errno));
g_free (path);
g_free (src_path);
goto error;
}
/* Since the exsiting dir in the worktree has been renamed,
* there is no more case conflict.
*/
g_hash_table_insert (no_conflict_hash, g_strdup(path), &dummy);
g_string_append_printf (buf, "/%s", ptr);
g_free (src_path);
}
g_free (conflict_dname);
g_free (path);
}
g_strfreev (components);
return g_string_free (buf, FALSE);
error:
g_strfreev (components);
return NULL;
}
#endif /* defined WIN32 || defined __APPLE__ */
char *
build_checkout_path (const char *worktree, const char *ce_name, int len)
{
@ -744,170 +383,6 @@ build_checkout_path (const char *worktree, const char *ce_name, int len)
return g_strdup(path);
}
static int
checkout_entry (struct cache_entry *ce,
struct unpack_trees_options *o,
gboolean recover_merge,
const char *conflict_head_id,
GHashTable *conflict_hash,
GHashTable *no_conflict_hash)
{
char *path_in, *path;
SeafStat st;
char file_id[41];
gboolean case_conflict = FALSE;
gboolean force_conflict = FALSE;
path_in = g_build_path ("/", o->base, ce->name, NULL);
#if defined WIN32 || defined __APPLE__
path = build_case_conflict_free_path (o->base, ce->name,
conflict_hash, no_conflict_hash,
&case_conflict,
FALSE);
#else
path = build_checkout_path (o->base, ce->name, ce_namelen(ce));
#endif
g_free (path_in);
if (!path)
return -1;
if (!S_ISDIR(ce->ce_mode)) {
/* In case that we're replacing an empty dir with a file,
* we need first to remove the empty dir.
*/
if (seaf_stat (path, &st) == 0 && S_ISDIR(st.st_mode)) {
if (seaf_util_rmdir (path) < 0) {
seaf_warning ("Failed to remove dir %s: %s\n", path, strerror(errno));
/* Don't quit since we can handle conflict later. */
}
}
} else {
if (seaf_util_mkdir (path, 0777) < 0) {
seaf_warning ("Failed to create empty dir %s in checkout.\n", path);
g_free (path);
return -1;
}
if (ce->ce_mtime.sec != 0 &&
seaf_set_file_time (path, ce->ce_mtime.sec) < 0) {
seaf_warning ("Failed to set mtime for %s.\n", path);
}
goto update_cache;
}
if (!o->reset && seaf_stat (path, &st) == 0 && S_ISREG(st.st_mode) &&
(ce->current_mtime != st.st_mtime))
{
/* If we're recovering an interrupted merge, we don't know whether
* the file was changed by checkout or by the user. So we have to
* calculate the sha1 for that file and compare it with the one in
* cache entry.
*/
if (!recover_merge ||
compare_file_content (path, &st, ce->sha1, o->crypt, o->version) != 0) {
seaf_warning ("File %s is changed. Checkout to conflict file.\n", path);
force_conflict = TRUE;
} else {
/* Recover merge and file content matches index entry.
* We were interrupted before updating the index, update index
* entry timestamp now.
*/
goto update_cache;
}
}
/* then checkout the file. */
gboolean conflicted = FALSE;
rawdata_to_hex (ce->sha1, file_id, 20);
if (seaf_fs_manager_checkout_file (seaf->fs_mgr,
o->repo_id,
o->version,
file_id,
path,
ce->ce_mode,
ce->ce_mtime.sec,
o->crypt,
ce->name,
conflict_head_id,
force_conflict,
&conflicted,
NULL) < 0) {
seaf_warning ("Failed to checkout file %s.\n", path);
g_free (path);
return -1;
}
/* If case conflict, this file has been checked out to another path.
* Remove the current entry, otherwise it won't be removed later
* since it's timestamp is 0.
*/
if (case_conflict) {
ce->ce_flags |= CE_REMOVE;
g_free (path);
return 0;
}
if (conflicted) {
g_free (path);
return 0;
}
update_cache:
/* finally fill cache_entry info */
/* Only update index if we checked out the file without any error
* or conflicts. The timestamp of the entry will remain 0 if error
* or conflicted.
*/
seaf_stat (path, &st);
fill_stat_cache_info (ce, &st);
g_free (path);
return 0;
}
int
update_worktree (struct unpack_trees_options *o,
gboolean recover_merge,
const char *conflict_head_id,
const char *default_conflict_suffix,
int *finished_entries)
{
struct index_state *result = &o->result;
int i;
struct cache_entry *ce;
int errs = 0;
GHashTable *conflict_hash, *no_conflict_hash;
for (i = 0; i < result->cache_nr; ++i) {
ce = result->cache[i];
if (ce->ce_flags & CE_WT_REMOVE)
errs |= unlink_entry (ce, o);
}
conflict_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
no_conflict_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
for (i = 0; i < result->cache_nr; ++i) {
ce = result->cache[i];
if (ce->ce_flags & CE_UPDATE) {
errs |= checkout_entry (ce, o, recover_merge,
conflict_head_id,
conflict_hash, no_conflict_hash);
}
if (finished_entries)
*finished_entries = *finished_entries + 1;
}
g_hash_table_destroy (conflict_hash);
g_hash_table_destroy (no_conflict_hash);
if (errs != 0)
return -1;
return 0;
}
int
delete_path (const char *worktree, const char *name,
unsigned int mode, gint64 old_mtime)
@ -1160,37 +635,3 @@ files_locked_on_windows (struct index_state *index, const char *worktree)
#endif /* WIN32 */
void
fill_seafile_blocks (const char *repo_id, int version,
const unsigned char *sha1, BlockList *bl)
{
char file_id[41];
Seafile *seafile;
int i;
rawdata_to_hex (sha1, file_id, 20);
seafile = seaf_fs_manager_get_seafile (seaf->fs_mgr, repo_id, version, file_id);
if (!seafile) {
seaf_warning ("Failed to find file %s.\n", file_id);
return;
}
for (i = 0; i < seafile->n_blocks; ++i)
block_list_insert (bl, seafile->blk_sha1s[i]);
seafile_unref (seafile);
}
void
collect_new_blocks_from_index (const char *repo_id, int version,
struct index_state *index, BlockList *bl)
{
int i;
struct cache_entry *ce;
for (i = 0; i < index->cache_nr; ++i) {
ce = index->cache[i];
if (ce->ce_flags & CE_UPDATE)
fill_seafile_blocks (repo_id, version, ce->sha1, bl);
}
}

View File

@ -5,7 +5,6 @@
#include "index/index.h"
#include "index/cache-tree.h"
#include "unpack-trees.h"
#include "fs-mgr.h"
#define PATH_SEPERATOR "/"
@ -28,24 +27,9 @@ commit_trees_cb (const char *repo_id, int version,
int
update_index (struct index_state *istate, const char *index_path);
int
update_worktree (struct unpack_trees_options *o,
gboolean recover_merge,
const char *conflict_head,
const char *default_conflict_suffix,
int *finished_entries);
int
seaf_remove_empty_dir (const char *path);
char *
build_case_conflict_free_path (const char *worktree,
const char *ce_name,
GHashTable *conflict_hash,
GHashTable *no_conflict_hash,
gboolean *is_case_conflict,
gboolean is_rename);
char *
build_checkout_path (const char *worktree, const char *ce_name, int len);
@ -53,16 +37,6 @@ int
delete_path (const char *worktree, const char *name,
unsigned int mode, gint64 old_mtime);
struct index_state;
int
delete_dir_with_check (const char *repo_id,
int repo_version,
const char *root_id,
const char *dir_path,
const char *worktree,
struct index_state *istate);
gboolean
do_check_file_locked (const char *path, const char *worktree, gboolean locked_on_server);
@ -78,12 +52,4 @@ compare_file_content (const char *path, SeafStat *st,
struct SeafileCrypt *crypt,
int repo_version);
void
fill_seafile_blocks (const char *repo_id, int version,
const unsigned char *sha1, BlockList *bl);
void
collect_new_blocks_from_index (const char *repo_id, int version,
struct index_state *index, BlockList *bl);
#endif

View File

@ -479,7 +479,7 @@ wt_monitor_job_linux (void *vmonitor)
}
if (FD_ISSET (monitor->cmd_pipe[0], &fds)) {
n = pipereadn (monitor->cmd_pipe[0], &cmd, sizeof(cmd));
n = seaf_pipe_readn (monitor->cmd_pipe[0], &cmd, sizeof(cmd));
if (n != sizeof(cmd)) {
seaf_warning ("[wt mon] failed to read command.\n");
continue;
@ -679,7 +679,7 @@ reply_watch_command (SeafWTMonitor *monitor, int result)
{
int n;
n = pipewriten (monitor->res_pipe[1], &result, sizeof(int));
n = seaf_pipe_writen (monitor->res_pipe[1], &result, sizeof(int));
if (n != sizeof(int))
seaf_warning ("[wt mon] fail to write command result.\n");
}

View File

@ -9,7 +9,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <ccnet/job-mgr.h>
#include "job-mgr.h"
#include "seafile-session.h"
#include "utils.h"
#include "wt-monitor.h"
@ -319,7 +319,7 @@ command_read_cb (CFFileDescriptorRef fdref,
WatchCommand cmd;
int n;
n = pipereadn (monitor->cmd_pipe[0], &cmd, sizeof(cmd));
n = seaf_pipe_readn (monitor->cmd_pipe[0], &cmd, sizeof(cmd));
if (n != sizeof(cmd)) {
seaf_warning ("[wt mon] failed to read command.\n");
CFFileDescriptorEnableCallBacks (fdref, kCFFileDescriptorReadCallBack);
@ -398,7 +398,7 @@ reply_watch_command (SeafWTMonitor *monitor, int result)
{
int n;
n = pipewriten (monitor->res_pipe[1], &result, sizeof(int));
n = seaf_pipe_writen (monitor->res_pipe[1], &result, sizeof(int));
if (n != sizeof(int))
seaf_warning ("[wt mon] fail to write command result.\n");
}

View File

@ -733,7 +733,7 @@ reply_watch_command (SeafWTMonitor *monitor, int result)
{
int n;
n = pipewriten (monitor->res_pipe[1], &result, sizeof(int));
n = seaf_pipe_writen (monitor->res_pipe[1], &result, sizeof(int));
if (n != sizeof(int))
seaf_warning ("[wt mon] fail to write command result.\n");
}

View File

@ -9,26 +9,26 @@
#define DEBUG_FLAG SEAFILE_DEBUG_WATCH
#include "log.h"
#include <ccnet/job-mgr.h>
#include "job-mgr.h"
int
seaf_wt_monitor_start (SeafWTMonitor *monitor)
{
if (ccnet_pipe (monitor->cmd_pipe) < 0) {
if (seaf_pipe (monitor->cmd_pipe) < 0) {
seaf_warning ("[wt mon] failed to create command pipe: %s.\n",
strerror(errno));
return -1;
}
if (ccnet_pipe (monitor->res_pipe) < 0) {
if (seaf_pipe (monitor->res_pipe) < 0) {
seaf_warning ("[wt mon] failed to create result pipe: %s.\n",
strerror(errno));
return -1;
}
if (ccnet_job_manager_schedule_job (monitor->seaf->job_mgr,
monitor->job_func,
NULL, monitor) < 0) {
if (seaf_job_manager_schedule_job (monitor->seaf->job_mgr,
monitor->job_func,
NULL, monitor) < 0) {
seaf_warning ("[wt mon] failed to start monitor thread.\n");
return -1;
}
@ -49,7 +49,7 @@ seaf_wt_monitor_watch_repo (SeafWTMonitor *monitor,
cmd.type = CMD_ADD_WATCH;
g_strlcpy (cmd.worktree, worktree, SEAF_PATH_MAX);
int n = pipewriten (monitor->cmd_pipe[1], &cmd, sizeof(cmd));
int n = seaf_pipe_writen (monitor->cmd_pipe[1], &cmd, sizeof(cmd));
if (n != sizeof(cmd)) {
seaf_warning ("[wt mon] fail to write command pipe.\n");
@ -58,7 +58,7 @@ seaf_wt_monitor_watch_repo (SeafWTMonitor *monitor,
seaf_debug ("send a watch command, repo %s\n", repo_id);
n = pipereadn (monitor->res_pipe[0], &res, sizeof(int));
n = seaf_pipe_readn (monitor->res_pipe[0], &res, sizeof(int));
if (n != sizeof(int)) {
seaf_warning ("[wt mon] fail to read result pipe.\n");
return -1;
@ -77,7 +77,7 @@ seaf_wt_monitor_unwatch_repo (SeafWTMonitor *monitor, const char *repo_id)
memcpy (cmd.repo_id, repo_id, 37);
cmd.type = CMD_DELETE_WATCH;
int n = pipewriten (monitor->cmd_pipe[1], &cmd, sizeof(cmd));
int n = seaf_pipe_writen (monitor->cmd_pipe[1], &cmd, sizeof(cmd));
if (n != sizeof(cmd)) {
seaf_warning ("[wt mon] fail to write command pipe.\n");
@ -86,7 +86,7 @@ seaf_wt_monitor_unwatch_repo (SeafWTMonitor *monitor, const char *repo_id)
seaf_debug ("send an unwatch command, repo %s\n", repo_id);
n = pipereadn (monitor->res_pipe[0], &res, sizeof(int));
n = seaf_pipe_readn (monitor->res_pipe[0], &res, sizeof(int));
if (n != sizeof(int)) {
seaf_warning ("[wt mon] fail to read result pipe.\n");
return -1;
@ -105,7 +105,7 @@ seaf_wt_monitor_refresh_repo (SeafWTMonitor *monitor, const char *repo_id)
memcpy (cmd.repo_id, repo_id, 37);
cmd.type = CMD_REFRESH_WATCH;
int n = pipewriten (monitor->cmd_pipe[1], &cmd, sizeof(cmd));
int n = seaf_pipe_writen (monitor->cmd_pipe[1], &cmd, sizeof(cmd));
if (n != sizeof(cmd)) {
seaf_warning ("[wt mon] fail to write command pipe.\n");
@ -114,7 +114,7 @@ seaf_wt_monitor_refresh_repo (SeafWTMonitor *monitor, const char *repo_id)
seaf_debug ("send a refresh command, repo %s\n", repo_id);
n = pipereadn (monitor->res_pipe[0], &res, sizeof(int));
n = seaf_pipe_readn (monitor->res_pipe[0], &res, sizeof(int));
if (n != sizeof(int)) {
seaf_warning ("[wt mon] fail to read result pipe.\n");
return -1;

View File

@ -25,8 +25,8 @@ typedef struct SeafWTMonitor {
struct _SeafileSession *seaf;
SeafWTMonitorPriv *priv;
ccnet_pipe_t cmd_pipe[2];
ccnet_pipe_t res_pipe[2];
seaf_pipe_t cmd_pipe[2];
seaf_pipe_t res_pipe[2];
/* platform dependent virtual functions */
void* (*job_func) (void *);

View File

@ -2,6 +2,7 @@
#ifndef _SEAFILE_RPC_H
#define _SEAFILE_RPC_H
#include <jansson.h>
#include "seafile-object.h"
/**
@ -19,57 +20,6 @@ seafile_get_session_info (GError **error);
*/
GList* seafile_get_repo_list (int start, int limit, GError **error);
gint64
seafile_count_repos (GError **error);
/**
* seafile_get_trash_repo_list:
*
* Returns deleted repository list.
*/
GList* seafile_get_trash_repo_list(int start, int limit, GError **error);
int
seafile_del_repo_from_trash (const char *repo_id, GError **error);
int
seafile_restore_repo_from_trash (const char *repo_id, GError **error);
GList *
seafile_get_trash_repos_by_owner (const char *owner, GError **error);
int
seafile_empty_repo_trash (GError **error);
int
seafile_empty_repo_trash_by_owner (const char *owner, GError **error);
/**
* seafile_get_commit_list:
*
* @limit: if limit <= 0, all commits start from @offset will be returned.
*
* Returns: commit list of a given repo.
*
* Possible Error:
* 1. Bad Argument
* 2. No head and branch master
* 3. Failed to list commits
*/
GList* seafile_get_commit_list (const gchar *repo,
int offset,
int limit,
GError **error);
/**
* seafile_get_commit:
* @id: the commit id.
*
* Returns: the commit object.
*/
GObject* seafile_get_commit (const char *repo_id, int version,
const gchar *id, GError **error);
/**
* seafile_get_repo:
*
@ -131,49 +81,9 @@ seafile_get_download_rate(GError **error);
int
seafile_get_upload_rate(GError **error);
/**
* seafile_edit_repo:
* @repo_id: repository id.
* @name: new name of the repository, NULL if unchanged.
* @description: new description of the repository, NULL if unchanged.
*/
int seafile_edit_repo (const gchar *repo_id,
const gchar *name,
const gchar *description,
const gchar *user,
GError **error);
int
seafile_change_repo_passwd (const char *repo_id,
const char *old_passwd,
const char *new_passwd,
const char *user,
GError **error);
/**
* seafile_repo_size:
*
* Returns: the size of a repo
*
* Possible Error:
* 1. Bad Argument
* 2. No local branch (No local branch record in branch.db)
* 3. Database error
* 4. Calculate branch size error
*/
gint64
seafile_repo_size(const gchar *repo_id, GError **error);
int
seafile_repo_last_modify(const char *repo_id, GError **error);
int seafile_set_repo_lantoken (const gchar *repo_id,
const gchar *token,
GError **error);
gchar* seafile_get_repo_lantoken (const gchar *repo_id,
GError **error);
int
seafile_set_repo_property (const char *repo_id,
const char *key,
@ -185,20 +95,6 @@ seafile_get_repo_property (const char *repo_id,
const char *key,
GError **error);
char *
seafile_get_repo_relay_address (const char *repo_id,
GError **error);
char *
seafile_get_repo_relay_port (const char *repo_id,
GError **error);
int
seafile_update_repo_relay_info (const char *repo_id,
const char *new_addr,
const char *new_port,
GError **error);
int
seafile_update_repos_server_host (const char *old_host,
const char *new_host,
@ -235,56 +131,6 @@ seafile_set_server_property (const char *server_url,
GList *
seafile_get_file_sync_errors (int offset, int limit, GError **error);
/**
* seafile_list_dir:
* List a directory.
*
* Returns: a list of dirents.
*
* @limit: if limit <= 0, all dirents start from @offset will be returned.
*/
GList * seafile_list_dir (const char *repo_id,
const char *dir_id, int offset, int limit, GError **error);
/**
* seafile_list_file_blocks:
* List the blocks of a file.
*
* Returns: a list of block ids speprated by '\n'.
*
* @limit: if limit <= 0, all blocks start from @offset will be returned.
*/
char * seafile_list_file_blocks (const char *repo_id,
const char *file_id,
int offset, int limit,
GError **error);
/**
* seafile_list_dir_by_path:
* List a directory in a commit by the path of the directory.
*
* Returns: a list of dirents.
*/
GList * seafile_list_dir_by_path (const char *repo_id,
const char *commit_id, const char *path, GError **error);
/**
* seafile_get_dir_id_by_commit_and_path:
* Get the dir_id of the path
*
* Returns: the dir_id of the path
*/
char * seafile_get_dir_id_by_commit_and_path (const char *repo_id,
const char *commit_id,
const char *path,
GError **error);
/**
* seafile_revert:
* Reset the repo to a previous state by creating a new commit.
*/
int seafile_revert (const char *repo_id, const char *commit, GError **error);
char *
seafile_gen_default_worktree (const char *worktree_parent,
const char *repo_name,
@ -352,46 +198,6 @@ seafile_get_clone_tasks (GError **error);
*/
int seafile_sync (const char *repo_id, const char *peer_id, GError **error);
/**
* seafile_get_total_block_size:
*
* Get the sum of size of all the blocks.
*/
gint64
seafile_get_total_block_size (GError **error);
/**
* seafile_get_commit_tree_block_number:
*
* Get the number of blocks belong to the commit tree.
*
* @commit_id: the head of the commit tree.
*
* Returns: -1 if the calculation is in progress, -2 if error, >=0 otherwise.
*/
int
seafile_get_commit_tree_block_number (const char *commit_id, GError **error);
/**
* seafile_gc:
* Start garbage collection.
*/
int
seafile_gc (GError **error);
/**
* seafile_gc_get_progress:
* Get progress of GC.
*
* Returns:
* progress of GC in precentage.
* -1 if GC is not running.
*/
/* int */
/* seafile_gc_get_progress (GError **error); */
/* ----------------- Task Related -------------- */
/**
@ -425,608 +231,10 @@ GList *
seafile_diff (const char *repo_id, const char *old, const char *new,
int fold_dir_diff, GError **error);
GList *
seafile_branch_gets (const char *repo_id, GError **error);
/**
* Return 1 if user is the owner of repo, otherwise return 0.
*/
int
seafile_is_repo_owner (const char *email, const char *repo_id,
GError **error);
int
seafile_set_repo_owner(const char *repo_id, const char *email,
GError **error);
/**
* Return owner id of repo
*/
char *
seafile_get_repo_owner(const char *repo_id, GError **error);
GList *
seafile_get_orphan_repo_list(GError **error);
GList *
seafile_list_owned_repos (const char *email, int ret_corrupted, GError **error);
/**
* seafile_add_chunk_server:
* @server: ID for the chunk server.
*
* Add a chunk server on a relay server.
*/
int seafile_add_chunk_server (const char *server, GError **error);
/**
* seafile_del_chunk_server:
* @server: ID for the chunk server.
*
* Delete a chunk server on a relay server.
*/
int seafile_del_chunk_server (const char *server, GError **error);
/**
* seafile_list_chunk_servers:
*
* List chunk servers set on a relay server.
*/
char *seafile_list_chunk_servers (GError **error);
gint64 seafile_get_user_quota_usage (const char *email, GError **error);
gint64 seafile_get_user_share_usage (const char *email, GError **error);
gint64
seafile_server_repo_size(const char *repo_id, GError **error);
int
seafile_repo_set_access_property (const char *repo_id, const char *ap,
GError **error);
char *
seafile_repo_query_access_property (const char *repo_id, GError **error);
char *
seafile_web_get_access_token (const char *repo_id,
const char *obj_id,
const char *op,
const char *username,
int use_onetime,
GError **error);
GObject *
seafile_web_query_access_token (const char *token, GError **error);
char *
seafile_query_zip_progress (const char *token, GError **error);
GObject *
seafile_get_checkout_task (const char *repo_id, GError **error);
GList *
seafile_get_sync_task_list (GError **error);
int
seafile_share_subdir_to_user (const char *repo_id,
const char *path,
const char *owner,
const char *share_user,
const char *permission,
const char *passwd,
GError **error);
int
seafile_unshare_subdir_for_user (const char *repo_id,
const char *path,
const char *owner,
const char *share_user,
GError **error);
int
seafile_update_share_subdir_perm_for_user (const char *repo_id,
const char *path,
const char *owner,
const char *share_user,
const char *permission,
GError **error);
int
seafile_add_share (const char *repo_id, const char *from_email,
const char *to_email, const char *permission,
GError **error);
GList *
seafile_list_share_repos (const char *email, const char *type,
int start, int limit, GError **error);
GList *
seafile_list_repo_shared_to (const char *from_user, const char *repo_id,
GError **error);
GList *
seafile_list_repo_shared_group (const char *from_user, const char *repo_id,
GError **error);
int
seafile_remove_share (const char *repo_id, const char *from_email,
const char *to_email, GError **error);
int
seafile_share_subdir_to_group (const char *repo_id,
const char *path,
const char *owner,
int share_group,
const char *permission,
const char *passwd,
GError **error);
int
seafile_unshare_subdir_for_group (const char *repo_id,
const char *path,
const char *owner,
int share_group,
GError **error);
int
seafile_update_share_subdir_perm_for_group (const char *repo_id,
const char *path,
const char *owner,
int share_group,
const char *permission,
GError **error);
int
seafile_group_share_repo (const char *repo_id, int group_id,
const char *user_name, const char *permission,
GError **error);
int
seafile_group_unshare_repo (const char *repo_id, int group_id,
const char *user_name, GError **error);
/* Get groups that a repo is shared to */
char *
seafile_get_shared_groups_by_repo(const char *repo_id, GError **error);
char *
seafile_get_group_repoids (int group_id, GError **error);
GList *
seafile_get_repos_by_group (int group_id, GError **error);
GList *
seafile_get_group_repos_by_owner (char *user, GError **error);
char *
seafile_get_group_repo_owner (const char *repo_id, GError **error);
int
seafile_remove_repo_group(int group_id, const char *username, GError **error);
gint64
seafile_get_file_size (const char *store_id, int version,
const char *file_id, GError **error);
gint64
seafile_get_dir_size (const char *store_id, int version,
const char *dir_id, GError **error);
int
seafile_set_repo_history_limit (const char *repo_id,
int days,
GError **error);
int
seafile_get_repo_history_limit (const char *repo_id,
GError **error);
int
seafile_check_passwd (const char *repo_id,
const char *magic,
GError **error);
int
seafile_set_passwd (const char *repo_id,
const char *user,
const char *passwd,
GError **error);
int
seafile_unset_passwd (const char *repo_id,
const char *user,
GError **error);
int
seafile_is_passwd_set (const char *repo_id, const char *user, GError **error);
GObject *
seafile_get_decrypt_key (const char *repo_id, const char *user, GError **error);
int
seafile_revert_on_server (const char *repo_id,
const char *commit_id,
const char *user_name,
GError **error);
/**
* Add a file into the repo on server.
* The content of the file is stored in a temporary file.
* @repo_id: repo id
* @temp_file_path: local file path, should be a temp file just uploaded.
* @parent_dir: the parent directory to put the file in.
* @file_name: the name of the target file.
* @user: the email of the user who uploaded the file.
*/
int
seafile_post_file (const char *repo_id, const char *temp_file_path,
const char *parent_dir, const char *file_name,
const char *user,
GError **error);
/**
* Add multiple files at once.
*
* @filenames_json: json array of filenames
* @paths_json: json array of temp file paths
*/
char *
seafile_post_multi_files (const char *repo_id,
const char *parent_dir,
const char *filenames_json,
const char *paths_json,
const char *user,
int replace,
GError **error);
/**
* Add file blocks at once.
*
* @blocks_json: json array of block ids
* @paths_json: json array of temp file paths
*/
char *
seafile_post_file_blocks (const char *repo_id,
const char *parent_dir,
const char *file_name,
const char *blockids_json,
const char *paths_json,
const char *user,
gint64 file_size,
int replace_existed,
GError **error);
int
seafile_post_empty_file (const char *repo_id, const char *parent_dir,
const char *new_file_name, const char *user,
GError **error);
/**
* Update an existing file in a repo
* @params: same as seafile_post_file
* @head_id: the commit id for the original file version.
* It's optional. If it's NULL, the current repo head will be used.
* @return The new file id
*/
char *
seafile_put_file (const char *repo_id, const char *temp_file_path,
const char *parent_dir, const char *file_name,
const char *user, const char *head_id,
GError **error);
/**
* Add file blocks at once.
*
* @blocks_json: json array of block ids
* @paths_json: json array of temp file paths
*/
char *
seafile_put_file_blocks (const char *repo_id, const char *parent_dir,
const char *file_name, const char *blockids_json,
const char *paths_json, const char *user,
const char *head_id, gint64 file_size, GError **error);
int
seafile_post_dir (const char *repo_id, const char *parent_dir,
const char *new_dir_name, const char *user,
GError **error);
/**
* delete a file/directory from the repo on server.
* @repo_id: repo id
* @parent_dir: the parent directory of the file to be deleted
* @file_name: the name of the target file.
* @user: the email of the user who uploaded the file.
*/
int
seafile_del_file (const char *repo_id,
const char *parent_dir, const char *file_name,
const char *user,
GError **error);
/**
* copy a file/directory from a repo to another on server.
*/
GObject *
seafile_copy_file (const char *src_repo_id,
const char *src_dir,
const char *src_filename,
const char *dst_repo_id,
const char *dst_dir,
const char *dst_filename,
const char *user,
int need_progress,
int synchronous,
GError **error);
GObject *
seafile_move_file (const char *src_repo_id,
const char *src_dir,
const char *src_filename,
const char *dst_repo_id,
const char *dst_dir,
const char *dst_filename,
int replace,
const char *user,
int need_progress,
int synchronous,
GError **error);
GObject *
seafile_get_copy_task (const char *task_id, GError **error);
int
seafile_cancel_copy_task (const char *task_id, GError **error);
int
seafile_rename_file (const char *repo_id,
const char *parent_dir,
const char *oldname,
const char *newname,
const char *user,
GError **error);
/**
* Return non-zero if filename is valid.
*/
int
seafile_is_valid_filename (const char *repo_id,
const char *filename,
GError **error);
int
seafile_set_user_quota (const char *user, gint64 quota, GError **error);
gint64
seafile_get_user_quota (const char *user, GError **error);
int
seafile_check_quota (const char *repo_id, GError **error);
char *
seafile_get_file_id_by_path (const char *repo_id, const char *path,
GError **error);
char *
seafile_get_dir_id_by_path (const char *repo_id, const char *path,
GError **error);
GObject *
seafile_get_dirent_by_path (const char *repo_id, const char *path,
GError **error);
/**
* Return a list of commits where every commit contains a unique version of
* the file.
*/
GList *
seafile_list_file_revisions (const char *repo_id,
const char *path,
int max_revision,
int limit,
int show_days,
GError **error);
GList *
seafile_calc_files_last_modified (const char *repo_id,
const char *parent_dir,
int limit,
GError **error);
int
seafile_revert_file (const char *repo_id,
const char *commit_id,
const char *path,
const char *user,
GError **error);
int
seafile_revert_dir (const char *repo_id,
const char *commit_id,
const char *path,
const char *user,
GError **error);
char *
seafile_check_repo_blocks_missing (const char *repo_id,
const char *blockids_json,
GError **error);
/*
* @show_days: return deleted files in how many days, return all if 0.
*/
GList *
seafile_get_deleted (const char *repo_id, int show_days,
const char *path, const char *scan_stat,
int limit, GError **error);
/**
* Generate a new token for (repo_id, email) and return it
*/
char *
seafile_generate_repo_token (const char *repo_id,
const char *email,
GError **error);
int
seafile_delete_repo_token (const char *repo_id,
const char *token,
const char *user,
GError **error);
GList *
seafile_list_repo_tokens (const char *repo_id,
GError **error);
GList *
seafile_list_repo_tokens_by_email (const char *email,
GError **error);
int
seafile_delete_repo_tokens_by_peer_id(const char *email, const char *peer_id, GError **error);
int
seafile_delete_repo_tokens_by_email (const char *email,
GError **error);
/**
* create a repo on seahub
*/
char *
seafile_create_repo (const char *repo_name,
const char *repo_desc,
const char *owner_email,
const char *passwd,
GError **error);
char *
seafile_create_enc_repo (const char *repo_id,
const char *repo_name,
const char *repo_desc,
const char *owner_email,
const char *magic,
const char *random_key,
int enc_version,
GError **error);
char *
seafile_check_permission (const char *repo_id, const char *user, GError **error);
char *
seafile_check_permission_by_path (const char *repo_id, const char *path,
const char *user, GError **error);
GList *
seafile_list_dir_with_perm (const char *repo_id,
const char *path,
const char *dir_id,
const char *user,
int offset,
int limit,
GError **error);
int
seafile_set_inner_pub_repo (const char *repo_id,
const char *permission,
GError **error);
int
seafile_unset_inner_pub_repo (const char *repo_id, GError **error);
GList *
seafile_list_inner_pub_repos (GError **error);
gint64
seafile_count_inner_pub_repos (GError **error);
GList *
seafile_list_inner_pub_repos_by_owner (const char *user, GError **error);
int
seafile_is_inner_pub_repo (const char *repo_id, GError **error);
int
seafile_set_share_permission (const char *repo_id,
const char *from_email,
const char *to_email,
const char *permission,
GError **error);
int
seafile_set_group_repo_permission (int group_id,
const char *repo_id,
const char *permission,
GError **error);
char *
seafile_get_file_id_by_commit_and_path(const char *repo_id,
const char *commit_id,
const char *path,
GError **error);
/* virtual repo related */
char *
seafile_create_virtual_repo (const char *origin_repo_id,
const char *path,
const char *repo_name,
const char *repo_desc,
const char *owner,
const char *passwd,
GError **error);
GList *
seafile_get_virtual_repos_by_owner (const char *owner, GError **error);
GObject *
seafile_get_virtual_repo (const char *origin_repo,
const char *path,
const char *owner,
GError **error);
char *
seafile_get_system_default_repo_id (GError **error);
/* Clean trash */
int
seafile_clean_up_repo_history (const char *repo_id, int keep_days, GError **error);
/* ------------------ public RPC calls. ------------ */
GList* seafile_get_repo_list_pub (int start, int limit, GError **error);
GObject* seafile_get_repo_pub (const gchar* id, GError **error);
GList* seafile_get_commit_list_pub (const gchar *repo,
int offset,
int limit,
GError **error);
GObject* seafile_get_commit_pub (const gchar *id, GError **error);
char *seafile_diff_pub (const char *repo_id, const char *old, const char *new,
GError **error);
GList * seafile_list_dir_pub (const char *dir_id, GError **error);
GList *
seafile_get_shared_users_for_subdir (const char *repo_id,
const char *path,
const char *from_user,
GError **error);
GList *
seafile_get_shared_groups_for_subdir (const char *repo_id,
const char *path,
const char *from_user,
GError **error);
GObject *
seafile_generate_magic_and_random_key(int enc_version,
const char* repo_id,
const char *passwd,
GError **error);
json_t * seafile_get_sync_notification (GError **error);
#endif

Some files were not shown because too many files have changed in this diff Show More