Skip to content

Commit

Permalink
[client] Fix upload missing file bug and add sanity check for commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
killing committed Aug 11, 2015
1 parent 2c78a24 commit 4a7bb8b
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 12 deletions.
7 changes: 7 additions & 0 deletions common/index/index.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ static void alloc_index (struct index_state *istate)
istate->i_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
#endif
istate->added_ces = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
istate->initialized = 1;
istate->name_hash_initialized = 1;
}
Expand Down Expand Up @@ -1083,6 +1085,8 @@ int add_to_index(const char *repo_id,
*/
*added = TRUE;

g_hash_table_replace (istate->added_ces, g_strdup(path), ce);

return 0;
}

Expand Down Expand Up @@ -1175,6 +1179,8 @@ add_empty_dir_to_index (struct index_state *istate, const char *path, SeafStat *

ce->ce_flags |= CE_ADDED;

g_hash_table_replace (istate->added_ces, g_strdup(path), ce);

if (add_index_entry(istate, ce, add_option)) {
seaf_warning("unable to add %s to index\n",path);
free (ce);
Expand Down Expand Up @@ -2102,6 +2108,7 @@ int discard_index(struct index_state *istate)
#if defined WIN32 || defined __APPLE__
g_hash_table_destroy (istate->i_name_hash);
#endif
g_hash_table_destroy (istate->added_ces);
/* cache_tree_free(&(istate->cache_tree)); */
/* free(istate->alloc); */
free(istate->cache);
Expand Down
1 change: 1 addition & 0 deletions common/index/index.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ struct index_state {
#if defined WIN32 || defined __APPLE__
GHashTable *i_name_hash; /* ignore case */
#endif
GHashTable *added_ces;
int has_modifier;
};

Expand Down
87 changes: 87 additions & 0 deletions daemon/change-set.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,8 @@ commit_tree_recursive (const char *repo_id, ChangeSetDir *dir, gint64 *new_mtime

seaf_dir = changeset_dir_to_seaf_dir (dir);

memcpy (dir->dir_id, seaf_dir->dir_id, 40);

if (!seaf_fs_manager_object_exists (seaf->fs_mgr,
repo_id, dir->version,
seaf_dir->dir_id)) {
Expand Down Expand Up @@ -610,3 +612,88 @@ commit_tree_from_changeset (ChangeSet *changeset)

return root_id;
}

gboolean
changeset_check_path (ChangeSet *changeset,
const char *path,
unsigned char *sha1,
guint32 mode,
gint64 mtime)
{
char *repo_id = changeset->repo_id;
ChangeSetDir *root = changeset->tree_root;
char **parts, *dname;
int n, i;
ChangeSetDir *dir;
ChangeSetDirent *dent;
SeafDir *seaf_dir;
gboolean ret = FALSE;
char id[41];

rawdata_to_hex (sha1, id, 20);

parts = g_strsplit (path, "/", 0);
n = g_strv_length(parts);
dir = root;
for (i = 0; i < n; i++) {
dname = parts[i];

dent = g_hash_table_lookup (dir->dents, dname);
if (!dent) {
seaf_message ("Changeset mismatch: path component %s of %s not found\n",
dname, path);
break;
}

if (S_ISDIR(dent->mode)) {
if (i == (n-1)) {
if (dent->mode != mode) {
seaf_message ("Changeset mismatch: %s is not a dir\n", path);
break;
} else if (strcmp (dent->id, EMPTY_SHA1) != 0) {
seaf_message ("Changeset mismatch: %s is not a empty dir\n", path);
break;
}
ret = TRUE;
break;
}

if (!dent->subdir) {
seaf_message ("Changeset mismatch: path component %s of %s is not in changeset\n",
dname, path);
break;
}
dir = dent->subdir;
} else if (S_ISREG(dent->mode)) {
if (i == (n-1)) {
if (dent->mode != mode) {
seaf_message ("Changeset mismatch: %s mode mismatch, "
"index: %u, changeset: %u\n",
path, mode, dent->mode);
break;
} else if (dent->mtime != mtime) {
seaf_message ("Changeset mismatch: %s mtime mismatch, "
"index: %"G_GINT64_FORMAT
", changeset: %"G_GINT64_FORMAT"\n",
path, mtime, dent->mtime);
break;
} else if (strcmp (dent->id, id) != 0) {
seaf_message ("Changeset mismatch: %s id mismatch, "
"index: %s, changeset: %s\n",
path, id, dent->id);
break;
}
ret = TRUE;
break;
}

/* We find a file in the middle of the path, this is invalid. */
seaf_message ("Changeset mismatch: path component %s of %s is a file\n",
dname, path);
break;
}
}

g_strfreev (parts);
return ret;
}
7 changes: 7 additions & 0 deletions daemon/change-set.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ add_to_changeset (ChangeSet *changeset,
char *
commit_tree_from_changeset (ChangeSet *changeset);

gboolean
changeset_check_path (ChangeSet *changeset,
const char *path,
unsigned char *sha1,
guint32 mode,
gint64 mtime);

#endif
59 changes: 47 additions & 12 deletions daemon/repo-mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,16 @@ add_remain_files (SeafRepo *repo, struct index_state *istate,
add_to_index (repo->id, repo->version, istate, path, full_path,
&st, 0, crypt, index_cb, repo->email, &added);
if (added) {
ce = index_name_exists (istate, path, strlen(path), 0);
add_to_changeset (repo->changeset,
DIFF_STATUS_ADDED,
ce->sha1,
&st,
repo->email,
path,
NULL,
TRUE);

*total_size += (gint64)(st.st_size);
if (*total_size >= MAX_COMMIT_SIZE) {
g_free (path);
Expand All @@ -1987,18 +1997,6 @@ add_remain_files (SeafRepo *repo, struct index_state *istate,
S_IFREG,
SYNC_STATUS_SYNCED);
}

if (added) {
ce = index_name_exists (istate, path, strlen(path), 0);
add_to_changeset (repo->changeset,
DIFF_STATUS_ADDED,
ce->sha1,
&st,
repo->email,
path,
NULL,
TRUE);
}
} else if (S_ISDIR(st.st_mode)) {
if (is_empty_dir (full_path, ignore_list)) {
int rc = add_empty_dir_to_index (istate, path, &st);
Expand Down Expand Up @@ -3516,6 +3514,41 @@ need_handle_unmerged_index (SeafRepo *repo, struct index_state *istate)
return TRUE;
}

static void
check_ce_changeset (gpointer key, gpointer value, gpointer user_data)
{
ChangeSet *changeset = user_data;
struct cache_entry *ce = value;

changeset_check_path (changeset, ce->name,
ce->sha1, ce->ce_mode, ce->ce_mtime.sec);
}

static void
commit_sanity_check (SeafRepo *repo,
struct index_state *istate,
const char *new_root_id)
{
ChangeSet *changeset = repo->changeset;
SeafCommit *head = NULL;

head = seaf_commit_manager_get_commit (seaf->commit_mgr,
repo->id, repo->version,
repo->head->commit_id);
if (!head) {
seaf_warning ("Head commit %s for repo %s not found\n",
repo->head->commit_id, repo->id);
return;
}

if (strcmp (head->root_id, new_root_id) == 0) {
seaf_warning ("BUG: repo %s, new root id is the same as current root id %s\n",
repo->id, new_root_id);
}

g_hash_table_foreach (istate->added_ces, check_ce_changeset, changeset);
}

static int
print_index (struct index_state *istate)
{
Expand Down Expand Up @@ -3591,6 +3624,8 @@ seaf_repo_index_commit (SeafRepo *repo, const char *desc, gboolean is_force_comm
goto out;
}

commit_sanity_check (repo, &istate, root_id);

if (commit_tree (repo, root_id, my_desc, commit_id, unmerged) < 0) {
seaf_warning ("Failed to save commit file");
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "Internal error");
Expand Down

0 comments on commit 4a7bb8b

Please sign in to comment.