diff --git a/common/fs-mgr.c b/common/fs-mgr.c index a05b44ee..d39fa530 100644 --- a/common/fs-mgr.c +++ b/common/fs-mgr.c @@ -1626,6 +1626,30 @@ seaf_fs_manager_get_seafdir_sorted (SeafFSManager *mgr, return dir; } +SeafDir * +seaf_fs_manager_get_seafdir_sorted_by_path (SeafFSManager *mgr, + const char *repo_id, + int version, + const char *root_id, + const char *path) +{ + SeafDir *dir = seaf_fs_manager_get_seafdir_by_path (mgr, repo_id, + version, root_id, + path, NULL); + + if (!dir) + return NULL; + + /* Only some very old dir objects are not sorted. */ + if (version > 0) + return dir; + + if (!is_dirents_sorted (dir->entries)) + dir->entries = g_list_sort (dir->entries, compare_dirents); + + return dir; +} + static int parse_metadata_type_v0 (const uint8_t *data, int len) { diff --git a/common/fs-mgr.h b/common/fs-mgr.h index d6e7767a..fe48cd26 100644 --- a/common/fs-mgr.h +++ b/common/fs-mgr.h @@ -226,6 +226,13 @@ seaf_fs_manager_get_seafdir_sorted (SeafFSManager *mgr, int version, const char *dir_id); +SeafDir * +seaf_fs_manager_get_seafdir_sorted_by_path (SeafFSManager *mgr, + const char *repo_id, + int version, + const char *root_id, + const char *path); + int seaf_fs_manager_populate_blocklist (SeafFSManager *mgr, const char *repo_id, diff --git a/common/rpc-service.c b/common/rpc-service.c index ddc41cb8..47250c94 100644 --- a/common/rpc-service.c +++ b/common/rpc-service.c @@ -3491,7 +3491,8 @@ seafile_revert_dir (const char *repo_id, } GList * -seafile_get_deleted (const char *repo_id, int show_days, GError **error) +seafile_get_deleted (const char *repo_id, int show_days, + const char *path, GError **error) { if (!repo_id) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, @@ -3505,7 +3506,8 @@ seafile_get_deleted (const char *repo_id, int show_days, GError **error) } return seaf_repo_manager_get_deleted_entries (seaf->repo_mgr, - repo_id, show_days, error); + repo_id, show_days, + path, error); } char * diff --git a/include/seafile-rpc.h b/include/seafile-rpc.h index db1ac820..67a9a56c 100644 --- a/include/seafile-rpc.h +++ b/include/seafile-rpc.h @@ -760,7 +760,8 @@ seafile_revert_dir (const char *repo_id, * @show_days: return deleted files in how many days, return all if 0. */ GList * -seafile_get_deleted (const char *repo_id, int show_days, GError **error); +seafile_get_deleted (const char *repo_id, int show_days, + const char *path, GError **error); /** * Generate a new token for (repo_id, email) and return it diff --git a/lib/rpc_table.py b/lib/rpc_table.py index d226a41d..cb96620b 100644 --- a/lib/rpc_table.py +++ b/lib/rpc_table.py @@ -67,6 +67,7 @@ func_table = [ [ "objlist", ["string"] ], [ "objlist", ["string", "int"] ], [ "objlist", ["string", "int", "int"] ], + [ "objlist", ["string", "int", "string"] ], [ "objlist", ["string", "string"] ], [ "objlist", ["string", "string", "string"] ], [ "objlist", ["string", "string", "int"] ], diff --git a/python/seafile/rpcclient.py b/python/seafile/rpcclient.py index 8ee61b30..8caa3fc2 100644 --- a/python/seafile/rpcclient.py +++ b/python/seafile/rpcclient.py @@ -515,8 +515,8 @@ class SeafServerThreadedRpcClient(ccnet.RpcClientBase): pass revert_dir = seafile_revert_dir - @searpc_func("objlist", ["string", "int"]) - def get_deleted(repo_id, show_days): + @searpc_func("objlist", ["string", "int", "string"]) + def get_deleted(repo_id, show_days, path): pass # share repo to user diff --git a/python/seaserv/api.py b/python/seaserv/api.py index ea553e44..3dddb280 100644 --- a/python/seaserv/api.py +++ b/python/seaserv/api.py @@ -199,8 +199,8 @@ class SeafileAPI(object): def revert_dir(self, repo_id, commit_id, path, username): return seafserv_threaded_rpc.revert_dir(repo_id, commit_id, path, username) - def get_deleted(self, repo_id, show_days): - return seafserv_threaded_rpc.get_deleted(repo_id, show_days) + def get_deleted(self, repo_id, show_days, path='/'): + return seafserv_threaded_rpc.get_deleted(repo_id, show_days, path) # share repo to user def share_repo(self, repo_id, from_username, to_username, permission): diff --git a/server/repo-mgr.h b/server/repo-mgr.h index f0d65ba2..f8c1af58 100644 --- a/server/repo-mgr.h +++ b/server/repo-mgr.h @@ -486,6 +486,7 @@ GList * seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, const char *repo_id, int show_days, + const char *path, GError **error); /* diff --git a/server/repo-op.c b/server/repo-op.c index 4bf6cee8..e3ee463f 100644 --- a/server/repo-op.c +++ b/server/repo-op.c @@ -4610,37 +4610,17 @@ add_deleted_entry (SeafRepo *repo, static int find_deleted_recursive (SeafRepo *repo, - const char *root1, - const char *root2, + SeafDir *d1, + SeafDir *d2, const char *base, SeafCommit *child, SeafCommit *parent, GHashTable *entries) { - SeafDir *d1, *d2; GList *p1, *p2; SeafDirent *dent1, *dent2; int res, ret = 0; - if (strcmp (root1, root2) == 0) - return 0; - - d1 = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr, - repo->store_id, repo->version, - root1); - if (!d1) { - seaf_warning ("Failed to find dir %s.\n", root1); - return -1; - } - d2 = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr, - repo->store_id, repo->version, - root2); - if (!d2) { - seaf_warning ("Failed to find dir %s.\n", root2); - seaf_dir_free (d1); - return -1; - } - p1 = d1->entries; p2 = d2->entries; @@ -4665,12 +4645,33 @@ find_deleted_recursive (SeafRepo *repo, /* both exists but with diffent type. */ add_deleted_entry (repo, entries, dent2, base, child, parent); } else if (S_ISDIR(dent1->mode)) { + SeafDir *n1 = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr, + repo->id, + repo->version, + dent1->id); + if (!n1) { + seaf_warning ("Failed to find dir %s.\n", dent1->id); + return -1; + } + + SeafDir *n2 = seaf_fs_manager_get_seafdir_sorted (seaf->fs_mgr, + repo->id, + repo->version, + dent2->id); + if (!n2) { + seaf_warning ("Failed to find dir %s.\n", dent2->id); + seaf_dir_free (n1); + return -1; + } + char *new_base = g_strconcat (base, dent1->name, "/", NULL); - ret = find_deleted_recursive (repo, dent1->id, dent2->id, new_base, + ret = find_deleted_recursive (repo, n1, n2, new_base, child, parent, entries); g_free (new_base); + seaf_dir_free (n1); + seaf_dir_free (n2); if (ret < 0) - goto out; + return ret; } p1 = p1->next; p2 = p2->next; @@ -4684,9 +4685,40 @@ find_deleted_recursive (SeafRepo *repo, add_deleted_entry (repo, entries, dent2, base, child, parent); } -out: - seaf_dir_free (d1); - seaf_dir_free (d2); + return ret; +} + +static int +find_deleted (SeafRepo *repo, + SeafCommit *child, + SeafCommit *parent, + const char *base, + GHashTable *entries) +{ + SeafDir *d1, *d2; + int ret = 0; + + d1 = seaf_fs_manager_get_seafdir_sorted_by_path (seaf->fs_mgr, + repo->id, + repo->version, + child->root_id, base); + if (!d1) { + seaf_warning ("Failed to find dir %s on root %s.\n", base, child->root_id); + return -1; + } + + d2 = seaf_fs_manager_get_seafdir_sorted_by_path (seaf->fs_mgr, + repo->id, + repo->version, + parent->root_id, base); + if (!d2) { + seaf_warning ("Failed to find dir %s on root %s.\n", base, parent->root_id); + seaf_dir_free (d1); + return -1; + } + + ret = find_deleted_recursive (repo, d1, d2, base, child, parent, entries); + return ret; } @@ -4694,6 +4726,7 @@ typedef struct CollectDelData { SeafRepo *repo; GHashTable *entries; gint64 truncate_time; + char *path; } CollectDelData; #define DEFAULT_RECYCLE_DAYS 7 @@ -4734,8 +4767,7 @@ collect_deleted (SeafCommit *commit, void *vdata, gboolean *stop) return FALSE; } - if (find_deleted_recursive (data->repo, commit->root_id, p1->root_id, "/", - commit, p1, entries) < 0) { + if (find_deleted (data->repo, commit, p1, data->path, entries) < 0) { seaf_commit_unref (p1); return FALSE; } @@ -4752,8 +4784,7 @@ collect_deleted (SeafCommit *commit, void *vdata, gboolean *stop) return FALSE; } - if (find_deleted_recursive (data->repo, commit->root_id, p2->root_id, "/", - commit, p2, entries) < 0) { + if (find_deleted (data->repo, commit, p2, data->path, entries) < 0) { seaf_commit_unref (p2); return FALSE; } @@ -4838,6 +4869,7 @@ GList * seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, const char *repo_id, int show_days, + const char *path, GError **error) { SeafRepo *repo; @@ -4866,9 +4898,18 @@ seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, data.repo = repo; data.entries = entries; data.truncate_time = MAX (show_time, truncate_time); + if (path) { + if (path[strlen(path) - 1] == '/') { + data.path = g_strdup (path); + } else { + data.path = g_strconcat (path, "/", NULL); + } + } else { + data.path = g_strdup ("/"); + } if (!seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, - repo->id, repo->version, + repo->id, repo->version, repo->head->commit_id, collect_deleted, &data, @@ -4878,6 +4919,7 @@ seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, "Internal error"); g_hash_table_destroy (entries); seaf_repo_unref (repo); + g_free (data.path); return NULL; } @@ -4893,6 +4935,8 @@ seaf_repo_manager_get_deleted_entries (SeafRepoManager *mgr, g_hash_table_destroy (entries); seaf_repo_unref (repo); + g_free (data.path); + return ret; } diff --git a/server/seaf-server.c b/server/seaf-server.c index e4f4c5e6..eebfdea9 100644 --- a/server/seaf-server.c +++ b/server/seaf-server.c @@ -344,7 +344,7 @@ static void start_rpc_service (CcnetClient *client, int cloud_mode) searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_get_deleted, "get_deleted", - searpc_signature_objlist__string_int()); + searpc_signature_objlist__string_int_string()); /* share repo to user */ searpc_server_register_function ("seafserv-threaded-rpcserver",