[client] Fix handling of removed folder on restart.

This commit is contained in:
Jiaqiang Xu 2015-08-24 14:24:25 +08:00
parent b90691302b
commit 1ba8c2841f
3 changed files with 124 additions and 81 deletions

View File

@ -439,7 +439,8 @@ add_to_tree (ChangeSet *changeset,
static ChangeSetDirent *
delete_from_tree (ChangeSet *changeset,
const char *path)
const char *path,
gboolean *parent_empty)
{
char *repo_id = changeset->repo_id;
ChangeSetDir *root = changeset->tree_root;
@ -449,6 +450,8 @@ delete_from_tree (ChangeSet *changeset,
ChangeSetDirent *dent, *ret = NULL;
SeafDir *seaf_dir;
*parent_empty = FALSE;
parts = g_strsplit (path, "/", 0);
n = g_strv_length(parts);
dir = root;
@ -463,6 +466,8 @@ delete_from_tree (ChangeSet *changeset,
if (i == (n-1)) {
/* Remove from hash table without freeing dent. */
remove_dent_from_dir (dir, dname);
if (g_hash_table_size (dir->dents) == 0)
*parent_empty = TRUE;
ret = dent;
break;
}
@ -485,6 +490,8 @@ delete_from_tree (ChangeSet *changeset,
if (i == (n-1)) {
/* Remove from hash table without freeing dent. */
remove_dent_from_dir (dir, dname);
if (g_hash_table_size (dir->dents) == 0)
*parent_empty = TRUE;
ret = dent;
break;
}
@ -507,6 +514,7 @@ apply_to_tree (ChangeSet *changeset,
char *repo_id = changeset->repo_id;
ChangeSetDir *root = changeset->tree_root;
ChangeSetDirent *dent, *dent_dst;
gboolean dummy;
switch (status) {
case DIFF_STATUS_ADDED:
@ -514,17 +522,12 @@ apply_to_tree (ChangeSet *changeset,
case DIFF_STATUS_DIR_ADDED:
add_to_tree (changeset, sha1, st, modifier, path, NULL);
break;
case DIFF_STATUS_DELETED:
case DIFF_STATUS_DIR_DELETED:
dent = delete_from_tree (changeset, path);
changeset_dirent_free (dent);
break;
case DIFF_STATUS_RENAMED:
dent = delete_from_tree (changeset, path);
dent = delete_from_tree (changeset, path, &dummy);
if (!dent)
break;
dent_dst = delete_from_tree (changeset, new_path);
dent_dst = delete_from_tree (changeset, new_path, &dummy);
changeset_dirent_free (dent_dst);
add_to_tree (changeset, NULL, NULL, NULL, new_path, dent);
@ -539,8 +542,54 @@ add_to_changeset (ChangeSet *changeset,
SeafStat *st,
const char *modifier,
const char *path,
const char *new_path,
gboolean add_to_diff)
const char *new_path)
{
DiffEntry *de;
unsigned char allzero[20] = {0};
de = diff_entry_new (DIFF_TYPE_INDEX, status, allzero, path);
changeset->diff = g_list_prepend (changeset->diff, de);
apply_to_tree (changeset,
status, sha1, st, modifier, path, new_path);
}
static void
remove_from_changeset_recursive (ChangeSet *changeset,
const char *path,
gboolean remove_parent,
const char *top_dir)
{
ChangeSetDirent *dent;
gboolean parent_empty = FALSE;
dent = delete_from_tree (changeset, path, &parent_empty);
changeset_dirent_free (dent);
if (remove_parent && parent_empty) {
char *parent = g_strdup(path);
char *slash = strrchr (parent, '/');
if (slash) {
*slash = '\0';
if (g_strcmp0 (top_dir, parent) != 0) {
/* Recursively remove parent dirs. */
remove_from_changeset_recursive (changeset,
parent,
remove_parent,
top_dir);
}
}
g_free (parent);
}
}
void
remove_from_changeset (ChangeSet *changeset,
char status,
const char *path,
gboolean remove_parent,
const char *top_dir,
gboolean add_to_diff)
{
DiffEntry *de;
unsigned char allzero[20] = {0};
@ -550,8 +599,7 @@ add_to_changeset (ChangeSet *changeset,
changeset->diff = g_list_prepend (changeset->diff, de);
}
apply_to_tree (changeset,
status, sha1, st, modifier, path, new_path);
remove_from_changeset_recursive (changeset, path, remove_parent, top_dir);
}
static char *

View File

@ -32,8 +32,18 @@ add_to_changeset (ChangeSet *changeset,
SeafStat *st,
const char *modifier,
const char *path,
const char *new_path,
gboolean add_to_diff);
const char *new_path);
/*
@remove_parent: remove the parent dir when it becomes empty.
*/
void
remove_from_changeset (ChangeSet *changeset,
char status,
const char *path,
gboolean remove_parent,
const char *top_dir,
gboolean add_to_diff);
char *
commit_tree_from_changeset (ChangeSet *changeset);

View File

@ -1090,8 +1090,7 @@ add_file (const char *repo_id,
st,
modifier,
path,
NULL,
TRUE);
NULL);
}
} else if (*remain_files == NULL) {
ret = add_to_index (repo_id, version, istate, path, full_path,
@ -1116,8 +1115,7 @@ add_file (const char *repo_id,
st,
modifier,
path,
NULL,
TRUE);
NULL);
}
} else
g_queue_push_tail (*remain_files, g_strdup(path));
@ -1275,8 +1273,7 @@ add_dir_recursive (const char *path, const char *full_path, SeafStat *st,
st,
NULL,
path,
NULL,
TRUE);
NULL);
}
} else
g_queue_push_tail (*(params->remain_files), g_strdup(path));
@ -1532,8 +1529,7 @@ add_dir_recursive (const char *path, const char *full_path, SeafStat *st,
st,
NULL,
path,
NULL,
TRUE);
NULL);
}
} else
g_queue_push_tail (*(params->remain_files), g_strdup(path));
@ -1725,14 +1721,16 @@ remove_deleted (struct index_state *istate, const char *worktree, const char *pr
/* Add to changeset only if dir is removed. */
ce->ce_flags |= CE_REMOVE;
if (changeset)
add_to_changeset (changeset,
DIFF_STATUS_DIR_DELETED,
NULL,
NULL,
NULL,
ce->name,
NULL,
TRUE);
/* Remove the parent dir from change set if it becomes
* empty. If in the work tree the empty dir still exist,
* we'll add it back to changeset in add_recursive() later.
*/
remove_from_changeset (changeset,
DIFF_STATUS_DIR_DELETED,
ce->name,
TRUE,
prefix,
TRUE);
} else if (!is_empty_dir (path, ignore_list)) {
/* Don't add to changeset if empty dir became non-empty. */
ce->ce_flags |= CE_REMOVE;
@ -1749,14 +1747,12 @@ remove_deleted (struct index_state *istate, const char *worktree, const char *pr
{
ce_array[i]->ce_flags |= CE_REMOVE;
if (changeset)
add_to_changeset (changeset,
DIFF_STATUS_DELETED,
NULL,
NULL,
NULL,
ce->name,
NULL,
TRUE);
remove_from_changeset (changeset,
DIFF_STATUS_DELETED,
ce->name,
TRUE,
prefix,
TRUE);
}
}
}
@ -1999,8 +1995,7 @@ add_remain_files (SeafRepo *repo, struct index_state *istate,
&st,
repo->email,
path,
NULL,
TRUE);
NULL);
*total_size += (gint64)(st.st_size);
if (*total_size >= MAX_COMMIT_SIZE) {
@ -2026,8 +2021,7 @@ add_remain_files (SeafRepo *repo, struct index_state *istate,
&st,
NULL,
path,
NULL,
TRUE);
NULL);
}
}
}
@ -2158,8 +2152,7 @@ update_attributes (SeafRepo *repo,
&st,
repo->email,
path,
NULL,
TRUE);
NULL);
}
g_free (full_path);
}
@ -2181,7 +2174,6 @@ scan_subtree_for_deletion (const char *repo_id,
wchar_t *p;
char *dir = NULL;
char *p2;
gboolean convertion_failed = FALSE;
/* In most file systems, like NTFS, 8.3 format path should contain ~.
* Also note that *~ files are ignored.
@ -2205,8 +2197,6 @@ scan_subtree_for_deletion (const char *repo_id,
dir_w = win32_83_path_to_long_path (worktree, path_w, wcslen(path_w));
if (dir_w)
break;
else
convertion_failed = TRUE;
}
if (!dir_w)
@ -2253,22 +2243,22 @@ scan_subtree_for_deletion (const char *repo_id,
* This can be fixed by removing the accurate deleted path. In most cases,
* basename doesn't contain ~, so we can always get the accurate path.
*/
if (!convertion_failed) {
char *basename = strrchr (path, '/');
char *deleted_path = NULL;
if (basename) {
deleted_path = g_build_path ("/", dir, basename, NULL);
add_to_changeset (changeset,
DIFF_STATUS_DELETED,
NULL,
NULL,
NULL,
deleted_path,
NULL,
FALSE);
g_free (deleted_path);
}
}
/* if (!convertion_failed) { */
/* char *basename = strrchr (path, '/'); */
/* char *deleted_path = NULL; */
/* if (basename) { */
/* deleted_path = g_build_path ("/", dir, basename, NULL); */
/* add_to_changeset (changeset, */
/* DIFF_STATUS_DELETED, */
/* NULL, */
/* NULL, */
/* NULL, */
/* deleted_path, */
/* NULL, */
/* FALSE); */
/* g_free (deleted_path); */
/* } */
/* } */
out:
g_free (path_w);
@ -2899,14 +2889,12 @@ handle_rename (SeafRepo *repo, struct index_state *istate,
scanned_del_dirs,
repo->changeset);
add_to_changeset (repo->changeset,
DIFF_STATUS_DELETED,
NULL,
NULL,
NULL,
event->path,
NULL,
FALSE);
remove_from_changeset (repo->changeset,
DIFF_STATUS_DELETED,
event->path,
FALSE,
NULL,
FALSE);
}
return;
}
@ -2938,8 +2926,7 @@ handle_rename (SeafRepo *repo, struct index_state *istate,
NULL,
NULL,
event->path,
event->new_path,
TRUE);
event->new_path);
}
AddOptions options;
@ -3068,14 +3055,12 @@ apply_worktree_changes_to_index (SeafRepo *repo, struct index_state *istate,
&scanned_del_dirs,
repo->changeset);
add_to_changeset (repo->changeset,
DIFF_STATUS_DELETED,
NULL,
NULL,
NULL,
event->path,
NULL,
TRUE);
remove_from_changeset (repo->changeset,
DIFF_STATUS_DELETED,
event->path,
FALSE,
NULL,
TRUE);
try_add_empty_parent_dir_entry_from_wt (repo->worktree,
istate,