diff --git a/common/rpc-service.c b/common/rpc-service.c index 6255b9e73..5c17f4326 100644 --- a/common/rpc-service.c +++ b/common/rpc-service.c @@ -2550,6 +2550,7 @@ seafile_post_file_blocks (const char *repo_id, const char *paths_json, const char *user, gint64 file_size, + int replace_existed, GError **error) { if (!repo_id || !parent_dir || !file_name @@ -2573,6 +2574,7 @@ seafile_post_file_blocks (const char *repo_id, paths_json, user, file_size, + replace_existed, &new_id, error) < 0) { return NULL; @@ -2587,6 +2589,7 @@ seafile_post_multi_files (const char *repo_id, const char *filenames_json, const char *paths_json, const char *user, + int replace_existed, GError **error) { if (!repo_id || !filenames_json || !parent_dir || !paths_json || !user) { @@ -2607,6 +2610,7 @@ seafile_post_multi_files (const char *repo_id, filenames_json, paths_json, user, + replace_existed, &ret_json, error) < 0) { return NULL; diff --git a/httpserver/upload-file.c b/httpserver/upload-file.c index e91d9eaab..3bee6cea0 100644 --- a/httpserver/upload-file.c +++ b/httpserver/upload-file.c @@ -305,6 +305,7 @@ upload_cb(evhtp_request_t *req, void *arg) filenames_json, tmp_files_json, fsm->user, + 0, &error); g_free (filenames_json); g_free (tmp_files_json); @@ -367,10 +368,11 @@ upload_api_cb(evhtp_request_t *req, void *arg) { RecvFSM *fsm = arg; SearpcClient *rpc_client = NULL; - char *parent_dir; + char *parent_dir, *replace_str; GError *error = NULL; int error_code = ERROR_INTERNAL; char *filenames_json, *tmp_files_json; + int replace = 0; /* After upload_headers_cb() returns an error, libevhtp may still * receive data from the web browser and call into this cb. @@ -386,6 +388,17 @@ upload_api_cb(evhtp_request_t *req, void *arg) return; } + replace_str = g_hash_table_lookup (fsm->form_kvs, "replace"); + if (replace_str) { + replace = atoi(replace_str); + if (replace != 0 && replace != 1) { + seaf_warning ("[Upload] Invalid argument replace: %s.\n", replace_str); + evbuffer_add_printf(req->buffer_out, "Invalid argument.\n"); + set_content_length_header (req); + evhtp_send_reply (req, EVHTP_RES_BADREQ); + return; + } + } parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); if (!parent_dir) { seaf_warning ("[upload] No parent dir given.\n"); @@ -417,6 +430,7 @@ upload_api_cb(evhtp_request_t *req, void *arg) filenames_json, tmp_files_json, fsm->user, + replace, &error); g_free (filenames_json); g_free (tmp_files_json); @@ -484,11 +498,12 @@ upload_blks_api_cb(evhtp_request_t *req, void *arg) { RecvFSM *fsm = arg; SearpcClient *rpc_client = NULL; - char *parent_dir, *file_name, *size_str; + char *parent_dir, *file_name, *size_str, *replace_str; GError *error = NULL; int error_code = ERROR_INTERNAL; char *blockids_json, *tmp_files_json; gint64 file_size = -1; + int replace = 0; /* After upload_headers_cb() returns an error, libevhtp may still * receive data from the web browser and call into this cb. @@ -497,6 +512,17 @@ upload_blks_api_cb(evhtp_request_t *req, void *arg) if (!fsm || fsm->state == RECV_ERROR) return; + replace_str = g_hash_table_lookup (fsm->form_kvs, "replace"); + if (replace_str) { + replace = atoi(replace_str); + if (replace != 0 && replace != 1) { + seaf_warning ("[Upload-blks] Invalid argument replace: %s.\n", replace_str); + evbuffer_add_printf(req->buffer_out, "Invalid argument.\n"); + set_content_length_header (req); + evhtp_send_reply (req, EVHTP_RES_BADREQ); + return; + } + } parent_dir = g_hash_table_lookup (fsm->form_kvs, "parent_dir"); file_name = g_hash_table_lookup (fsm->form_kvs, "file_name"); size_str = g_hash_table_lookup (fsm->form_kvs, "file_size"); @@ -534,6 +560,7 @@ upload_blks_api_cb(evhtp_request_t *req, void *arg) tmp_files_json, fsm->user, file_size, + replace, &error); g_free (blockids_json); g_free (tmp_files_json); @@ -668,6 +695,7 @@ upload_blks_ajax_cb(evhtp_request_t *req, void *arg) tmp_files_json, fsm->user, file_size, + 0, &error); g_free (blockids_json); g_free (tmp_files_json); @@ -806,6 +834,7 @@ upload_ajax_cb(evhtp_request_t *req, void *arg) filenames_json, tmp_files_json, fsm->user, + 0, &error); g_free (filenames_json); g_free (tmp_files_json); diff --git a/include/seafile-rpc.h b/include/seafile-rpc.h index 95e76dbc5..92ac34660 100644 --- a/include/seafile-rpc.h +++ b/include/seafile-rpc.h @@ -566,6 +566,7 @@ seafile_post_multi_files (const char *repo_id, const char *filenames_json, const char *paths_json, const char *user, + int replace, GError **error); /** @@ -582,6 +583,7 @@ seafile_post_file_blocks (const char *repo_id, const char *paths_json, const char *user, gint64 file_size, + int replace_existed, GError **error); diff --git a/include/seafile.h b/include/seafile.h index 00412afbb..6da9be301 100644 --- a/include/seafile.h +++ b/include/seafile.h @@ -132,6 +132,7 @@ seafile_post_file_blocks (SearpcClient *client, const char *paths_json, const char *user, gint64 file_size, + int replace_existed, GError **error); char * @@ -141,6 +142,7 @@ seafile_post_multi_files (SearpcClient *client, const char *filenames_json, const char *paths_json, const char *user, + int replace_existed, GError **error); int diff --git a/lib/rpc_table.py b/lib/rpc_table.py index 92392e439..10d124182 100644 --- a/lib/rpc_table.py +++ b/lib/rpc_table.py @@ -47,10 +47,12 @@ [ "string", ["string", "string", "string", "string"] ], [ "string", ["string", "string", "string", "string", "int"] ], [ "string", ["string", "string", "string", "string", "string"] ], + [ "string", ["string", "string", "string", "string", "string", "int"] ], [ "string", ["string", "string", "string", "string", "string", "string", "int"] ], [ "string", ["string", "string", "string", "string", "string", "string", "int", "int"] ], [ "string", ["string", "string", "string", "string", "string", "string"] ], [ "string", ["string", "string", "string", "string", "string", "string", "int64"] ], + [ "string", ["string", "string", "string", "string", "string", "string", "int64", "int"] ], [ "string", ["string", "string", "string", "string", "string", "string", "string"] ], [ "string", ["string", "string", "string", "string", "string", "string", "string", "int64"] ], [ "string", ["string", "string", "string", "string", "string", "string", "string", "string", "string"] ], diff --git a/lib/seafile-rpc-wrapper.c b/lib/seafile-rpc-wrapper.c index 5ac8ce4f1..e18f34cc0 100644 --- a/lib/seafile-rpc-wrapper.c +++ b/lib/seafile-rpc-wrapper.c @@ -322,16 +322,18 @@ seafile_post_file_blocks (SearpcClient *client, const char *paths_json, const char *user, gint64 file_size, + int replace_existed, GError **error) { return searpc_client_call__string (client, "seafile_post_file_blocks", error, - 7, "string", repo_id, + 8, "string", repo_id, "string", parent_dir, "string", file_name, "string", blockids_json, "string", paths_json, "string", user, - "int64", &file_size); + "int64", &file_size, + "int", replace_existed); } char * @@ -341,14 +343,16 @@ seafile_post_multi_files (SearpcClient *client, const char *filenames_json, const char *paths_json, const char *user, + int replace_existed, GError **error) { return searpc_client_call__string (client, "seafile_post_multi_files", error, - 5, "string", repo_id, + 6, "string", repo_id, "string", parent_dir, "string", filenames_json, "string", paths_json, - "string", user); + "string", user, + "int", replace_existed); } int diff --git a/server/repo-mgr.h b/server/repo-mgr.h index cf2a89668..2ff92545c 100644 --- a/server/repo-mgr.h +++ b/server/repo-mgr.h @@ -277,6 +277,7 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr, const char *filenames_json, const char *paths_json, const char *user, + int replace_existed, char **new_ids, GError **error); @@ -289,6 +290,7 @@ seaf_repo_manager_post_file_blocks (SeafRepoManager *mgr, const char *paths_json, const char *user, gint64 file_size, + int replace_existed, char **new_id, GError **error); diff --git a/server/repo-op.c b/server/repo-op.c index b3ba6a896..7a67b0508 100644 --- a/server/repo-op.c +++ b/server/repo-op.c @@ -129,6 +129,7 @@ static char * post_file_recursive (SeafRepo *repo, const char *dir_id, const char *to_path, + int replace_existed, SeafDirent *newdent) { SeafDir *olddir, *newdir; @@ -147,9 +148,30 @@ post_file_recursive (SeafRepo *repo, /* we reach the target dir. new dir entry is added */ if (*to_path == '\0') { - GList *newentries; + GList *newentries = NULL; char *unique_name; SeafDirent *dent_dup; + if (replace_existed && filename_exists(olddir->entries, newdent->name)) { + GList *p; + SeafDirent *dent; + + for (p = olddir->entries; p; p = p->next) { + dent = p->data; + if (strcmp(dent->name, newdent->name) == 0) { + newentries = g_list_prepend (newentries, seaf_dirent_dup(newdent)); + } else { + newentries = g_list_prepend (newentries, seaf_dirent_dup(dent)); + } + } + newentries = g_list_reverse (newentries); + newdir = seaf_dir_new (NULL, newentries, + dir_version_from_repo_version(repo->version)); + seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir); + id = g_strndup (newdir->dir_id, 41); + id[40] = '\0'; + seaf_dir_free (newdir); + goto out; + } unique_name = generate_unique_filename (newdent->name, olddir->entries); if (!unique_name) @@ -191,7 +213,7 @@ post_file_recursive (SeafRepo *repo, if (strcmp(dent->name, to_path_dup) != 0) continue; - id = post_file_recursive (repo, dent->id, remain, newdent); + id = post_file_recursive (repo, dent->id, remain, replace_existed, newdent); if (id != NULL) { memcpy(dent->id, id, 40); dent->id[40] = '\0'; @@ -224,16 +246,26 @@ post_file_recursive (SeafRepo *repo, } static char * -do_post_file (SeafRepo *repo, - const char *root_id, - const char *parent_dir, - SeafDirent *dent) +do_post_file_replace (SeafRepo *repo, + const char *root_id, + const char *parent_dir, + int replace_existed, + SeafDirent *dent) { /* if parent_dir is a absolutely path, we will remove the first '/' */ if (*parent_dir == '/') parent_dir = parent_dir + 1; - return post_file_recursive(repo, root_id, parent_dir, dent); + return post_file_recursive(repo, root_id, parent_dir, replace_existed, dent); +} + +static char * +do_post_file (SeafRepo *repo, + const char *root_id, + const char *parent_dir, + SeafDirent *dent) +{ + return do_post_file_replace(repo, root_id, parent_dir, 0, dent); } static char * @@ -685,7 +717,7 @@ seaf_repo_manager_post_file (SeafRepoManager *mgr, static int add_new_entries (SeafRepo *repo, const char *user, GList **entries, GList *filenames, GList *id_list, - GList *size_list, GList **name_list) + GList *size_list, int replace_existed, GList **name_list) { GList *ptr1, *ptr2, *ptr3; char *file, *id; @@ -701,8 +733,28 @@ add_new_entries (SeafRepo *repo, const char *user, char *unique_name; SeafDirent *newdent; + gboolean replace = FALSE; + + if (replace_existed) { + GList *p; + SeafDirent *dent; + + for (p = *entries; p; p = p->next) { + dent = p->data; + if (strcmp(dent->name, file) == 0) { + replace = TRUE; + *entries = g_list_delete_link (*entries, p); + seaf_dirent_free (dent); + break; + } + } + } + + if (replace) + unique_name = g_strdup (file); + else + unique_name = generate_unique_filename (file, *entries); - unique_name = generate_unique_filename (file, *entries); if (unique_name != NULL) { newdent = seaf_dirent_new (dir_version_from_repo_version(repo->version), id, STD_FILE_MODE, unique_name, @@ -726,6 +778,7 @@ post_multi_files_recursive (SeafRepo *repo, GList *id_list, GList *size_list, const char *user, + int replace_existed, GList **name_list) { SeafDir *olddir, *newdir; @@ -751,7 +804,7 @@ post_multi_files_recursive (SeafRepo *repo, if (add_new_entries (repo, user, &newentries, filenames, id_list, size_list, - name_list) < 0) + replace_existed, name_list) < 0) goto out; newdir = seaf_dir_new (NULL, newentries, @@ -780,9 +833,9 @@ post_multi_files_recursive (SeafRepo *repo, if (strcmp(dent->name, to_path_dup) != 0) continue; - id = post_multi_files_recursive (repo, - dent->id, remain, filenames, id_list, - size_list, user, name_list); + id = post_multi_files_recursive (repo, dent->id, remain, filenames, + id_list, size_list, user, + replace_existed, name_list); if (id != NULL) { memcpy(dent->id, id, 40); dent->id[40] = '\0'; @@ -822,15 +875,16 @@ do_post_multi_files (SeafRepo *repo, GList *id_list, GList *size_list, const char *user, + int replace_existed, GList **name_list) { /* if parent_dir is a absolutely path, we will remove the first '/' */ if (*parent_dir == '/') parent_dir = parent_dir + 1; - return post_multi_files_recursive(repo, - root_id, parent_dir, filenames, - id_list, size_list, user, name_list); + return post_multi_files_recursive(repo, root_id, parent_dir, + filenames, id_list, size_list, + user, replace_existed, name_list); } static GList * @@ -901,6 +955,7 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr, const char *filenames_json, const char *paths_json, const char *user, + int replace_existed, char **ret_json, GError **error) { @@ -990,9 +1045,9 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr, size_list = g_list_reverse (size_list); /* Add the files to parent dir and commit. */ - root_id = do_post_multi_files (repo, - head_commit->root_id, canon_path, - filenames, id_list, size_list, user, &name_list); + root_id = do_post_multi_files (repo, head_commit->root_id, canon_path, + filenames, id_list, size_list, user, + replace_existed, &name_list); if (!root_id) { seaf_warning ("[post file] Failed to put file.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, @@ -1050,6 +1105,7 @@ seaf_repo_manager_post_file_blocks (SeafRepoManager *mgr, const char *paths_json, const char *user, gint64 file_size, + int replace_existed, char **new_id, GError **error) { @@ -1124,8 +1180,8 @@ seaf_repo_manager_post_file_blocks (SeafRepoManager *mgr, hex, STD_FILE_MODE, file_name, (gint64)time(NULL), user, file_size); - root_id = do_post_file (repo, - head_commit->root_id, canon_path, new_dent); + root_id = do_post_file_replace (repo, head_commit->root_id, + canon_path, replace_existed, new_dent); if (!root_id) { seaf_warning ("[post-blks] Failed to post file.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, diff --git a/server/seaf-server.c b/server/seaf-server.c index 47220e634..8740c175a 100644 --- a/server/seaf-server.c +++ b/server/seaf-server.c @@ -194,11 +194,11 @@ static void start_rpc_service (CcnetClient *client, int cloud_mode) searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_post_file_blocks, "seafile_post_file_blocks", - searpc_signature_string__string_string_string_string_string_string_int64()); + searpc_signature_string__string_string_string_string_string_string_int64_int()); searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_post_multi_files, "seafile_post_multi_files", - searpc_signature_string__string_string_string_string_string()); + searpc_signature_string__string_string_string_string_string_int()); searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_put_file,