1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-09-18 16:35:42 +00:00

Create only one commit when move or copy multiple files

This commit is contained in:
cuihaikuo
2017-06-29 14:15:18 +08:00
parent 62833505af
commit ffd92675be
3 changed files with 774 additions and 88 deletions

View File

@@ -3716,11 +3716,19 @@ seafile_copy_file (const char *src_repo_id,
rsrc_dir = format_dir_path (norm_src_dir);
rdst_dir = format_dir_path (norm_dst_dir);
ret = (GObject *)seaf_repo_manager_copy_file (seaf->repo_mgr,
src_repo_id, rsrc_dir, norm_src_filename,
dst_repo_id, rdst_dir, norm_dst_filename,
user, need_progress, synchronous,
error);
if (strchr(norm_src_filename, '\t') && strchr(norm_dst_filename, '\t'))
ret = (GObject *)seaf_repo_manager_copy_multiple_files (seaf->repo_mgr,
src_repo_id, rsrc_dir, norm_src_filename,
dst_repo_id, rdst_dir, norm_dst_filename,
user, need_progress, synchronous,
error);
else
ret = (GObject *)seaf_repo_manager_copy_file (seaf->repo_mgr,
src_repo_id, rsrc_dir, norm_src_filename,
dst_repo_id, rdst_dir, norm_dst_filename,
user, need_progress, synchronous,
error);
out:
g_free (norm_src_dir);
@@ -3793,11 +3801,18 @@ seafile_move_file (const char *src_repo_id,
rsrc_dir = format_dir_path (norm_src_dir);
rdst_dir = format_dir_path (norm_dst_dir);
ret = (GObject *)seaf_repo_manager_move_file (seaf->repo_mgr,
src_repo_id, rsrc_dir, norm_src_filename,
dst_repo_id, rdst_dir, norm_dst_filename,
replace, user, need_progress, synchronous,
error);
if (strchr(norm_src_filename, '\t') && strchr(norm_dst_filename, '\t'))
ret = (GObject *)seaf_repo_manager_move_multiple_files (seaf->repo_mgr,
src_repo_id, rsrc_dir, norm_src_filename,
dst_repo_id, rdst_dir, norm_dst_filename,
replace, user, need_progress, synchronous,
error);
else
ret = (GObject *)seaf_repo_manager_move_file (seaf->repo_mgr,
src_repo_id, rsrc_dir, norm_src_filename,
dst_repo_id, rdst_dir, norm_dst_filename,
replace, user, need_progress, synchronous,
error);
out:
g_free (norm_src_dir);

View File

@@ -425,6 +425,19 @@ seaf_repo_manager_copy_file (SeafRepoManager *mgr,
int synchronous,
GError **error);
SeafileCopyResult *
seaf_repo_manager_copy_multiple_files (SeafRepoManager *mgr,
const char *src_repo_id,
const char *src_dir,
const char *src_filenames,
const char *dst_repo_id,
const char *dst_dir,
const char *dst_filenames,
const char *user,
int need_progress,
int synchronous,
GError **error);
SeafileCopyResult *
seaf_repo_manager_move_file (SeafRepoManager *mgr,
const char *src_repo_id,
@@ -439,6 +452,20 @@ seaf_repo_manager_move_file (SeafRepoManager *mgr,
int synchronous,
GError **error);
SeafileCopyResult *
seaf_repo_manager_move_multiple_files (SeafRepoManager *mgr,
const char *src_repo_id,
const char *src_dir,
const char *src_filenames,
const char *dst_repo_id,
const char *dst_dir,
const char *dst_filenames,
int replace,
const char *user,
int need_progress,
int synchronous,
GError **error);
int
seaf_repo_manager_rename_file (SeafRepoManager *mgr,
const char *repo_id,

View File

@@ -35,6 +35,9 @@
gboolean
should_ignore_file(const char *filename, void *data);
static gboolean
is_virtual_repo_and_origin (SeafRepo *repo1, SeafRepo *repo2);
/*
* Repo operations.
*/
@@ -1607,7 +1610,7 @@ seaf_repo_manager_del_file (SeafRepoManager *mgr,
}
/* Commit. */
if (file_num) {
if (file_num > 1) {
snprintf(buf, SEAF_PATH_MAX, "Deleted \"%s\" and %d more files",
desc_file, file_num - 1);
} else if (S_ISDIR(mode)) {
@@ -1704,7 +1707,8 @@ out:
static int
put_dirent_and_commit (SeafRepo *repo,
const char *path,
SeafDirent *dent,
SeafDirent *dents[],
int n_dents,
int replace,
const char *user,
GError **error)
@@ -1712,27 +1716,52 @@ put_dirent_and_commit (SeafRepo *repo,
SeafCommit *head_commit = NULL;
char *root_id = NULL;
char buf[SEAF_PATH_MAX];
int ret = 0;
int ret = 0, i = 0;
GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id);
root_id = do_post_file_replace (repo,
head_commit->root_id, path,
replace, dent);
root_id = head_commit->root_id;
GList *filenames = NULL;
GList *id_list = NULL;
GList *size_list = NULL;
GList *name_list = NULL;
for (i = 0; i < n_dents; i++) {
filenames = g_list_append (filenames, dents[i]->name);
id_list = g_list_append (id_list, dents[i]->id);
size_list = g_list_append (size_list, &(dents[i]->size));
}
if (*path == '/')
path = path + 1;
root_id = post_multi_files_recursive (repo, root_id, path, filenames,
id_list, size_list, user,
replace, &name_list);
g_list_free (filenames);
g_list_free (id_list);
g_list_free (size_list);
g_list_free_full (name_list, (GDestroyNotify)g_free);
if (!root_id) {
seaf_warning ("[cp file] Failed to cp file %s to %s in repo %s.\n",
dent->name, path, repo->id);
if (n_dents > 1)
seaf_warning ("[cp file] Failed to cp %s and other %d files to %s in repo %s.\n",
dents[0]->name, n_dents - 1, path, repo->id);
else
seaf_warning ("[cp file] Failed to cp %s to %s in repo %s.\n",
dents[0]->name, path, repo->id);
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"Failed to cp file");
"Failed to cp file");
ret = -1;
goto out;
}
/* Commit. */
if (S_ISDIR(dent->mode)) {
snprintf(buf, sizeof(buf), "Added directory \"%s\"", dent->name);
if (n_dents > 1) {
snprintf(buf, sizeof(buf), "Added \"%s\" and %d more files",
dents[0]->name, n_dents - 1);
} else if (S_ISDIR(dents[0]->mode)) {
snprintf(buf, sizeof(buf), "Added directory \"%s\"", dents[0]->name);
} else {
snprintf(buf, sizeof(buf), "Added \"%s\"", dent->name);
snprintf(buf, sizeof(buf), "Added \"%s\"", dents[0]->name);
}
if (gen_new_commit (repo->id, head_commit, root_id,
@@ -1883,7 +1912,12 @@ cross_repo_copy (const char *src_repo_id,
{
SeafRepo *src_repo = NULL, *dst_repo = NULL;
SeafDirent *src_dent = NULL, *dst_dent = NULL;
int ret = 0;
SeafDirent **src_dents = NULL, **dst_dents = NULL;
char **src_names = NULL, **dst_names = NULL;
char *new_id = NULL;
guint64 new_size = 0;
int ret = 0, i = 0;
int file_num = 1;
src_repo = seaf_repo_manager_get_repo (seaf->repo_mgr, src_repo_id);
if (!src_repo) {
@@ -1897,30 +1931,70 @@ cross_repo_copy (const char *src_repo_id,
goto out;
}
src_dent = get_dirent_by_path (src_repo, NULL,
src_path, src_filename, NULL);
if (!src_dent) {
ret = -1;
goto out;
/* get src dirents */
if (strchr(src_filename, '\t') && strchr(dst_filename, '\t')) {
src_names = g_strsplit (src_filename, "\t", -1);
dst_names = g_strsplit (dst_filename, "\t", -1);
file_num = g_strv_length (src_names);
src_dents = g_new0 (SeafDirent *, file_num);
dst_dents = g_new0 (SeafDirent *, file_num);
for (i = 0; i < file_num; i++) {
if (strcmp(src_names[i], "") == 0) {
ret = -1;
seaf_warning ("[copy files] Bad args: Empty src_filename.\n");
goto out;
}
src_dents[i] = get_dirent_by_path (src_repo, NULL,
src_path, src_names[i], NULL);
if (!src_dents[i]) {
ret = -1;
seaf_warning ("[copy files] File %s not Found.\n", src_names[i]);
goto out;
}
}
for (i = 0; i < file_num; i++) {
new_id = copy_recursive (src_repo, dst_repo,
src_dents[i]->id, src_dents[i]->mode, modifier, task,
&new_size);
if (!new_id) {
ret = -1;
seaf_warning ("[copy files] Failed to copy file %s.\n", src_dents[i]->name);
goto out;
}
dst_dents[i] = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
new_id, src_dents[i]->mode, dst_names[i],
src_dents[i]->mtime, modifier, new_size);
g_free (new_id);
}
} else {
src_dent = get_dirent_by_path (src_repo, NULL,
src_path, src_filename, NULL);
if (!src_dent) {
ret = -1;
goto out;
}
new_id = copy_recursive (src_repo, dst_repo,
src_dent->id, src_dent->mode, modifier, task,
&new_size);
if (!new_id) {
ret = -1;
goto out;
}
dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
new_id, src_dent->mode, dst_filename,
src_dent->mtime, modifier, new_size);
g_free (new_id);
}
guint64 new_size = 0;
char *new_id = copy_recursive (src_repo, dst_repo,
src_dent->id, src_dent->mode, modifier, task,
&new_size);
if (!new_id) {
ret = -1;
goto out;
}
dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
new_id, src_dent->mode, dst_filename,
src_dent->mtime, modifier, new_size);
g_free (new_id);
if (put_dirent_and_commit (dst_repo,
dst_path,
dst_dent,
file_num > 1 ? dst_dents : &dst_dent,
file_num,
replace,
modifier,
NULL) < 0) {
@@ -1942,6 +2016,16 @@ out:
seaf_dirent_free(src_dent);
if (dst_dent)
seaf_dirent_free(dst_dent);
if (file_num > 1) {
for (i = 0; i < file_num; i++) {
seaf_dirent_free(src_dents[i]);
seaf_dirent_free(dst_dents[i]);
}
g_free (src_dents);
g_free (dst_dents);
g_strfreev(src_names);
g_strfreev(dst_names);
}
if (ret == 0) {
update_repo_size (dst_repo_id);
@@ -1967,7 +2051,7 @@ is_virtual_repo_and_origin (SeafRepo *repo1, SeafRepo *repo2)
static gboolean
check_file_count_and_size (SeafRepo *repo, SeafDirent *dent, gint64 total_files,
GError **error)
gint64 *multi_file_size, GError **error)
{
if (seaf->copy_mgr->max_files > 0 &&
total_files > seaf->copy_mgr->max_files) {
@@ -1998,6 +2082,14 @@ check_file_count_and_size (SeafRepo *repo, SeafDirent *dent, gint64 total_files,
repo->store_id, dent->id);
return FALSE;
}
if (multi_file_size) {
*multi_file_size += size;
if (*multi_file_size > seaf->copy_mgr->max_size) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"Folder or file size is too large");
return FALSE;
}
}
if (size > seaf->copy_mgr->max_size) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
@@ -2059,13 +2151,12 @@ seaf_repo_manager_copy_file (SeafRepoManager *mgr,
src_canon_path = get_canonical_path (src_path);
dst_canon_path = get_canonical_path (dst_path);
/* first check whether a file with file_name already exists in destination dir */
GET_COMMIT_OR_FAIL(dst_head_commit,
dst_repo->id, dst_repo->version,
dst_repo->head->commit_id);
FAIL_IF_FILE_EXISTS(dst_repo->store_id, dst_repo->version,
dst_head_commit->root_id, dst_canon_path, dst_filename, NULL);
/* FAIL_IF_FILE_EXISTS(dst_repo->store_id, dst_repo->version,
dst_head_commit->root_id, dst_canon_path, dst_filename, NULL); */
/* get src dirent */
src_dent = get_dirent_by_path (src_repo, NULL,
@@ -2087,7 +2178,8 @@ seaf_repo_manager_copy_file (SeafRepoManager *mgr,
if (put_dirent_and_commit (dst_repo,
dst_canon_path,
dst_dent,
&dst_dent,
1,
0,
user,
error) < 0) {
@@ -2118,7 +2210,7 @@ seaf_repo_manager_copy_file (SeafRepoManager *mgr,
goto out;
}
if (!check_file_count_and_size (src_repo, src_dent, total_files, error)) {
if (!check_file_count_and_size (src_repo, src_dent, total_files, NULL, error)) {
ret = -1;
goto out;
}
@@ -2143,7 +2235,7 @@ seaf_repo_manager_copy_file (SeafRepoManager *mgr,
goto out;
}
} else {
/* Synchronous for cross-repo move */
/* Synchronous for cross-repo copy */
if (cross_repo_copy (src_repo_id,
src_canon_path,
src_filename,
@@ -2185,10 +2277,231 @@ out:
return res;
}
SeafileCopyResult *
seaf_repo_manager_copy_multiple_files (SeafRepoManager *mgr,
const char *src_repo_id,
const char *src_path,
const char *src_filenames,
const char *dst_repo_id,
const char *dst_path,
const char *dst_filenames,
const char *user,
int need_progress,
int synchronous,
GError **error)
{
SeafRepo *src_repo = NULL, *dst_repo = NULL;
SeafDirent **src_dents = NULL, **dst_dents = NULL;
char *src_canon_path = NULL, *dst_canon_path = NULL;
SeafCommit *dst_head_commit = NULL;
int i = 0, ret = 0;
int file_num = 1;
gint64 *file_sizes = NULL;
gboolean background = FALSE;
char *task_id = NULL;
char **src_names = NULL, **dst_names = NULL;
SeafileCopyResult *res = NULL;
GET_REPO_OR_FAIL(src_repo, src_repo_id);
if (strcmp(src_repo_id, dst_repo_id) != 0) {
GET_REPO_OR_FAIL(dst_repo, dst_repo_id);
if (src_repo->encrypted || dst_repo->encrypted) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
"Can't copy files between encrypted repo(s)");
ret = -1;
goto out;
}
} else {
seaf_repo_ref (src_repo);
dst_repo = src_repo;
}
src_canon_path = get_canonical_path (src_path);
dst_canon_path = get_canonical_path (dst_path);
GET_COMMIT_OR_FAIL(dst_head_commit,
dst_repo->id, dst_repo->version,
dst_repo->head->commit_id);
/*FAIL_IF_FILE_EXISTS(dst_repo->store_id, dst_repo->version,
dst_head_commit->root_id, dst_canon_path, dst_filename, NULL);*/
/* get src dirents */
if (strchr(src_filenames, '\t') && strchr(dst_filenames, '\t')) {
src_names = g_strsplit (src_filenames, "\t", -1);
dst_names = g_strsplit (dst_filenames, "\t", -1);
file_num = g_strv_length (src_names);
int dst_file_num = g_strv_length (dst_names);
if (dst_file_num != file_num) {
ret = -1;
seaf_warning ("[copy files] Bad args.\n");
goto out;
}
src_dents = g_new0 (SeafDirent *, file_num);
file_sizes = g_new0 (gint64, file_num);
for (i = 0; i < file_num; i++) {
if (strcmp(src_names[i], "") == 0) {
ret = -1;
seaf_warning ("[copy files] Bad args: Empty src_filenames.\n");
goto out;
}
src_dents[i] = get_dirent_by_path (src_repo, NULL,
src_canon_path, src_names[i], error);
if (!src_dents[i]) {
ret = -1;
seaf_warning ("[copy files] File %s not Found.\n", src_names[i]);
goto out;
}
file_sizes[i] = (src_dents[i]->version > 0) ? src_dents[i]->size : -1;
}
} else {
ret = -1;
seaf_warning ("[copy files] Bad args: Split filenames with '\\t'.\n");
goto out;
}
/* copy file within the same repo */
if (src_repo == dst_repo ||
is_virtual_repo_and_origin (src_repo, dst_repo)) {
dst_dents = g_new0 (SeafDirent *, file_num);
for (i = 0; i < file_num; i++) {
if (strcmp(dst_names[i], "") == 0) {
ret = -1;
seaf_warning ("[copy files] Bad args: Empty dst_filenames.\n");
goto out;
}
/* duplicate src dirents with new names */
dst_dents[i] = seaf_dirent_new (dir_version_from_repo_version (dst_repo->version),
src_dents[i]->id, src_dents[i]->mode, dst_names[i],
src_dents[i]->mtime, user, file_sizes[i]);
}
if (put_dirent_and_commit (dst_repo,
dst_canon_path,
dst_dents,
file_num,
0,
user,
error) < 0) {
if (!error)
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"failed to put dirents");
ret = -1;
goto out;
}
seaf_repo_manager_merge_virtual_repo (mgr, src_repo_id, NULL);
update_repo_size (dst_repo_id);
} else {
/* copy between different repos */
if (!synchronous) {
background = TRUE;
gint64 total_files = -1;
gint64 total_files_all = 0;
gint64 total_size_all = 0;
for (i = 0; i < file_num; i++) {
if (S_ISDIR(src_dents[i]->mode))
total_files = seaf_fs_manager_count_fs_files (seaf->fs_mgr,
src_repo->store_id,
src_repo->version,
src_dents[i]->id);
else
total_files = 1;
if (total_files < 0) {
seaf_warning ("Failed to get file count.\n");
ret = -1;
goto out;
}
total_files_all += total_files;
if (!check_file_count_and_size (src_repo, src_dents[i], total_files_all,
&total_size_all, error)) {
ret = -1;
goto out;
}
}
task_id = seaf_copy_manager_add_task (seaf->copy_mgr,
src_repo_id,
src_canon_path,
src_filenames,
dst_repo_id,
dst_canon_path,
dst_filenames,
0,
user,
total_files_all,
cross_repo_copy,
need_progress);
if (need_progress && !task_id) {
seaf_warning ("Failed to start copy task.\n");
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"failed to start copy task");
ret = -1;
goto out;
}
} else {
/* Synchronous for cross-repo copy */
if (cross_repo_copy (src_repo_id,
src_canon_path,
src_filenames,
dst_repo_id,
dst_canon_path,
dst_filenames,
0,
user,
NULL) < 0) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"Failed to move");
ret = -1;
goto out;
}
} // Synchronous copy
} //else diffrent repo
out:
if (src_repo) seaf_repo_unref (src_repo);
if (dst_repo) seaf_repo_unref (dst_repo);
if (dst_head_commit) seaf_commit_unref(dst_head_commit);
if (src_canon_path) g_free (src_canon_path);
if (dst_canon_path) g_free (dst_canon_path);
if (src_names)
g_strfreev (src_names);
if (dst_names)
g_strfreev (dst_names);
if (file_sizes)
g_free (file_sizes);
if (src_dents) {
for (i = 0; i < file_num; i++)
seaf_dirent_free (src_dents[i]);
g_free (src_dents);
}
if (dst_dents) {
for (i = 0; i < file_num; i++)
seaf_dirent_free (dst_dents[i]);
g_free (dst_dents);
}
if (ret == 0) {
res = seafile_copy_result_new ();
g_object_set (res, "background", background, "task_id", task_id, NULL);
g_free (task_id);
}
return res;
}
static int
move_file_same_repo (const char *repo_id,
const char *src_path, SeafDirent *src_dent,
const char *dst_path, SeafDirent *dst_dent,
const char *src_path, SeafDirent *src_dents[],
const char *dst_path, SeafDirent *dst_dents[],
int file_num,
int replace,
const char *user,
GError **error)
@@ -2197,21 +2510,45 @@ move_file_same_repo (const char *repo_id,
SeafCommit *head_commit = NULL;
char *root_id_after_put = NULL, *root_id = NULL;
char buf[SEAF_PATH_MAX];
int ret = 0;
int ret = 0, i = 0;
GString *filenames_str = NULL;
GET_REPO_OR_FAIL(repo, repo_id);
GET_COMMIT_OR_FAIL(head_commit, repo->id, repo->version, repo->head->commit_id);
root_id_after_put = do_post_file_replace (repo,
head_commit->root_id, dst_path,
replace, dst_dent);
filenames_str = g_string_new ("");
root_id_after_put = head_commit->root_id;
GList *filenames = NULL;
GList *id_list = NULL;
GList *size_list = NULL;
GList *name_list = NULL;
for (i = 0; i < file_num; i++) {
filenames = g_list_append (filenames, dst_dents[i]->name);
id_list = g_list_append (id_list, dst_dents[i]->id);
size_list = g_list_append (size_list, &(dst_dents[i]->size));
g_string_append_printf (filenames_str, "%s", src_dents[i]->name);
if ((i + 1) < file_num)
g_string_append_printf (filenames_str, "\t");
}
if (*dst_path == '/')
dst_path = dst_path + 1;
root_id_after_put = post_multi_files_recursive (repo, head_commit->root_id, dst_path, filenames,
id_list, size_list, user,
replace, &name_list);
g_list_free (filenames);
g_list_free (id_list);
g_list_free (size_list);
g_list_free_full (name_list, (GDestroyNotify)g_free);
if (!root_id_after_put) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "move file failed");
ret = -1;
goto out;
}
root_id = do_del_file (repo, root_id_after_put, src_path, filenames_str->str);
root_id = do_del_file (repo, root_id_after_put, src_path, src_dent->name);
if (!root_id) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "move file failed");
ret = -1;
@@ -2219,10 +2556,13 @@ move_file_same_repo (const char *repo_id,
}
/* Commit. */
if (S_ISDIR(src_dent->mode)) {
snprintf(buf, SEAF_PATH_MAX, "Moved directory \"%s\"", src_dent->name);
if (file_num > 1) {
snprintf(buf, SEAF_PATH_MAX, "Moved \"%s\" and %d more files",
src_dents[0]->name,file_num - 1);
} else if (S_ISDIR(src_dents[0]->mode)) {
snprintf(buf, SEAF_PATH_MAX, "Moved directory \"%s\"", src_dents[0]->name);
} else {
snprintf(buf, SEAF_PATH_MAX, "Moved \"%s\"", src_dent->name);
snprintf(buf, SEAF_PATH_MAX, "Moved \"%s\"", src_dents[0]->name);
}
if (gen_new_commit (repo_id, head_commit, root_id,
@@ -2234,6 +2574,9 @@ out:
seaf_repo_unref (repo);
if (head_commit)
seaf_commit_unref (head_commit);
if (filenames_str)
g_string_free (filenames_str, TRUE);
g_free (root_id_after_put);
g_free (root_id);
@@ -2253,7 +2596,12 @@ cross_repo_move (const char *src_repo_id,
{
SeafRepo *src_repo = NULL, *dst_repo = NULL;
SeafDirent *src_dent = NULL, *dst_dent = NULL;
int ret = 0;
SeafDirent **src_dents = NULL, **dst_dents = NULL;
char **src_names = NULL, **dst_names = NULL;
char *new_id = NULL;
guint64 new_size = 0;
int ret = 0, i = 0;
int file_num = 1;
src_repo = seaf_repo_manager_get_repo (seaf->repo_mgr, src_repo_id);
if (!src_repo) {
@@ -2267,30 +2615,70 @@ cross_repo_move (const char *src_repo_id,
goto out;
}
src_dent = get_dirent_by_path (src_repo, NULL,
src_path, src_filename, NULL);
if (!src_dent) {
ret = -1;
goto out;
}
/* get src dirents */
if (strchr(src_filename, '\t') && strchr(dst_filename, '\t')) {
src_names = g_strsplit (src_filename, "\t", -1);
dst_names = g_strsplit (dst_filename, "\t", -1);
file_num = g_strv_length (src_names);
guint64 new_size = 0;
char *new_id = copy_recursive (src_repo, dst_repo,
src_dent->id, src_dent->mode, modifier, task,
&new_size);
if (!new_id) {
ret = -1;
goto out;
}
src_dents = g_new0 (SeafDirent *, file_num);
dst_dents = g_new0 (SeafDirent *, file_num);
dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
new_id, src_dent->mode, dst_filename,
src_dent->mtime, modifier, new_size);
g_free (new_id);
for (i = 0; i < file_num; i++) {
if (strcmp(src_names[i], "") == 0) {
ret = -1;
seaf_warning ("[move files] Bad args: Empty src_filename.\n");
goto out;
}
src_dents[i] = get_dirent_by_path (src_repo, NULL,
src_path, src_names[i], NULL);
if (!src_dents[i]) {
ret = -1;
seaf_warning ("[move files] File %s not Found.\n", src_names[i]);
goto out;
}
}
for (i = 0; i < file_num; i++) {
new_id = copy_recursive (src_repo, dst_repo,
src_dents[i]->id, src_dents[i]->mode, modifier, task,
&new_size);
if (!new_id) {
ret = -1;
seaf_warning ("[move files] Failed to copy file %s.\n", src_dents[i]->name);
goto out;
}
dst_dents[i] = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
new_id, src_dents[i]->mode, dst_names[i],
src_dents[i]->mtime, modifier, new_size);
g_free (new_id);
}
} else {
src_dent = get_dirent_by_path (src_repo, NULL,
src_path, src_filename, NULL);
if (!src_dent) {
ret = -1;
goto out;
}
new_id = copy_recursive (src_repo, dst_repo,
src_dent->id, src_dent->mode, modifier, task,
&new_size);
if (!new_id) {
ret = -1;
goto out;
}
dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
new_id, src_dent->mode, dst_filename,
src_dent->mtime, modifier, new_size);
g_free (new_id);
}
if (put_dirent_and_commit (dst_repo,
dst_path,
dst_dent,
file_num > 1 ? dst_dents : &dst_dent,
file_num,
replace,
modifier,
NULL) < 0) {
@@ -2320,6 +2708,16 @@ out:
seaf_dirent_free(src_dent);
if (dst_dent)
seaf_dirent_free(dst_dent);
if (file_num > 1) {
for (i = 0; i < file_num; i++) {
seaf_dirent_free(src_dents[i]);
seaf_dirent_free(dst_dents[i]);
}
g_free (src_dents);
g_free (dst_dents);
g_strfreev(src_names);
g_strfreev(dst_names);
}
if (ret == 0) {
update_repo_size (dst_repo_id);
@@ -2387,7 +2785,6 @@ seaf_repo_manager_move_file (SeafRepoManager *mgr,
ret = -1;
goto out;
}
gint64 file_size = (src_dent->version > 0) ? src_dent->size : -1;
if (src_repo == dst_repo) {
@@ -2398,9 +2795,9 @@ seaf_repo_manager_move_file (SeafRepoManager *mgr,
/* move file within the same repo */
if (move_file_same_repo (src_repo_id,
src_canon_path, src_dent,
dst_canon_path, dst_dent,
replace, user, error) < 0) {
src_canon_path, &src_dent,
dst_canon_path, &dst_dent,
1, replace, user, error) < 0) {
ret = -1;
goto out;
}
@@ -2421,7 +2818,8 @@ seaf_repo_manager_move_file (SeafRepoManager *mgr,
/* add this dirent to dst repo */
if (put_dirent_and_commit (dst_repo,
dst_canon_path,
dst_dent,
&dst_dent,
1,
replace,
user,
error) < 0) {
@@ -2460,7 +2858,7 @@ seaf_repo_manager_move_file (SeafRepoManager *mgr,
goto out;
}
if (!check_file_count_and_size (src_repo, src_dent, total_files, error)) {
if (!check_file_count_and_size (src_repo, src_dent, total_files, NULL, error)) {
ret = -1;
goto out;
}
@@ -2524,6 +2922,252 @@ out:
return res;
}
SeafileCopyResult *
seaf_repo_manager_move_multiple_files (SeafRepoManager *mgr,
const char *src_repo_id,
const char *src_path,
const char *src_filenames,
const char *dst_repo_id,
const char *dst_path,
const char *dst_filenames,
int replace,
const char *user,
int need_progress,
int synchronous,
GError **error)
{
SeafRepo *src_repo = NULL, *dst_repo = NULL;
SeafDirent **src_dents = NULL, **dst_dents = NULL;
char *src_canon_path = NULL, *dst_canon_path = NULL;
SeafCommit *dst_head_commit = NULL;
int i = 0, ret = 0;
int file_num = 1;
gint64 *file_sizes = NULL;
gboolean background = FALSE;
char *task_id = NULL;
char **src_names = NULL, **dst_names = NULL;
SeafileCopyResult *res = NULL;
GET_REPO_OR_FAIL(src_repo, src_repo_id);
if (strcmp(src_repo_id, dst_repo_id) != 0) {
GET_REPO_OR_FAIL(dst_repo, dst_repo_id);
if (src_repo->encrypted || dst_repo->encrypted) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
"Can't copy files between encrypted repo(s)");
ret = -1;
goto out;
}
} else {
seaf_repo_ref (src_repo);
dst_repo = src_repo;
}
src_canon_path = get_canonical_path (src_path);
dst_canon_path = get_canonical_path (dst_path);
GET_COMMIT_OR_FAIL(dst_head_commit,
dst_repo->id, dst_repo->version,
dst_repo->head->commit_id);
/*FAIL_IF_FILE_EXISTS(dst_repo->store_id, dst_repo->version,
dst_head_commit->root_id, dst_canon_path, dst_filename, NULL);*/
/* get src dirents */
if (strchr(src_filenames, '\t') && strchr(dst_filenames, '\t')) {
src_names = g_strsplit (src_filenames, "\t", -1);
dst_names = g_strsplit (dst_filenames, "\t", -1);
file_num = g_strv_length (src_names);
int dst_file_num = g_strv_length (dst_names);
if (dst_file_num != file_num) {
ret = -1;
seaf_warning ("[move files] Bad args.\n");
goto out;
}
src_dents = g_new0 (SeafDirent *, file_num);
file_sizes = g_new0 (gint64, file_num);
for (i = 0; i < file_num; i++) {
if (strcmp(src_names[i], "") == 0) {
ret = -1;
seaf_warning ("[move files] Bad args: Empty src_filenames.\n");
goto out;
}
src_dents[i] = get_dirent_by_path (src_repo, NULL,
src_canon_path, src_names[i], error);
if (!src_dents[i]) {
ret = -1;
seaf_warning ("[move files] File %s not Found.\n", src_names[i]);
goto out;
}
file_sizes[i] = (src_dents[i]->version > 0) ? src_dents[i]->size : -1;
}
} else {
ret = -1;
seaf_warning ("[move files] Bad args: Split filenames with '\\t'.\n");
goto out;
}
/* move file within the same repo */
if (src_repo == dst_repo) {
dst_dents = g_new0 (SeafDirent *, file_num);
for (i = 0; i < file_num; i++) {
if (strcmp(dst_names[i], "") == 0) {
ret = -1;
seaf_warning ("[move files] Bad args: Empty dst_filenames.\n");
goto out;
}
/* duplicate src dirents with new names */
dst_dents[i] = seaf_dirent_new (dir_version_from_repo_version (dst_repo->version),
src_dents[i]->id, src_dents[i]->mode, dst_names[i],
src_dents[i]->mtime, user, file_sizes[i]);
}
/* move file within the same repo */
if (move_file_same_repo (src_repo_id,
src_canon_path, src_dents,
dst_canon_path, dst_dents,
file_num, replace, user, error) < 0) {
ret = -1;
goto out;
}
seaf_repo_manager_cleanup_virtual_repos (mgr, src_repo_id);
seaf_repo_manager_merge_virtual_repo (mgr, src_repo_id, NULL);
update_repo_size (dst_repo_id);
} else {
/* move between virtual and origin repos */
if (is_virtual_repo_and_origin (src_repo, dst_repo)) {
dst_dents = g_new0 (SeafDirent *, file_num);
for (i = 0; i < file_num; i++) {
dst_dents[i] = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
src_dents[i]->id, src_dents[i]->mode, dst_names[i],
src_dents[i]->mtime, user, src_dents[i]->size);
}
if (put_dirent_and_commit (dst_repo,
dst_path,
dst_dents,
file_num,
replace,
user,
NULL) < 0) {
ret = -1;
goto out;
}
seaf_repo_manager_merge_virtual_repo (mgr, dst_repo->id, NULL);
if (seaf_repo_manager_del_file (mgr, src_repo->id, src_path,
src_filenames, user, error) < 0) {
ret = -1;
goto out;
}
seaf_repo_manager_merge_virtual_repo (mgr, src_repo->id, NULL);
update_repo_size (dst_repo->id);
} else if (!synchronous) {
/* move between different repos */
background = TRUE;
gint64 total_files = -1;
gint64 total_files_all = 0;
gint64 total_size_all = 0;
for (i = 0; i < file_num; i++) {
if (S_ISDIR(src_dents[i]->mode))
total_files = seaf_fs_manager_count_fs_files (seaf->fs_mgr,
src_repo->store_id,
src_repo->version,
src_dents[i]->id);
else
total_files = 1;
if (total_files < 0) {
seaf_warning ("Failed to get file count.\n");
ret = -1;
goto out;
}
total_files_all += total_files;
if (!check_file_count_and_size (src_repo, src_dents[i], total_files_all,
&total_size_all, error)) {
ret = -1;
goto out;
}
}
task_id = seaf_copy_manager_add_task (seaf->copy_mgr,
src_repo_id,
src_canon_path,
src_filenames,
dst_repo_id,
dst_canon_path,
dst_filenames,
0,
user,
total_files_all,
cross_repo_move,
need_progress);
if (need_progress && !task_id) {
seaf_warning ("Failed to start copy task.\n");
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"failed to start copy task");
ret = -1;
goto out;
}
} else {
/* Synchronous for cross-repo move */
if (cross_repo_move (src_repo_id,
src_canon_path,
src_filenames,
dst_repo_id,
dst_canon_path,
dst_filenames,
replace,
user,
NULL) < 0) {
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
"Failed to move");
ret = -1;
goto out;
}
} // Synchronous move
} //else diffrent repo
out:
if (src_repo) seaf_repo_unref (src_repo);
if (dst_repo) seaf_repo_unref (dst_repo);
if (dst_head_commit) seaf_commit_unref(dst_head_commit);
if (src_canon_path) g_free (src_canon_path);
if (dst_canon_path) g_free (dst_canon_path);
if (src_names)
g_strfreev (src_names);
if (dst_names)
g_strfreev (dst_names);
if (file_sizes)
g_free (file_sizes);
if (src_dents) {
for (i = 0; i < file_num; i++)
seaf_dirent_free (src_dents[i]);
g_free (src_dents);
}
if (dst_dents) {
for (i = 0; i < file_num; i++)
seaf_dirent_free (dst_dents[i]);
g_free (dst_dents);
}
if (ret == 0) {
res = seafile_copy_result_new ();
g_object_set (res, "background", background, "task_id", task_id, NULL);
g_free (task_id);
}
return res;
}
int
seaf_repo_manager_post_dir (SeafRepoManager *mgr,
const char *repo_id,