[client] Fix case rename bug and remove ignored hidden files when delete empty dir.

This commit is contained in:
Jiaqiang Xu 2014-11-13 14:06:37 +08:00
parent e79c7f092a
commit 2c4a44c67d
10 changed files with 574 additions and 131 deletions

View File

@ -684,7 +684,8 @@ diff_resolve_renames (GList **diff_entries)
/* Collect all "deleted" entries. */
for (p = *diff_entries; p != NULL; p = p->next) {
de = p->data;
if (de->status == DIFF_STATUS_DELETED &&
if ((de->status == DIFF_STATUS_DELETED ||
de->status == DIFF_STATUS_DIR_DELETED) &&
memcmp (de->sha1, empty_sha1, 20) != 0)
g_hash_table_insert (deleted, de->sha1, p);
}
@ -692,7 +693,8 @@ diff_resolve_renames (GList **diff_entries)
/* Collect all "added" entries into a separate list. */
for (p = *diff_entries; p != NULL; p = p->next) {
de = p->data;
if (de->status == DIFF_STATUS_ADDED &&
if ((de->status == DIFF_STATUS_ADDED ||
de->status == DIFF_STATUS_DIR_ADDED) &&
memcmp (de->sha1, empty_sha1, 20) != 0)
added = g_list_prepend (added, p);
}
@ -704,6 +706,7 @@ diff_resolve_renames (GList **diff_entries)
while (p != NULL) {
GList *p_add, *p_del;
DiffEntry *de_add, *de_del, *de_rename;
int rename_status;
p_add = p->data;
de_add = p_add->data;
@ -711,7 +714,13 @@ diff_resolve_renames (GList **diff_entries)
p_del = g_hash_table_lookup (deleted, de_add->sha1);
if (p_del) {
de_del = p_del->data;
de_rename = diff_entry_new (de_del->type, DIFF_STATUS_RENAMED,
if (de_add->status == DIFF_STATUS_DIR_ADDED)
rename_status = DIFF_STATUS_DIR_RENAMED;
else
rename_status = DIFF_STATUS_RENAMED;
de_rename = diff_entry_new (de_del->type, rename_status,
de_del->sha1, de_del->name);
de_rename->new_name = g_strdup(de_add->name);

View File

@ -18,6 +18,7 @@
#define DIFF_STATUS_UNMERGED 'U'
#define DIFF_STATUS_DIR_ADDED 'B'
#define DIFF_STATUS_DIR_DELETED 'C'
#define DIFF_STATUS_DIR_RENAMED 'E'
enum {
STATUS_UNMERGED_NONE,

View File

@ -1890,6 +1890,85 @@ seaf_fs_manager_traverse_tree (SeafFSManager *mgr,
return traverse_dir (mgr, repo_id, version, root_id, callback, user_data, skip_errors);
}
static int
traverse_dir_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *dir_path,
SeafDirent *dent,
TraverseFSPathCallback callback,
void *user_data)
{
SeafDir *dir;
GList *p;
SeafDirent *seaf_dent;
gboolean stop = FALSE;
char *sub_path;
int ret = 0;
if (!callback (mgr, dir_path, dent, user_data, &stop))
return -1;
if (stop)
return 0;
dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, dent->id);
if (!dir) {
seaf_warning ("get seafdir %s failed\n", dent->id);
return -1;
}
for (p = dir->entries; p; p = p->next) {
seaf_dent = (SeafDirent *)p->data;
sub_path = g_strconcat (dir_path, "/", seaf_dent->name, NULL);
if (S_ISREG(seaf_dent->mode)) {
if (!callback (mgr, sub_path, seaf_dent, user_data, &stop)) {
g_free (sub_path);
ret = -1;
break;
}
} else if (S_ISDIR(seaf_dent->mode)) {
if (traverse_dir_path (mgr, repo_id, version, sub_path, seaf_dent,
callback, user_data) < 0) {
g_free (sub_path);
ret = -1;
break;
}
}
g_free (sub_path);
}
seaf_dir_free (dir);
return ret;
}
int
seaf_fs_manager_traverse_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *root_id,
const char *dir_path,
TraverseFSPathCallback callback,
void *user_data)
{
SeafDirent *dent;
int ret = 0;
dent = seaf_fs_manager_get_dirent_by_path (mgr, repo_id, version,
root_id, dir_path);
if (!dent) {
seaf_warning ("Failed to get dirent for %.8s:%s.\n", repo_id, dir_path);
return -1;
}
ret = traverse_dir_path (mgr, repo_id, version, dir_path, dent,
callback, user_data);
seaf_dirent_free (dent);
return ret;
}
static gboolean
fill_blocklist (SeafFSManager *mgr,
const char *repo_id, int version,
@ -2247,6 +2326,48 @@ seaf_fs_manager_get_seafdir_id_by_path (SeafFSManager *mgr,
return dir_id;
}
SeafDirent *
seaf_fs_manager_get_dirent_by_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *root_id,
const char *path)
{
SeafDirent *dent = NULL;
SeafDir *dir = NULL;
char *parent_dir = NULL;
char *file_name = NULL;
parent_dir = g_path_get_dirname(path);
file_name = g_path_get_basename(path);
if (strcmp (parent_dir, ".") == 0)
dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, root_id);
else
dir = seaf_fs_manager_get_seafdir_by_path (mgr, repo_id, version,
root_id, parent_dir, NULL);
if (!dir) {
seaf_warning ("dir %s doesn't exist in repo %.8s.\n", parent_dir, repo_id);
goto out;
}
GList *p;
for (p = dir->entries; p; p = p->next) {
SeafDirent *d = p->data;
if (strcmp (d->name, file_name) == 0) {
dent = seaf_dirent_dup(d);
break;
}
}
out:
if (dir)
seaf_dir_free (dir);
return dent;
}
static gboolean
verify_seafdir_v0 (const char *dir_id, const uint8_t *data, int len,
gboolean verify_id)

View File

@ -253,6 +253,21 @@ seaf_fs_manager_traverse_tree (SeafFSManager *mgr,
void *user_data,
gboolean skip_errors);
typedef gboolean (*TraverseFSPathCallback) (SeafFSManager *mgr,
const char *path,
SeafDirent *dent,
void *user_data,
gboolean *stop);
int
seaf_fs_manager_traverse_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *root_id,
const char *dir_path,
TraverseFSPathCallback callback,
void *user_data);
gboolean
seaf_fs_manager_object_exists (SeafFSManager *mgr,
const char *repo_id,
@ -326,6 +341,13 @@ seaf_fs_manager_get_seafdir_id_by_path (SeafFSManager *mgr,
const char *path,
GError **error);
SeafDirent *
seaf_fs_manager_get_dirent_by_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *root_id,
const char *path);
/* Check object integrity. */
gboolean

View File

@ -314,6 +314,19 @@ seaf_repo_unset_readonly (SeafRepo *repo)
save_repo_property (repo->manager, repo->id, REPO_PROP_IS_READONLY, "false");
}
gboolean
seaf_repo_manager_is_ignored_hidden_file (const char *filename)
{
GPatternSpec **spec = ignore_patterns;
while (*spec) {
if (g_pattern_match_string(*spec, filename))
return TRUE;
spec++;
}
return FALSE;
}
static inline gboolean
has_trailing_space_or_period (const char *path)
@ -1758,7 +1771,8 @@ checkout_file (const char *repo_id,
#ifndef __linux__
path = build_case_conflict_free_path (worktree, name,
conflict_hash, no_conflict_hash,
&case_conflict);
&case_conflict,
FALSE);
#else
path = build_checkout_path (worktree, name, strlen(name));
#endif
@ -1900,7 +1914,8 @@ checkout_empty_dir (const char *worktree,
#ifndef __linux__
path = build_case_conflict_free_path (worktree, name,
conflict_hash, no_conflict_hash,
&case_conflict);
&case_conflict,
FALSE);
#else
path = build_checkout_path (worktree, name, strlen(name));
#endif
@ -1974,6 +1989,114 @@ cleanup_file_blocks (const char *repo_id, int version, const char *file_id)
seafile_unref (file);
}
static gboolean
expand_dir_added_cb (SeafFSManager *mgr,
const char *path,
SeafDirent *dent,
void *user_data,
gboolean *stop)
{
GList **expanded = user_data;
DiffEntry *de = NULL;
unsigned char sha1[20];
hex_to_rawdata (dent->id, sha1, 20);
if (S_ISDIR(dent->mode) && strcmp(dent->id, EMPTY_SHA1) == 0)
de = diff_entry_new (DIFF_TYPE_COMMITS, DIFF_STATUS_DIR_ADDED, sha1, path);
else if (S_ISREG(dent->mode))
de = diff_entry_new (DIFF_TYPE_COMMITS, DIFF_STATUS_ADDED, sha1, path);
if (de) {
de->mtime = dent->mtime;
de->mode = dent->mode;
de->modifier = g_strdup(dent->modifier);
de->size = dent->size;
*expanded = g_list_prepend (*expanded, de);
}
return TRUE;
}
/*
* Expand DIR_ADDED results into multiple ADDED results.
*/
static int
expand_diff_results (const char *repo_id, int version,
const char *remote_root, const char *local_root,
GList **results)
{
GList *ptr, *next;
DiffEntry *de;
char obj_id[41];
GList *expanded = NULL;
ptr = *results;
while (ptr) {
de = ptr->data;
next = ptr->next;
if (de->status == DIFF_STATUS_DIR_ADDED) {
*results = g_list_delete_link (*results, ptr);
rawdata_to_hex (de->sha1, obj_id, 20);
if (seaf_fs_manager_traverse_path (seaf->fs_mgr,
repo_id, version,
remote_root,
de->name,
expand_dir_added_cb,
&expanded) < 0)
goto error;
}
ptr = next;
}
expanded = g_list_reverse (expanded);
*results = g_list_concat (*results, expanded);
return 0;
error:
for (ptr = expanded; ptr; ptr = ptr->next)
diff_entry_free ((DiffEntry *)(ptr->data));
return -1;
}
static int
do_rename_in_worktree (DiffEntry *de, const char *worktree,
GHashTable *conflict_hash, GHashTable *no_conflict_hash)
{
char *old_path, *new_path;
gboolean case_conflict;
int ret = 0;
old_path = g_build_filename (worktree, de->name, NULL);
if (g_file_test (old_path, G_FILE_TEST_EXISTS)) {
#ifndef __linux__
new_path = build_case_conflict_free_path (worktree, de->new_name,
conflict_hash, no_conflict_hash,
&case_conflict,
TRUE);
#else
new_path = build_checkout_path (worktree, de->new_name, strlen(de->new_name));
#endif
if (g_rename (old_path, new_path) < 0) {
seaf_warning ("Failed to rename %s to %s: %s.\n",
old_path, new_path, strerror(errno));
ret = -1;
}
g_free (new_path);
}
g_free (old_path);
return ret;
}
#define UPDATE_CACHE_SIZE_LIMIT 100 * (1 << 20) /* 100MB */
int
@ -2047,7 +2170,7 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
if (diff_commit_roots (task->repo_id, task->repo_version,
master_head ? master_head->root_id : EMPTY_SHA1,
remote_head->root_id,
&results, FALSE) < 0) {
&results, TRUE) < 0) {
seaf_warning ("Failed to diff for repo %.8s.\n", task->repo_id);
ret = FETCH_CHECKOUT_FAILED;
goto out;
@ -2056,10 +2179,26 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
GList *ptr;
DiffEntry *de;
/* Expand DIR_ADDED diff entries. */
if (expand_diff_results (task->repo_id, task->repo_version,
remote_head->root_id,
master_head ? master_head->root_id : EMPTY_SHA1,
&results) < 0) {
ret = FETCH_CHECKOUT_FAILED;
goto out;
}
#ifdef WIN32
for (ptr = results; ptr; ptr = ptr->next) {
de = ptr->data;
if (do_check_file_locked (de->name, worktree)) {
if (de->status == DIFF_STATUS_DIR_RENAMED) {
if (do_check_dir_locked (de->name, worktree)) {
seaf_message ("File(s) in dir %s are locked by other program, "
"skip checkout.\n", de->name);
ret = FETCH_CHECKOUT_FAILED;
goto out;
}
} else if (do_check_file_locked (de->name, worktree)) {
seaf_message ("File %s is locked by other program, skip checkout.\n",
de->name);
ret = FETCH_CHECKOUT_FAILED;
@ -2099,13 +2238,10 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
++(task->n_to_download);
}
/* Delete/rename files before deleting dirs,
* because we can't delete non-empty dirs.
*/
for (ptr = results; ptr; ptr = ptr->next) {
de = ptr->data;
if (de->status == DIFF_STATUS_DELETED) {
seaf_debug ("Delete %s.\n", de->name);
seaf_debug ("Delete file %s.\n", de->name);
ce = index_name_exists (&istate, de->name, strlen(de->name), 0);
if (!ce)
@ -2115,33 +2251,28 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
remove_from_index_with_prefix (&istate, de->name);
try_add_empty_parent_dir_entry (worktree, &istate, ignore_list, de->name);
} else if (de->status == DIFF_STATUS_DIR_DELETED) {
seaf_debug ("Delete dir %s.\n", de->name);
/* Nothing to delete. */
if (!master_head || strcmp(master_head->root_id, EMPTY_SHA1) == 0)
continue;
delete_dir_with_check (task->repo_id, task->repo_version,
master_head->root_id, de->name,
worktree, &istate);
try_add_empty_parent_dir_entry (worktree, &istate, ignore_list, de->name);
}
}
for (ptr = results; ptr; ptr = ptr->next) {
de = ptr->data;
if (de->status == DIFF_STATUS_RENAMED) {
if (de->status == DIFF_STATUS_RENAMED ||
de->status == DIFF_STATUS_DIR_RENAMED) {
seaf_debug ("Rename %s to %s.\n", de->name, de->new_name);
char *old_path = g_build_filename (worktree, de->name, NULL);
char *new_path;
gboolean case_conflict;
#ifndef __linux__
new_path = build_case_conflict_free_path (worktree, de->new_name,
conflict_hash, no_conflict_hash,
&case_conflict);
#else
new_path = build_checkout_path (worktree, de->new_name, strlen(de->new_name));
#endif
if (g_file_test (old_path, G_FILE_TEST_EXISTS) &&
g_rename (old_path, new_path) < 0)
seaf_warning ("Failed to rename %s to %s: %s.\n",
old_path, new_path, strerror(errno));
g_free (old_path);
g_free (new_path);
do_rename_in_worktree (de, worktree, conflict_hash, no_conflict_hash);
rename_index_entries (&istate, de->name, de->new_name);
@ -2150,22 +2281,6 @@ seaf_repo_fetch_and_checkout (TransferTask *task,
}
}
for (ptr = results; ptr; ptr = ptr->next) {
de = ptr->data;
if (de->status == DIFF_STATUS_DIR_DELETED) {
seaf_debug ("Delete %s.\n", de->name);
ce = index_name_exists (&istate, de->name, strlen(de->name), 0);
if (!ce)
continue;
delete_path (worktree, de->name, de->mode, ce->ce_mtime.sec);
remove_from_index_with_prefix (&istate, de->name);
try_add_empty_parent_dir_entry (worktree, &istate, ignore_list, de->name);
}
}
if (istate.cache_changed)
update_index (&istate, index_path);

View File

@ -415,4 +415,7 @@ int
seaf_repo_fetch_and_checkout (struct _TransferTask *task,
const char *remote_head_id);
gboolean
seaf_repo_manager_is_ignored_hidden_file (const char *filename);
#endif

View File

@ -16,6 +16,7 @@
#include "merge.h"
#include "vc-utils.h"
#include "vc-common.h"
#include "index/index.h"
static gint
compare_dirents (gconstpointer a, gconstpointer b)
@ -170,21 +171,36 @@ int
seaf_remove_empty_dir (const char *path)
{
SeafStat st;
char *ds_store, *thumbs_db;
GDir *dir;
const char *dname;
char *full_path;
GError *error = NULL;
if (seaf_stat (path, &st) < 0 || !S_ISDIR(st.st_mode))
return 0;
if (g_rmdir (path) < 0) {
ds_store = g_build_filename (path, ".DS_Store", NULL);
g_unlink (ds_store);
g_free (ds_store);
dir = g_dir_open (path, 0, &error);
if (!dir) {
seaf_warning ("Failed to open dir %s: %s.\n", path, error->message);
return -1;
}
thumbs_db = g_build_filename (path, "Thumbs.db", NULL);
g_unlink (thumbs_db);
g_free (thumbs_db);
/* Remove all ignored hidden files. */
while ((dname = g_dir_read_name (dir)) != NULL) {
if (seaf_repo_manager_is_ignored_hidden_file(dname)) {
full_path = g_build_path ("/", path, dname, NULL);
if (g_unlink (full_path) < 0)
seaf_warning ("Failed to remove file %s: %s.\n",
full_path, strerror(errno));
g_free (full_path);
}
}
g_dir_close (dir);
if (g_rmdir (path) < 0) {
seaf_warning ("Failed to remove dir %s: %s.\n", path, strerror(errno));
return -1;
}
}
@ -314,7 +330,8 @@ case_conflict_utf8 (const char *name1, const char *name2)
}
static gboolean
case_conflict_exists (const char *dir_path, const char *new_dname)
case_conflict_exists (const char *dir_path, const char *new_dname,
char **conflict_dname)
{
GDir *dir;
const char *dname;
@ -337,13 +354,14 @@ case_conflict_exists (const char *dir_path, const char *new_dname)
char *norm_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC);
if (case_conflict_utf8 (norm_dname, new_dname)) {
is_case_conflict = TRUE;
g_free (norm_dname);
*conflict_dname = norm_dname;
break;
}
g_free (norm_dname);
#else
if (case_conflict_utf8 (dname, new_dname)) {
is_case_conflict = TRUE;
*conflict_dname = g_strdup(dname);
break;
}
#endif
@ -406,17 +424,19 @@ build_case_conflict_free_path (const char *worktree,
const char *ce_name,
GHashTable *conflict_hash,
GHashTable *no_conflict_hash,
gboolean *is_case_conflict)
gboolean *is_case_conflict,
gboolean is_rename)
{
GString *buf = g_string_new (worktree);
char **components, *ptr;
guint i, n_comps;
static int dummy;
char *conflict_dname = NULL;
components = g_strsplit (ce_name, "/", -1);
n_comps = g_strv_length (components);
for (i = 0; i < n_comps; ++i) {
char *path = NULL, *dname = NULL, *case_conflict_free_path = NULL;
char *path = NULL, *dname = NULL;
SeafStat st;
ptr = components[i];
@ -453,7 +473,7 @@ build_case_conflict_free_path (const char *worktree,
}
/* No luck in the hash tables, we have to run case conflict detection. */
if (!case_conflict_exists (buf->str, ptr)) {
if (!case_conflict_exists (buf->str, ptr, &conflict_dname)) {
/* No case conflict. */
if (i != n_comps - 1)
g_hash_table_insert (no_conflict_hash,
@ -470,26 +490,50 @@ build_case_conflict_free_path (const char *worktree,
* remember it in the hash table.
*/
dname = gen_case_conflict_free_dname (buf->str, ptr);
if (!is_rename) {
dname = gen_case_conflict_free_dname (buf->str, ptr);
case_conflict_free_path = g_build_path ("/", buf->str, dname, NULL);
if (i != n_comps - 1) {
if (g_mkdir (case_conflict_free_path, 0777) < 0) {
seaf_warning ("Failed to create dir %s.\n", case_conflict_free_path);
char *case_conflict_free_path = g_build_path ("/", buf->str, dname, NULL);
if (i != n_comps - 1) {
if (g_mkdir (case_conflict_free_path, 0777) < 0) {
seaf_warning ("Failed to create dir %s.\n",
case_conflict_free_path);
g_free (path);
g_free (dname);
g_free (case_conflict_free_path);
goto error;
}
g_hash_table_insert (conflict_hash, g_strdup(path), g_strdup(dname));
}
g_string_append_printf (buf, "/%s", dname);
g_free (dname);
g_free (case_conflict_free_path);
} else {
char *src_path = g_build_path ("/", buf->str, conflict_dname, NULL);
if (i != (n_comps - 1) && g_rename (src_path, path) < 0) {
seaf_warning ("Failed to rename %s to %s: %s.\n",
src_path, path, strerror(errno));
g_free (path);
g_free (dname);
g_free (case_conflict_free_path);
g_free (src_path);
goto error;
}
g_hash_table_insert (conflict_hash, g_strdup(path), g_strdup(dname));
/* Since the exsiting dir in the worktree has been renamed,
* there is no more case conflict.
*/
g_hash_table_insert (no_conflict_hash, g_strdup(path), &dummy);
g_string_append_printf (buf, "/%s", ptr);
g_free (src_path);
}
g_string_append_printf (buf, "/%s", dname);
g_free (conflict_dname);
g_free (path);
g_free (dname);
g_free (case_conflict_free_path);
}
g_strfreev (components);
@ -565,7 +609,8 @@ checkout_entry (struct cache_entry *ce,
#ifndef __linux__
path = build_case_conflict_free_path (o->base, ce->name,
conflict_hash, no_conflict_hash,
&case_conflict);
&case_conflict,
FALSE);
#else
path = build_checkout_path (o->base, ce->name, ce_namelen(ce));
#endif
@ -763,18 +808,106 @@ delete_path (const char *worktree, const char *name,
return 0;
}
static int
delete_dir_recursive (const char *repo_id,
int repo_version,
const char *dir_path,
SeafDir *dir,
const char *worktree,
struct index_state *istate)
{
GList *ptr;
SeafDirent *dent;
char *sub_path;
SeafDir *sub_dir;
for (ptr = dir->entries; ptr; ptr = ptr->next) {
dent = ptr->data;
sub_path = g_strconcat (dir_path, "/", dent->name, NULL);
if (S_ISDIR(dent->mode)) {
if (strcmp(dent->id, EMPTY_SHA1) == 0) {
delete_path (worktree, sub_path, dent->mode, 0);
} else {
sub_dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr,
repo_id, repo_version,
dent->id);
if (!sub_dir) {
seaf_warning ("Failed to find dir %s in repo %.8s.\n",
sub_path, repo_id);
g_free (sub_path);
return -1;
}
if (delete_dir_recursive (repo_id, repo_version,
sub_path, sub_dir,
worktree, istate) < 0) {
g_free (sub_path);
return -1;
}
seaf_dir_free (sub_dir);
}
} else if (S_ISREG(dent->mode)) {
struct cache_entry *ce;
ce = index_name_exists (istate, sub_path, strlen(sub_path), 0);
if (ce) {
delete_path (worktree, sub_path, dent->mode, ce->ce_mtime.sec);
}
}
g_free (sub_path);
}
char *full_path = g_build_filename (worktree, dir_path, NULL);
if (seaf_remove_empty_dir (full_path) < 0) {
g_warning ("Failed to remove dir %s: %s.\n", full_path, strerror(errno));
return -1;
}
return 0;
}
int
delete_dir_with_check (const char *repo_id,
int repo_version,
const char *root_id,
const char *dir_path,
const char *worktree,
struct index_state *istate)
{
SeafDir *dir;
int ret;
dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr,
repo_id, repo_version,
root_id, dir_path, NULL);
if (!dir) {
seaf_warning ("Failed to find dir %s in repo %.8s.\n", dir_path, repo_id);
return -1;
}
ret = delete_dir_recursive (repo_id, repo_version, dir_path,
dir, worktree, istate);
seaf_dir_free (dir);
/* Remove all index entries under this directory */
remove_from_index_with_prefix (istate, dir_path);
return ret;
}
#ifdef WIN32
gboolean
do_check_file_locked (const char *path, const char *worktree)
static gboolean
check_file_locked (const char *path)
{
char *real_path;
HANDLE handle;
wchar_t *path_w;
real_path = g_build_path(PATH_SEPERATOR, worktree, path, NULL);
path_w = wchar_from_utf8 (real_path);
g_free (real_path);
path_w = wchar_from_utf8 (path);
handle = CreateFileW (path_w,
GENERIC_WRITE,
@ -793,6 +926,73 @@ do_check_file_locked (const char *path, const char *worktree)
return FALSE;
}
gboolean
do_check_file_locked (const char *path, const char *worktree)
{
char *real_path;
gboolean ret;
real_path = g_build_path(PATH_SEPERATOR, worktree, path, NULL);
ret = check_file_locked (real_path);
g_free (real_path);
return ret;
}
static gboolean
check_dir_locked_recursive (const char *path)
{
GDir *dir;
const char *dname;
char *sub_path;
SeafStat st;
GError *error = NULL;
gboolean ret = FALSE;
dir = g_dir_open (path, 0, &error);
if (!dir) {
seaf_warning ("Failed to open dir %s: %s.\n", path, error->message);
return TRUE;
}
while ((dname = g_dir_read_name (dir)) != NULL) {
sub_path = g_build_path (PATH_SEPERATOR, path, dname, NULL);
if (seaf_stat (sub_path, &st) < 0) {
seaf_warning ("Failed to stat %s: %s.\n", sub_path, strerror(errno));
g_free (sub_path);
ret = TRUE;
break;
}
if (S_ISDIR(st.st_mode)) {
if (check_dir_locked_recursive (sub_path)) {
g_free (sub_path);
ret = TRUE;
break;
}
} else if (S_ISREG(st.st_mode)) {
if (check_file_locked (sub_path)) {
g_free (sub_path);
ret = TRUE;
break;
}
}
g_free (sub_path);
}
g_dir_close (dir);
return ret;
}
gboolean
do_check_dir_locked (const char *path, const char *worktree)
{
char *real_path = g_build_path (PATH_SEPERATOR, worktree, path, NULL);
gboolean ret = check_dir_locked_recursive (real_path);
g_free (real_path);
return ret;
}
gboolean
files_locked_on_windows (struct index_state *index, const char *worktree)
{

View File

@ -43,7 +43,8 @@ build_case_conflict_free_path (const char *worktree,
const char *ce_name,
GHashTable *conflict_hash,
GHashTable *no_conflict_hash,
gboolean *is_case_conflict);
gboolean *is_case_conflict,
gboolean is_rename);
char *
build_checkout_path (const char *worktree, const char *ce_name, int len);
@ -52,9 +53,22 @@ int
delete_path (const char *worktree, const char *name,
unsigned int mode, gint64 old_mtime);
struct index_state;
int
delete_dir_with_check (const char *repo_id,
int repo_version,
const char *root_id,
const char *dir_path,
const char *worktree,
struct index_state *istate);
gboolean
do_check_file_locked (const char *path, const char *worktree);
gboolean
do_check_dir_locked (const char *path, const char *worktree);
gboolean
files_locked_on_windows (struct index_state *index, const char *worktree);

View File

@ -112,11 +112,11 @@ static int getattr_repo(SeafileSession *seaf,
if (strcmp (repo_path, "/") != 0) {
// get dirent of the dir
SeafDirent *dirent = fuse_get_dirent_by_path (seaf->fs_mgr,
repo->store_id,
repo->version,
commit->root_id,
repo_path);
SeafDirent *dirent = seaf_fs_manager_get_dirent_by_path (seaf->fs_mgr,
repo->store_id,
repo->version,
commit->root_id,
repo_path);
if (dirent && repo->version != 0)
stbuf->st_mtime = dirent->mtime;
@ -136,11 +136,11 @@ static int getattr_repo(SeafileSession *seaf,
if (file)
stbuf->st_size = file->file_size;
SeafDirent *dirent = fuse_get_dirent_by_path (seaf->fs_mgr,
repo->store_id,
repo->version,
commit->root_id,
repo_path);
SeafDirent *dirent = seaf_fs_manager_get_dirent_by_path (seaf->fs_mgr,
repo->store_id,
repo->version,
commit->root_id,
repo_path);
if (dirent && repo->version != 0)
stbuf->st_mtime = dirent->mtime;

View File

@ -83,48 +83,6 @@ int parse_fuse_path (const char *path,
return ret;
}
SeafDirent *
fuse_get_dirent_by_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *root_id,
const char *path)
{
SeafDirent *dent = NULL;
SeafDir *dir = NULL;
char *parent_dir = NULL;
char *file_name = NULL;
parent_dir = g_path_get_dirname(path);
file_name = g_path_get_basename(path);
if (strcmp (parent_dir, ".") == 0)
dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, root_id);
else
dir = seaf_fs_manager_get_seafdir_by_path (mgr, repo_id, version,
root_id, parent_dir, NULL);
if (!dir) {
seaf_warning ("dir %s doesn't exist in repo %.8s.\n", parent_dir, repo_id);
goto out;
}
GList *p;
for (p = dir->entries; p; p = p->next) {
SeafDirent *d = p->data;
if (strcmp (d->name, file_name) == 0) {
dent = seaf_dirent_dup(d);
break;
}
}
out:
if (dir)
seaf_dir_free (dir);
return dent;
}
static int seaf_fuse_getattr(const char *path, struct stat *stbuf)
{
memset(stbuf, 0, sizeof(struct stat));