mirror of
https://github.com/haiwen/seafile.git
synced 2025-01-09 04:17:30 +08:00
Use JSON for fs object format and store modifier, size, mtime in direcotry objects.
This commit is contained in:
parent
bf51101235
commit
2983357dfb
766
common/fs-mgr.c
766
common/fs-mgr.c
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,30 @@
|
||||
#include "cdc/cdc.h"
|
||||
#include "../common/seafile-crypt.h"
|
||||
|
||||
#define CURRENT_DIR_OBJ_VERSION 1
|
||||
#define CURRENT_SEAFILE_OBJ_VERSION 1
|
||||
|
||||
typedef struct _SeafFSManager SeafFSManager;
|
||||
typedef struct _SeafFSObject SeafFSObject;
|
||||
typedef struct _Seafile Seafile;
|
||||
typedef struct _SeafDir SeafDir;
|
||||
typedef struct _SeafDirent SeafDirent;
|
||||
|
||||
typedef enum {
|
||||
SEAF_METADATA_TYPE_INVALID,
|
||||
SEAF_METADATA_TYPE_FILE,
|
||||
SEAF_METADATA_TYPE_LINK,
|
||||
SEAF_METADATA_TYPE_DIR,
|
||||
} SeafMetadataType;
|
||||
|
||||
/* Common to seafile and seafdir objects. */
|
||||
struct _SeafFSObject {
|
||||
int type;
|
||||
};
|
||||
|
||||
struct _Seafile {
|
||||
SeafFSObject object;
|
||||
int version;
|
||||
char file_id[41];
|
||||
guint64 file_size;
|
||||
guint32 n_blocks;
|
||||
@ -32,36 +50,44 @@ seafile_ref (Seafile *seafile);
|
||||
void
|
||||
seafile_unref (Seafile *seafile);
|
||||
|
||||
typedef enum {
|
||||
SEAF_METADATA_TYPE_INVALID,
|
||||
SEAF_METADATA_TYPE_FILE,
|
||||
SEAF_METADATA_TYPE_LINK,
|
||||
SEAF_METADATA_TYPE_DIR,
|
||||
} SeafMetadataType;
|
||||
|
||||
#define SEAF_DIR_NAME_LEN 256
|
||||
|
||||
|
||||
struct _SeafDirent {
|
||||
int version;
|
||||
guint32 mode;
|
||||
char id[41];
|
||||
guint32 name_len;
|
||||
char name[SEAF_DIR_NAME_LEN];
|
||||
char *name;
|
||||
|
||||
/* attributes for version > 0 */
|
||||
gint64 mtime;
|
||||
char *modifier; /* for files only */
|
||||
gint64 size; /* for files only */
|
||||
};
|
||||
|
||||
struct _SeafDir {
|
||||
SeafFSObject object;
|
||||
int version;
|
||||
char dir_id[41];
|
||||
GList *entries;
|
||||
|
||||
/* data in on-disk format. */
|
||||
void *ondisk;
|
||||
int ondisk_size;
|
||||
};
|
||||
|
||||
SeafDir *
|
||||
seaf_dir_new (const char *id, GList *entries, gint64 ctime);
|
||||
seaf_dir_new (const char *id, GList *entries, int version);
|
||||
|
||||
void
|
||||
seaf_dir_free (SeafDir *dir);
|
||||
|
||||
SeafDir *
|
||||
seaf_dir_from_data (const char *dir_id, const uint8_t *data, int len);
|
||||
seaf_dir_from_data (const char *dir_id, const uint8_t *data, int len,
|
||||
gboolean is_json);
|
||||
|
||||
void *
|
||||
seaf_dir_to_data (SeafDir *dir, int *len);
|
||||
|
||||
int
|
||||
seaf_dir_save (SeafFSManager *fs_mgr,
|
||||
@ -69,15 +95,28 @@ seaf_dir_save (SeafFSManager *fs_mgr,
|
||||
int version,
|
||||
SeafDir *dir);
|
||||
|
||||
int
|
||||
seaf_metadata_type_from_data (const uint8_t *data, int len);
|
||||
|
||||
SeafDirent *
|
||||
seaf_dirent_new (const char *sha1, int mode, const char *name);
|
||||
seaf_dirent_new (int version, const char *sha1, int mode, const char *name,
|
||||
gint64 mtime, const char *modifier, gint64 size);
|
||||
|
||||
void
|
||||
seaf_dirent_free (SeafDirent *dent);
|
||||
|
||||
SeafDirent *
|
||||
seaf_dirent_dup (SeafDirent *dent);
|
||||
|
||||
int
|
||||
seaf_metadata_type_from_data (const uint8_t *data, int len, gboolean is_json);
|
||||
|
||||
/* Parse an fs object without knowing its type. */
|
||||
SeafFSObject *
|
||||
seaf_fs_object_from_data (const char *obj_id,
|
||||
const uint8_t *data, int len,
|
||||
gboolean is_json);
|
||||
|
||||
void
|
||||
seaf_fs_object_free (SeafFSObject *obj);
|
||||
|
||||
typedef struct {
|
||||
/* TODO: GHashTable may be inefficient when we have large number of IDs. */
|
||||
GHashTable *block_hash;
|
||||
@ -136,8 +175,10 @@ seaf_fs_manager_checkout_file (SeafFSManager *mgr,
|
||||
const char *file_id,
|
||||
const char *file_path,
|
||||
guint32 mode,
|
||||
guint64 mtime,
|
||||
struct SeafileCrypt *crypt,
|
||||
const char *conflict_suffix,
|
||||
const char *in_repo_path,
|
||||
const char *conflict_head_id,
|
||||
gboolean force_conflict,
|
||||
gboolean *conflicted);
|
||||
|
||||
@ -162,6 +203,7 @@ seaf_fs_manager_index_blocks (SeafFSManager *mgr,
|
||||
int version,
|
||||
const char *file_path,
|
||||
unsigned char sha1[],
|
||||
gint64 *size,
|
||||
SeafileCrypt *crypt,
|
||||
gboolean write_data);
|
||||
|
||||
@ -311,4 +353,10 @@ seaf_fs_manager_verify_object (SeafFSManager *mgr,
|
||||
gboolean verify_id,
|
||||
gboolean *io_error);
|
||||
|
||||
int
|
||||
dir_version_from_repo_version (int repo_version);
|
||||
|
||||
int
|
||||
seafile_version_from_repo_version (int repo_version);
|
||||
|
||||
#endif
|
||||
|
@ -257,6 +257,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
|
||||
|
||||
static int update_one(const char *repo_id,
|
||||
int version,
|
||||
const char *worktree,
|
||||
struct cache_tree *it,
|
||||
struct cache_entry **cache,
|
||||
int entries,
|
||||
@ -306,6 +307,7 @@ static int update_one(const char *repo_id,
|
||||
if (!sub->cache_tree)
|
||||
sub->cache_tree = cache_tree();
|
||||
subcnt = update_one(repo_id, version,
|
||||
worktree,
|
||||
sub->cache_tree,
|
||||
cache + i, entries - i,
|
||||
path,
|
||||
@ -322,7 +324,8 @@ static int update_one(const char *repo_id,
|
||||
|
||||
discard_unused_subtrees(it);
|
||||
|
||||
if (commit_cb (repo_id, version, it, cache, entries, base, baselen) < 0) {
|
||||
if (commit_cb (repo_id, version, worktree,
|
||||
it, cache, entries, base, baselen) < 0) {
|
||||
g_warning ("save seafile dirent failed");
|
||||
return -1;
|
||||
}
|
||||
@ -332,6 +335,7 @@ static int update_one(const char *repo_id,
|
||||
|
||||
int cache_tree_update(const char *repo_id,
|
||||
int repo_version,
|
||||
const char *worktree,
|
||||
struct cache_tree *it,
|
||||
struct cache_entry **cache,
|
||||
int entries,
|
||||
@ -343,7 +347,7 @@ int cache_tree_update(const char *repo_id,
|
||||
i = verify_cache(cache, entries);
|
||||
if (i)
|
||||
return i;
|
||||
i = update_one(repo_id, repo_version,
|
||||
i = update_one(repo_id, repo_version, worktree,
|
||||
it, cache, entries, "", 0, missing_ok, dryrun, commit_cb);
|
||||
if (i < 0)
|
||||
return i;
|
||||
@ -514,6 +518,8 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
|
||||
return it;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
|
||||
{
|
||||
int entries, was_valid, newfd;
|
||||
@ -573,6 +579,8 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* 0 */
|
||||
|
||||
static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
|
||||
{
|
||||
struct tree_desc desc;
|
||||
|
@ -16,10 +16,13 @@ struct cache_tree {
|
||||
unsigned char sha1[20];
|
||||
int subtree_nr;
|
||||
int subtree_alloc;
|
||||
guint64 mtime;
|
||||
struct cache_tree_sub **down;
|
||||
};
|
||||
|
||||
typedef int (*CommitCB) (const char *repo_id, int version, struct cache_tree *,
|
||||
typedef int (*CommitCB) (const char *, int,
|
||||
const char *,
|
||||
struct cache_tree *,
|
||||
struct cache_entry **, int, const char *, int);
|
||||
struct cache_tree_sub *cache_tree_find_subtree(struct cache_tree *,
|
||||
const char *, int, int);
|
||||
@ -34,6 +37,7 @@ struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *);
|
||||
|
||||
int cache_tree_fully_valid(struct cache_tree *);
|
||||
int cache_tree_update(const char *repo_id, int version,
|
||||
const char *worktree,
|
||||
struct cache_tree *, struct cache_entry **, int, int, int, CommitCB);
|
||||
|
||||
/* bitmasks to write_cache_as_tree flags */
|
||||
|
@ -66,6 +66,7 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
|
||||
struct cache_entry *old = istate->cache[nr];
|
||||
|
||||
remove_name_hash(old);
|
||||
cache_entry_free (old);
|
||||
set_index_entry(istate, nr, ce);
|
||||
istate->cache_changed = 1;
|
||||
}
|
||||
@ -79,7 +80,8 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
|
||||
g_critical("bad signature\n");
|
||||
return -1;
|
||||
}
|
||||
if (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3)) {
|
||||
if (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3) &&
|
||||
hdr->hdr_version != htonl(4)) {
|
||||
g_critical("bad index version\n");
|
||||
return -1;
|
||||
}
|
||||
@ -118,21 +120,21 @@ static int convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_ent
|
||||
|
||||
len = flags & CE_NAMEMASK;
|
||||
|
||||
if (flags & CE_EXTENDED) {
|
||||
struct ondisk_cache_entry_extended *ondisk2;
|
||||
int extended_flags;
|
||||
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
|
||||
extended_flags = ntohs(ondisk2->flags2) << 16;
|
||||
/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
|
||||
if (extended_flags & ~CE_EXTENDED_FLAGS) {
|
||||
g_critical("Unknown index entry format %08x\n", extended_flags);
|
||||
return -1;
|
||||
}
|
||||
flags |= extended_flags;
|
||||
name = ondisk2->name;
|
||||
}
|
||||
else
|
||||
name = ondisk->name;
|
||||
/* if (flags & CE_EXTENDED) { */
|
||||
/* struct ondisk_cache_entry_extended *ondisk2; */
|
||||
/* int extended_flags; */
|
||||
/* ondisk2 = (struct ondisk_cache_entry_extended *)ondisk; */
|
||||
/* extended_flags = ntohs(ondisk2->flags2) << 16; */
|
||||
/* /\* We do not yet understand any bit out of CE_EXTENDED_FLAGS *\/ */
|
||||
/* if (extended_flags & ~CE_EXTENDED_FLAGS) { */
|
||||
/* g_critical("Unknown index entry format %08x\n", extended_flags); */
|
||||
/* return -1; */
|
||||
/* } */
|
||||
/* flags |= extended_flags; */
|
||||
/* name = ondisk2->name; */
|
||||
/* } */
|
||||
/* else */
|
||||
name = ondisk->name;
|
||||
|
||||
if (len == CE_NAMEMASK)
|
||||
len = strlen(name);
|
||||
@ -141,8 +143,6 @@ static int convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_ent
|
||||
|
||||
ret->ce_ctime.sec = ntohl(ondisk->ctime.sec);
|
||||
ret->ce_mtime.sec = ntohl(ondisk->mtime.sec);
|
||||
ret->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
|
||||
ret->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
|
||||
ret->ce_dev = ntohl(ondisk->dev);
|
||||
ret->ce_ino = ntohl(ondisk->ino);
|
||||
ret->ce_mode = ntohl(ondisk->mode);
|
||||
@ -165,35 +165,101 @@ static int convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_ent
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int read_index_extension(struct index_state *istate,
|
||||
const char *ext, void *data, unsigned long sz)
|
||||
static int convert_from_disk2(struct ondisk_cache_entry2 *ondisk, struct cache_entry **ce)
|
||||
{
|
||||
switch (CACHE_EXT(ext)) {
|
||||
case CACHE_EXT_TREE:
|
||||
istate->cache_tree = cache_tree_read(data, sz);
|
||||
break;
|
||||
case CACHE_EXT_RESOLVE_UNDO:
|
||||
/* istate->resolve_undo = resolve_undo_read(data, sz); */
|
||||
break;
|
||||
size_t len;
|
||||
const char *name;
|
||||
unsigned int flags = 0;
|
||||
struct cache_entry *ret;
|
||||
|
||||
flags = ntohs(ondisk->flags);
|
||||
|
||||
len = flags & CE_NAMEMASK;
|
||||
|
||||
name = ondisk->name;
|
||||
|
||||
if (len == CE_NAMEMASK)
|
||||
len = strlen(name);
|
||||
|
||||
ret = calloc(1, cache_entry_size(len));
|
||||
|
||||
ret->ce_ctime.sec = ntoh64(ondisk->ctime.sec);
|
||||
ret->ce_mtime.sec = ntoh64(ondisk->mtime.sec);
|
||||
ret->ce_dev = ntohl(ondisk->dev);
|
||||
ret->ce_ino = ntohl(ondisk->ino);
|
||||
ret->ce_mode = ntohl(ondisk->mode);
|
||||
ret->ce_uid = ntohl(ondisk->uid);
|
||||
ret->ce_gid = ntohl(ondisk->gid);
|
||||
ret->ce_size = ntoh64(ondisk->size);
|
||||
/* On-disk flags are just 16 bits */
|
||||
ret->ce_flags = flags;
|
||||
|
||||
hashcpy(ret->sha1, ondisk->sha1);
|
||||
|
||||
/*
|
||||
* NEEDSWORK: If the original index is crafted, this copy could
|
||||
* go unchecked.
|
||||
*/
|
||||
memcpy(ret->name, name, len + 1);
|
||||
|
||||
*ce = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_modifiers (struct index_state *istate, void *data, unsigned int size)
|
||||
{
|
||||
char *p = data, *sep = data, *modifier;
|
||||
unsigned int i;
|
||||
unsigned int idx = 0;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (*sep == '\n') {
|
||||
while (idx < istate->cache_nr &&
|
||||
S_ISDIR(istate->cache[idx]->ce_mode))
|
||||
++idx;
|
||||
if (idx >= istate->cache_nr) {
|
||||
g_warning ("More modifiers than cache entries.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
modifier = g_strndup(p, sep - p);
|
||||
istate->cache[idx]->modifier = modifier;
|
||||
idx++;
|
||||
p = sep + 1;
|
||||
}
|
||||
++sep;
|
||||
}
|
||||
|
||||
if (idx != istate->cache_nr) {
|
||||
g_warning ("Less modifiers than cached entries.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
istate->has_modifier = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_index_extension(struct index_state *istate,
|
||||
unsigned int ext, void *data, unsigned int sz)
|
||||
{
|
||||
switch (ext) {
|
||||
case CACHE_EXT_MODIFIER:
|
||||
return read_modifiers (istate, data, sz);
|
||||
default:
|
||||
/* if (*ext < 'A' || 'Z' < *ext) */
|
||||
/* return error("index uses %.4s extension, which we do not understand", */
|
||||
/* ext); */
|
||||
/* fprintf(stderr, "ignoring %.4s extension\n", ext); */
|
||||
g_critical("unknown extension.\n");
|
||||
g_critical("unknown extension %u.\n", ext);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* remember to discard_cache() before reading a different cache! */
|
||||
int read_index_from(struct index_state *istate, const char *path)
|
||||
int read_index_from(struct index_state *istate, const char *path, int repo_version)
|
||||
{
|
||||
int fd, i;
|
||||
SeafStat st;
|
||||
unsigned long src_offset, dst_offset;
|
||||
unsigned long src_offset;
|
||||
struct cache_header *hdr;
|
||||
void *mm;
|
||||
size_t mmap_size;
|
||||
@ -201,6 +267,11 @@ int read_index_from(struct index_state *istate, const char *path)
|
||||
if (istate->initialized)
|
||||
return istate->cache_nr;
|
||||
|
||||
/* All newly created index files are version 4. */
|
||||
istate->version = 4;
|
||||
/* Index file stores modifier info if repo version > 0 */
|
||||
if (repo_version > 0)
|
||||
istate->has_modifier = 1;
|
||||
istate->timestamp.sec = 0;
|
||||
istate->timestamp.nsec = 0;
|
||||
fd = g_open (path, O_RDONLY | O_BINARY, 0);
|
||||
@ -233,6 +304,11 @@ int read_index_from(struct index_state *istate, const char *path)
|
||||
if (verify_hdr(hdr, mmap_size) < 0)
|
||||
goto unmap;
|
||||
|
||||
/* Index version will be set to on-disk value here.
|
||||
* If the index is from an old repo, it will be set to 2.
|
||||
* But when we write the index, it'll be updated to version 4.
|
||||
*/
|
||||
istate->version = ntohl(hdr->hdr_version);
|
||||
istate->cache_nr = ntohl(hdr->hdr_entries);
|
||||
istate->cache_alloc = alloc_nr(istate->cache_nr);
|
||||
istate->cache = calloc(istate->cache_alloc, sizeof(struct cache_entry *));
|
||||
@ -247,47 +323,57 @@ int read_index_from(struct index_state *istate, const char *path)
|
||||
istate->initialized = 1;
|
||||
|
||||
src_offset = sizeof(*hdr);
|
||||
dst_offset = 0;
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct ondisk_cache_entry *disk_ce;
|
||||
struct ondisk_cache_entry2 *disk_ce2;
|
||||
struct cache_entry *ce;
|
||||
|
||||
disk_ce = (struct ondisk_cache_entry *)((char *)mm + src_offset);
|
||||
/* ce = (struct cache_entry *)((char *)istate->alloc + dst_offset); */
|
||||
if (istate->version < 4) {
|
||||
disk_ce = (struct ondisk_cache_entry *)((char *)mm + src_offset);
|
||||
|
||||
/* allocate each ce separately so that we can free new
|
||||
* entries added by add_index_entry() later.
|
||||
*/
|
||||
if (convert_from_disk(disk_ce, &ce) < 0)
|
||||
return -1;
|
||||
/* allocate each ce separately so that we can free new
|
||||
* entries added by add_index_entry() later.
|
||||
*/
|
||||
if (convert_from_disk(disk_ce, &ce) < 0)
|
||||
return -1;
|
||||
|
||||
src_offset += ondisk_ce_size(ce);
|
||||
} else {
|
||||
disk_ce2 = (struct ondisk_cache_entry2 *)((char *)mm + src_offset);
|
||||
|
||||
/* allocate each ce separately so that we can free new
|
||||
* entries added by add_index_entry() later.
|
||||
*/
|
||||
if (convert_from_disk2(disk_ce2, &ce) < 0)
|
||||
return -1;
|
||||
|
||||
src_offset += ondisk_ce_size2(ce);
|
||||
}
|
||||
set_index_entry(istate, i, ce);
|
||||
|
||||
src_offset += ondisk_ce_size(ce);
|
||||
dst_offset += ce_size(ce);
|
||||
}
|
||||
istate->timestamp.sec = st.st_mtime;
|
||||
istate->timestamp.nsec = 0;
|
||||
|
||||
#if 0
|
||||
while (src_offset <= mmap_size - 20 - 8) {
|
||||
while (src_offset <= mmap_size - 20 - sizeof(struct cache_ext_hdr)) {
|
||||
/* After an array of active_nr index entries,
|
||||
* there can be arbitrary number of extended
|
||||
* sections, each of which is prefixed with
|
||||
* extension name (4-byte) and section length
|
||||
* in 4-byte network byte order.
|
||||
*/
|
||||
uint32_t extsize;
|
||||
memcpy(&extsize, (char *)mm + src_offset + 4, 4);
|
||||
extsize = ntohl(extsize);
|
||||
struct cache_ext_hdr *exthdr;
|
||||
exthdr = (struct cache_ext_hdr *) ((char *)mm + src_offset);
|
||||
unsigned int name = ntohl(exthdr->ext_name);
|
||||
unsigned int size = ntohl(exthdr->ext_size);
|
||||
if (read_index_extension(istate,
|
||||
(const char *) mm + src_offset,
|
||||
(char *) mm + src_offset + 8,
|
||||
extsize) < 0)
|
||||
name,
|
||||
(char *) mm + src_offset + sizeof(struct cache_ext_hdr),
|
||||
size) < 0)
|
||||
goto unmap;
|
||||
src_offset += 8;
|
||||
src_offset += extsize;
|
||||
src_offset += sizeof(struct cache_ext_hdr);
|
||||
src_offset += size;
|
||||
}
|
||||
#endif
|
||||
|
||||
munmap(mm, mmap_size);
|
||||
return istate->cache_nr;
|
||||
|
||||
@ -345,8 +431,8 @@ int cache_name_compare(const char *name1, int flags1, const char *name2, int fla
|
||||
*/
|
||||
void fill_stat_cache_info(struct cache_entry *ce, SeafStat *st)
|
||||
{
|
||||
ce->ce_ctime.sec = (unsigned int)st->st_ctime;
|
||||
ce->ce_mtime.sec = (unsigned int)st->st_mtime;
|
||||
ce->ce_ctime.sec = st->st_ctime;
|
||||
ce->ce_mtime.sec = st->st_mtime;
|
||||
ce->ce_ctime.nsec = 0;
|
||||
ce->ce_mtime.nsec = 0;
|
||||
ce->ce_dev = st->st_dev;
|
||||
@ -417,9 +503,9 @@ static int ce_match_stat_basic(struct cache_entry *ce, SeafStat *st)
|
||||
g_warning("internal error: ce_mode is %o\n", ce->ce_mode);
|
||||
return -1;
|
||||
}
|
||||
if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
|
||||
if (ce->ce_mtime.sec != st->st_mtime)
|
||||
changed |= MTIME_CHANGED;
|
||||
if (ce->ce_ctime.sec != (unsigned int)st->st_ctime)
|
||||
if (ce->ce_ctime.sec != st->st_ctime)
|
||||
changed |= CTIME_CHANGED;
|
||||
|
||||
#if 0
|
||||
@ -428,7 +514,6 @@ static int ce_match_stat_basic(struct cache_entry *ce, SeafStat *st)
|
||||
changed |= OWNER_CHANGED;
|
||||
if (ce->ce_ino != (unsigned int) st->st_ino)
|
||||
changed |= INODE_CHANGED;
|
||||
#endif
|
||||
|
||||
if (ce->ce_size != st->st_size)
|
||||
changed |= DATA_CHANGED;
|
||||
@ -438,6 +523,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, SeafStat *st)
|
||||
if (!is_empty_blob_sha1(ce->sha1))
|
||||
changed |= DATA_CHANGED;
|
||||
}
|
||||
#endif
|
||||
|
||||
return changed;
|
||||
}
|
||||
@ -625,6 +711,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
|
||||
|
||||
/* record_resolve_undo(istate, ce); */
|
||||
remove_name_hash(ce);
|
||||
cache_entry_free (ce);
|
||||
istate->cache_changed = 1;
|
||||
istate->cache_nr--;
|
||||
if (pos >= istate->cache_nr)
|
||||
@ -648,7 +735,7 @@ void remove_marked_cache_entries(struct index_state *istate)
|
||||
for (i = j = 0; i < istate->cache_nr; i++) {
|
||||
if (ce_array[i]->ce_flags & CE_REMOVE) {
|
||||
remove_name_hash(ce_array[i]);
|
||||
free (ce_array[i]);
|
||||
cache_entry_free (ce_array[i]);
|
||||
} else {
|
||||
ce_array[j++] = ce_array[i];
|
||||
}
|
||||
@ -852,7 +939,8 @@ int add_to_index(const char *repo_id,
|
||||
SeafStat *st,
|
||||
int flags,
|
||||
SeafileCrypt *crypt,
|
||||
IndexCB index_cb)
|
||||
IndexCB index_cb,
|
||||
const char *modifier)
|
||||
{
|
||||
int size, namelen;
|
||||
mode_t st_mode = st->st_mode;
|
||||
@ -899,20 +987,25 @@ int add_to_index(const char *repo_id,
|
||||
if (alias && !ce_stage(alias) &&
|
||||
(ABS(alias->ce_mtime.sec - st->st_mtime) == 3600 ||
|
||||
ABS(alias->ce_ctime.sec - st->st_ctime) == 3600)) {
|
||||
if (index_cb (repo_id, version, full_path, sha1, crypt, FALSE) < 0)
|
||||
if (index_cb (repo_id, version, full_path, sha1, crypt, FALSE) < 0) {
|
||||
free (ce);
|
||||
return 0;
|
||||
}
|
||||
if (memcmp (alias->sha1, sha1, 20) == 0)
|
||||
goto update_index;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Skip index file errors. */
|
||||
if (index_cb (repo_id, version, full_path, sha1, crypt, TRUE) < 0)
|
||||
if (index_cb (repo_id, version, full_path, sha1, crypt, TRUE) < 0) {
|
||||
free (ce);
|
||||
return 0;
|
||||
}
|
||||
|
||||
update_index:
|
||||
memcpy (ce->sha1, sha1, 20);
|
||||
ce->ce_flags |= CE_ADDED;
|
||||
ce->modifier = strdup(modifier);
|
||||
|
||||
if (add_index_entry(istate, ce, add_option)) {
|
||||
g_warning("unable to add %s to index\n",path);
|
||||
@ -941,12 +1034,12 @@ static int is_garbage_empty_dir (struct index_state *istate, struct cache_entry
|
||||
int this_len = strlen (ce->name);
|
||||
while (pos < istate->cache_nr) {
|
||||
next = istate->cache[pos];
|
||||
/* If file under this "empty dir" exists and mtime is 0,
|
||||
/* If file under this "empty dir" exists and ctime is 0,
|
||||
* then this empty dir is left by a file checkout failure.
|
||||
*/
|
||||
if (strncmp (ce->name, next->name, this_len) != 0)
|
||||
break;
|
||||
if (next->ce_mtime.sec == 0 && ce_stage(next) == 0)
|
||||
if (next->ce_ctime.sec == 0 && ce_stage(next) == 0)
|
||||
return 1;
|
||||
++pos;
|
||||
}
|
||||
@ -967,7 +1060,8 @@ add_empty_dir_to_index (struct index_state *istate, const char *path, SeafStat *
|
||||
memcpy(ce->name, path, namelen);
|
||||
ce->ce_flags = namelen;
|
||||
|
||||
ce->ce_mtime.sec = (unsigned int)st->st_mtime;
|
||||
ce->ce_mtime.sec = st->st_mtime;
|
||||
ce->ce_ctime.sec = st->st_ctime;
|
||||
|
||||
ce->ce_mode = S_IFDIR;
|
||||
/* sha1 is all-zero. */
|
||||
@ -1202,16 +1296,14 @@ static int ce_write(WriteIndexInfo *info, int fd, void *data, unsigned int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int write_index_ext_header(SHA_CTX *context, int fd,
|
||||
static int write_index_ext_header(WriteIndexInfo *info, int fd,
|
||||
unsigned int ext, unsigned int sz)
|
||||
{
|
||||
ext = htonl(ext);
|
||||
sz = htonl(sz);
|
||||
return ((ce_write(context, fd, &ext, 4) < 0) ||
|
||||
(ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
|
||||
return ((ce_write(info, fd, &ext, 4) < 0) ||
|
||||
(ce_write(info, fd, &sz, 4) < 0)) ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ce_flush(WriteIndexInfo *info, int fd)
|
||||
{
|
||||
@ -1292,10 +1384,8 @@ static int ce_write_entry(WriteIndexInfo *info, int fd, struct cache_entry *ce)
|
||||
char *name;
|
||||
int result;
|
||||
|
||||
ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
|
||||
ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
|
||||
ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
|
||||
ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
|
||||
ondisk->ctime.sec = htonl((unsigned int)ce->ce_ctime.sec);
|
||||
ondisk->mtime.sec = htonl((unsigned int)ce->ce_mtime.sec);
|
||||
ondisk->dev = htonl(ce->ce_dev);
|
||||
ondisk->ino = htonl(ce->ce_ino);
|
||||
ondisk->mode = htonl(ce->ce_mode);
|
||||
@ -1304,14 +1394,14 @@ static int ce_write_entry(WriteIndexInfo *info, int fd, struct cache_entry *ce)
|
||||
ondisk->size = hton64(ce->ce_size);
|
||||
hashcpy(ondisk->sha1, ce->sha1);
|
||||
ondisk->flags = htons(ce->ce_flags);
|
||||
if (ce->ce_flags & CE_EXTENDED) {
|
||||
struct ondisk_cache_entry_extended *ondisk2;
|
||||
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
|
||||
ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
|
||||
name = ondisk2->name;
|
||||
}
|
||||
else
|
||||
name = ondisk->name;
|
||||
/* if (ce->ce_flags & CE_EXTENDED) { */
|
||||
/* struct ondisk_cache_entry_extended *ondisk2; */
|
||||
/* ondisk2 = (struct ondisk_cache_entry_extended *)ondisk; */
|
||||
/* ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16); */
|
||||
/* name = ondisk2->name; */
|
||||
/* } */
|
||||
/* else */
|
||||
name = ondisk->name;
|
||||
memcpy(name, ce->name, ce_namelen(ce));
|
||||
|
||||
result = ce_write(info, fd, ondisk, size);
|
||||
@ -1319,6 +1409,52 @@ static int ce_write_entry(WriteIndexInfo *info, int fd, struct cache_entry *ce)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ce_write_entry2(WriteIndexInfo *info, int fd, struct cache_entry *ce)
|
||||
{
|
||||
int size = ondisk_ce_size2(ce);
|
||||
struct ondisk_cache_entry2 *ondisk = calloc(1, size);
|
||||
char *name;
|
||||
int result;
|
||||
|
||||
ondisk->ctime.sec = hton64(ce->ce_ctime.sec);
|
||||
ondisk->mtime.sec = hton64(ce->ce_mtime.sec);
|
||||
ondisk->dev = htonl(ce->ce_dev);
|
||||
ondisk->ino = htonl(ce->ce_ino);
|
||||
ondisk->mode = htonl(ce->ce_mode);
|
||||
ondisk->uid = htonl(ce->ce_uid);
|
||||
ondisk->gid = htonl(ce->ce_gid);
|
||||
ondisk->size = hton64(ce->ce_size);
|
||||
hashcpy(ondisk->sha1, ce->sha1);
|
||||
ondisk->flags = htons(ce->ce_flags);
|
||||
name = ondisk->name;
|
||||
memcpy(name, ce->name, ce_namelen(ce));
|
||||
|
||||
result = ce_write(info, fd, ondisk, size);
|
||||
free(ondisk);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
modifiers_to_string (GString *buf, struct index_state *istate)
|
||||
{
|
||||
int i;
|
||||
struct cache_entry *ce;
|
||||
|
||||
for (i = 0; i < istate->cache_nr; ++i) {
|
||||
ce = istate->cache[i];
|
||||
if (S_ISDIR(ce->ce_mode) || (ce->ce_flags & CE_REMOVE))
|
||||
continue;
|
||||
if (!ce->modifier) {
|
||||
g_warning ("BUG: index entry %s doesn't have modifier info.\n",
|
||||
ce->name);
|
||||
return -1;
|
||||
}
|
||||
g_string_append_printf (buf, "%s\n", ce->modifier);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_index(struct index_state *istate, int newfd)
|
||||
{
|
||||
WriteIndexInfo info;
|
||||
@ -1343,8 +1479,8 @@ int write_index(struct index_state *istate, int newfd)
|
||||
}
|
||||
|
||||
hdr.hdr_signature = htonl(CACHE_SIGNATURE);
|
||||
/* for extended format, increase version so older git won't try to read it */
|
||||
hdr.hdr_version = htonl(extended ? 3 : 2);
|
||||
/* Always use version 4 for newly created index files */
|
||||
hdr.hdr_version = htonl(4);
|
||||
hdr.hdr_entries = htonl(entries - removed);
|
||||
|
||||
SHA1_Init(&info.context);
|
||||
@ -1357,34 +1493,26 @@ int write_index(struct index_state *istate, int newfd)
|
||||
continue;
|
||||
/* if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) */
|
||||
/* ce_smudge_racily_clean_entry(ce); */
|
||||
if (ce_write_entry(&info, newfd, ce) < 0)
|
||||
if (ce_write_entry2(&info, newfd, ce) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Write extension data here */
|
||||
if (istate->cache_tree) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
if (istate->has_modifier) {
|
||||
GString *buf = g_string_new ("");
|
||||
int err;
|
||||
|
||||
cache_tree_write(&sb, istate->cache_tree);
|
||||
err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
|
||||
|| ce_write(&c, newfd, sb.buf, sb.len) < 0;
|
||||
strbuf_release(&sb);
|
||||
if (modifiers_to_string (buf, istate) < 0) {
|
||||
g_string_free (buf, TRUE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = write_index_ext_header(&info, newfd, CACHE_EXT_MODIFIER, buf->len) < 0
|
||||
|| ce_write(&info, newfd, buf->str, buf->len) < 0;
|
||||
g_string_free (buf, TRUE);
|
||||
if (err)
|
||||
return -1;
|
||||
}
|
||||
if (istate->resolve_undo) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
resolve_undo_write(&sb, istate->resolve_undo);
|
||||
err = write_index_ext_header(&c, newfd, CACHE_EXT_RESOLVE_UNDO,
|
||||
sb.len) < 0
|
||||
|| ce_write(&c, newfd, sb.buf, sb.len) < 0;
|
||||
strbuf_release(&sb);
|
||||
if (err)
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ce_flush(&info, newfd) || seaf_fstat(newfd, &st))
|
||||
return -1;
|
||||
@ -1397,7 +1525,7 @@ int discard_index(struct index_state *istate)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < istate->cache_nr; ++i)
|
||||
free (istate->cache[i]);
|
||||
cache_entry_free (istate->cache[i]);
|
||||
|
||||
istate->cache_nr = 0;
|
||||
istate->cache_changed = 0;
|
||||
@ -1414,3 +1542,9 @@ int discard_index(struct index_state *istate)
|
||||
/* no need to throw away allocated active_cache */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cache_entry_free (struct cache_entry *ce)
|
||||
{
|
||||
g_free (ce->modifier);
|
||||
free (ce);
|
||||
}
|
||||
|
@ -133,6 +133,25 @@ struct ondisk_cache_entry {
|
||||
char name[0]; /* more */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cache_time64 {
|
||||
guint64 sec;
|
||||
guint64 nsec;
|
||||
};
|
||||
|
||||
struct ondisk_cache_entry2 {
|
||||
struct cache_time64 ctime;
|
||||
struct cache_time64 mtime;
|
||||
unsigned int dev;
|
||||
unsigned int ino;
|
||||
unsigned int mode;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
uint64_t size;
|
||||
unsigned char sha1[20];
|
||||
unsigned short flags;
|
||||
char name[0]; /* more */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* This struct is used when CE_EXTENDED bit is 1
|
||||
* The struct must match ondisk_cache_entry exactly from
|
||||
@ -153,9 +172,17 @@ struct ondisk_cache_entry_extended {
|
||||
char name[0]; /* more */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CACHE_EXT_MODIFIER 1
|
||||
|
||||
struct cache_ext_hdr {
|
||||
unsigned int ext_name;
|
||||
unsigned int ext_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cache_entry {
|
||||
struct cache_time ce_ctime;
|
||||
struct cache_time ce_mtime;
|
||||
struct cache_time64 ce_ctime;
|
||||
struct cache_time64 ce_mtime;
|
||||
guint64 current_mtime; /* used in merge */
|
||||
unsigned int ce_dev;
|
||||
unsigned int ce_ino;
|
||||
unsigned int ce_mode;
|
||||
@ -164,6 +191,7 @@ struct cache_entry {
|
||||
uint64_t ce_size;
|
||||
unsigned int ce_flags;
|
||||
unsigned char sha1[20];
|
||||
char *modifier;
|
||||
struct cache_entry *next;
|
||||
char name[0]; /* more */
|
||||
};
|
||||
@ -226,8 +254,8 @@ static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry
|
||||
{
|
||||
unsigned int state = dst->ce_flags & CE_STATE_MASK;
|
||||
|
||||
/* Don't copy hash chain and name */
|
||||
memcpy(dst, src, offsetof(struct cache_entry, next));
|
||||
/* Don't copy modifier, hash chain and name */
|
||||
memcpy(dst, src, offsetof(struct cache_entry, modifier));
|
||||
|
||||
/* Restore the hash state */
|
||||
dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
|
||||
@ -249,9 +277,8 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
|
||||
}
|
||||
|
||||
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
|
||||
#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \
|
||||
ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
|
||||
ondisk_cache_entry_size(ce_namelen(ce)))
|
||||
#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
|
||||
#define ondisk_ce_size2(ce) ondisk_cache_entry_size2(ce_namelen(ce))
|
||||
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
|
||||
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
|
||||
#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
|
||||
@ -296,9 +323,11 @@ static inline unsigned int canon_mode(unsigned int mode)
|
||||
#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
|
||||
#define cache_entry_size(len) flexible_size(cache_entry,len)
|
||||
#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
|
||||
#define ondisk_cache_entry_size2(len) flexible_size(ondisk_cache_entry2,len)
|
||||
#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
|
||||
|
||||
struct index_state {
|
||||
unsigned int version;
|
||||
struct cache_entry **cache;
|
||||
unsigned int cache_nr, cache_alloc, cache_changed;
|
||||
/* struct cache_tree *cache_tree; */
|
||||
@ -307,6 +336,7 @@ struct index_state {
|
||||
unsigned name_hash_initialized : 1,
|
||||
initialized : 1;
|
||||
struct hash_table name_hash;
|
||||
int has_modifier;
|
||||
};
|
||||
|
||||
extern struct index_state the_index;
|
||||
@ -372,7 +402,7 @@ static inline enum object_type object_type(unsigned int mode)
|
||||
/* Initialize and use the cache information */
|
||||
extern int read_index(struct index_state *);
|
||||
extern int read_index_preload(struct index_state *, const char **pathspec);
|
||||
extern int read_index_from(struct index_state *, const char *path);
|
||||
extern int read_index_from(struct index_state *, const char *path, int repo_version);
|
||||
extern int is_index_unborn(struct index_state *);
|
||||
extern int read_index_unmerged(struct index_state *);
|
||||
extern int write_index(struct index_state *, int newfd);
|
||||
@ -413,7 +443,8 @@ int add_to_index(const char *repo_id,
|
||||
SeafStat *st,
|
||||
int flags,
|
||||
struct SeafileCrypt *crypt,
|
||||
IndexCB index_cb);
|
||||
IndexCB index_cb,
|
||||
const char *modifier);
|
||||
|
||||
int
|
||||
add_empty_dir_to_index (struct index_state *istate,
|
||||
@ -425,6 +456,8 @@ extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned ch
|
||||
extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
|
||||
extern int index_name_is_other(const struct index_state *, const char *, int);
|
||||
|
||||
void cache_entry_free (struct cache_entry *ce);
|
||||
|
||||
/* do stat comparison even if CE_VALID is true */
|
||||
#define CE_MATCH_IGNORE_VALID 01
|
||||
/* do not check the contents but report dirty on racily-clean entries */
|
||||
|
@ -12,31 +12,69 @@ merge_trees_recursive (const char *repo_id, int version,
|
||||
MergeOptions *opt);
|
||||
|
||||
static char *
|
||||
merge_conflict_filename (const char *remote_head,
|
||||
merge_conflict_filename (const char *repo_id, int version,
|
||||
const char *remote_head,
|
||||
const char *basedir,
|
||||
const char *filename)
|
||||
{
|
||||
char *conflict_name = NULL;
|
||||
char *path = NULL, *modifier = NULL, *conflict_name = NULL;
|
||||
gint64 mtime;
|
||||
SeafCommit *commit;
|
||||
|
||||
conflict_name = gen_conflict_path (filename);
|
||||
path = g_strconcat (basedir, filename, NULL);
|
||||
|
||||
int rc = get_file_modifier_mtime (repo_id, version, remote_head, path,
|
||||
&modifier, &mtime);
|
||||
if (rc < 0) {
|
||||
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
repo_id, version,
|
||||
remote_head);
|
||||
if (!commit) {
|
||||
seaf_warning ("Failed to find remote head %s.\n", remote_head);
|
||||
goto out;
|
||||
}
|
||||
modifier = g_strdup(commit->creator_name);
|
||||
mtime = (gint64)time(NULL);
|
||||
seaf_commit_unref (commit);
|
||||
}
|
||||
|
||||
conflict_name = gen_conflict_path (filename, modifier, mtime);
|
||||
|
||||
out:
|
||||
g_free (path);
|
||||
g_free (modifier);
|
||||
return conflict_name;
|
||||
}
|
||||
|
||||
static char *
|
||||
merge_conflict_dirname (const char *remote_head,
|
||||
merge_conflict_dirname (const char *repo_id, int version,
|
||||
const char *remote_head,
|
||||
const char *basedir,
|
||||
const char *dirname)
|
||||
{
|
||||
char *conflict_name = NULL;
|
||||
char *modifier = NULL, *conflict_name = NULL;
|
||||
SeafCommit *commit;
|
||||
|
||||
conflict_name = gen_conflict_path (dirname);
|
||||
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
repo_id, version,
|
||||
remote_head);
|
||||
if (!commit) {
|
||||
seaf_warning ("Failed to find remote head %s.\n", remote_head);
|
||||
goto out;
|
||||
}
|
||||
modifier = g_strdup(commit->creator_name);
|
||||
seaf_commit_unref (commit);
|
||||
|
||||
conflict_name = gen_conflict_path (dirname, modifier, (gint64)time(NULL));
|
||||
|
||||
out:
|
||||
g_free (modifier);
|
||||
return conflict_name;
|
||||
}
|
||||
|
||||
static int
|
||||
merge_entries (int n, SeafDirent *dents[],
|
||||
merge_entries (const char *repo_id, int version,
|
||||
int n, SeafDirent *dents[],
|
||||
const char *basedir,
|
||||
GList **dents_out,
|
||||
MergeOptions *opt)
|
||||
@ -87,7 +125,8 @@ merge_entries (int n, SeafDirent *dents[],
|
||||
|
||||
seaf_debug ("%s%s: files conflict\n", basedir, head->name);
|
||||
|
||||
conflict_name = merge_conflict_filename(opt->remote_head,
|
||||
conflict_name = merge_conflict_filename(repo_id, version,
|
||||
opt->remote_head,
|
||||
basedir,
|
||||
head->name);
|
||||
if (!conflict_name)
|
||||
@ -114,7 +153,8 @@ merge_entries (int n, SeafDirent *dents[],
|
||||
seaf_debug ("%s%s: DFC, file -> dir, file\n",
|
||||
basedir, remote->name);
|
||||
|
||||
conflict_name = merge_conflict_filename(opt->remote_head,
|
||||
conflict_name = merge_conflict_filename(repo_id, version,
|
||||
opt->remote_head,
|
||||
basedir,
|
||||
remote->name);
|
||||
if (!conflict_name)
|
||||
@ -157,7 +197,8 @@ merge_entries (int n, SeafDirent *dents[],
|
||||
/* We use remote head commit author name as conflict
|
||||
* suffix of a dir.
|
||||
*/
|
||||
conflict_name = merge_conflict_dirname (opt->remote_head,
|
||||
conflict_name = merge_conflict_dirname (repo_id, version,
|
||||
opt->remote_head,
|
||||
basedir, dents[2]->name);
|
||||
if (!conflict_name)
|
||||
return -1;
|
||||
@ -211,7 +252,8 @@ merge_entries (int n, SeafDirent *dents[],
|
||||
|
||||
seaf_debug ("%s%s: DFC, dir -> dir, file\n", basedir, remote->name);
|
||||
|
||||
conflict_name = merge_conflict_filename(opt->remote_head,
|
||||
conflict_name = merge_conflict_filename(repo_id, version,
|
||||
opt->remote_head,
|
||||
basedir,
|
||||
remote->name);
|
||||
if (!conflict_name)
|
||||
@ -250,7 +292,8 @@ merge_entries (int n, SeafDirent *dents[],
|
||||
|
||||
seaf_debug ("%s%s: DFC, dir -> file, dir\n", basedir, head->name);
|
||||
|
||||
conflict_name = merge_conflict_dirname (opt->remote_head,
|
||||
conflict_name = merge_conflict_dirname (repo_id, version,
|
||||
opt->remote_head,
|
||||
basedir, dents[2]->name);
|
||||
if (!conflict_name)
|
||||
return -1;
|
||||
@ -472,7 +515,8 @@ merge_trees_recursive (const char *repo_id, int version,
|
||||
|
||||
/* Merge entries of this level. */
|
||||
if (n_files > 0) {
|
||||
ret = merge_entries (n, dents, basedir, &merged_dents, opt);
|
||||
ret = merge_entries (repo_id, version,
|
||||
n, dents, basedir, &merged_dents, opt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@ -488,7 +532,8 @@ merge_trees_recursive (const char *repo_id, int version,
|
||||
|
||||
if (n == 3 && opt->do_merge) {
|
||||
merged_dents = g_list_sort (merged_dents, compare_dirents);
|
||||
merged_tree = seaf_dir_new (NULL, merged_dents, 0);
|
||||
merged_tree = seaf_dir_new (NULL, merged_dents,
|
||||
dir_version_from_repo_version(version));
|
||||
|
||||
memcpy (opt->merged_tree_root, merged_tree->dir_id, 40);
|
||||
|
||||
|
@ -1263,6 +1263,9 @@ seafile_list_dir_by_path(const char *repo_id,
|
||||
"obj_id", dent->id,
|
||||
"obj_name", dent->name,
|
||||
"mode", dent->mode,
|
||||
"version", dent->version,
|
||||
"mtime", dent->mtime,
|
||||
"size", dent->size,
|
||||
NULL);
|
||||
res = g_list_prepend (res, d);
|
||||
}
|
||||
@ -3555,7 +3558,11 @@ seafile_list_dir (const char *repo_id,
|
||||
"obj_id", dent->id,
|
||||
"obj_name", dent->name,
|
||||
"mode", dent->mode,
|
||||
"version", dent->version,
|
||||
"mtime", dent->mtime,
|
||||
"size", dent->size,
|
||||
NULL);
|
||||
seaf_message ("%"G_GUINT64_FORMAT"\n", dent->mtime);
|
||||
res = g_list_prepend (res, d);
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,10 @@ traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
|
||||
entries[i].path = dent->name;
|
||||
entries[i].pathlen = dent->name_len;
|
||||
entries[i].mode = dent->mode;
|
||||
entries[i].mtime = dent->mtime;
|
||||
if (S_ISREG(dent->mode)) {
|
||||
entries[i].modifier = dent->modifier;
|
||||
}
|
||||
|
||||
ptrs[i] = ptrs[i]->next;
|
||||
}
|
||||
|
@ -4,14 +4,16 @@
|
||||
#include "fs-mgr.h"
|
||||
|
||||
struct name_entry {
|
||||
unsigned char sha1[20];
|
||||
const char *path;
|
||||
int pathlen;
|
||||
unsigned int mode;
|
||||
unsigned char sha1[20];
|
||||
const char *path;
|
||||
int pathlen;
|
||||
unsigned int mode;
|
||||
char *modifier;
|
||||
guint64 mtime;
|
||||
};
|
||||
|
||||
struct tree_desc {
|
||||
SeafDir *tree;
|
||||
SeafDir *tree;
|
||||
};
|
||||
|
||||
inline static void tree_desc_free (struct tree_desc *t)
|
||||
|
@ -20,6 +20,7 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
|
||||
memcpy(new, ce, size);
|
||||
new->next = NULL;
|
||||
new->ce_flags = (new->ce_flags & ~clear) | set;
|
||||
new->modifier = g_strdup(ce->modifier);
|
||||
add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
|
||||
}
|
||||
|
||||
@ -349,6 +350,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
|
||||
ce->ce_flags = create_ce_flags(len, stage);
|
||||
hashcpy(ce->sha1, n->sha1);
|
||||
make_traverse_path(ce->name, info, n);
|
||||
ce->modifier = g_strdup(n->modifier);
|
||||
ce->ce_mtime.sec = n->mtime;
|
||||
|
||||
return ce;
|
||||
}
|
||||
@ -400,7 +403,7 @@ static int unpack_nondirectories(int n, unsigned long mask,
|
||||
int ret = call_unpack_fn(src, o);
|
||||
for (i = 1; i <= n; i++)
|
||||
if (src[i] && src[i] != o->df_conflict_entry)
|
||||
free(src[i]);
|
||||
cache_entry_free(src[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -651,6 +654,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
||||
|
||||
memset(&o->result, 0, sizeof(o->result));
|
||||
o->result.initialized = 1;
|
||||
o->result.version = o->src_index->version;
|
||||
o->result.has_modifier = o->src_index->has_modifier;
|
||||
o->result.timestamp.sec = o->src_index->timestamp.sec;
|
||||
o->result.timestamp.nsec = o->src_index->timestamp.nsec;
|
||||
o->merge_size = len;
|
||||
@ -976,8 +981,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
|
||||
|
||||
/* We need timestamp when checking out the file later. */
|
||||
if (old) {
|
||||
merge->ce_ctime = old->ce_ctime;
|
||||
merge->ce_mtime = old->ce_mtime;
|
||||
merge->current_mtime = old->ce_mtime.sec;
|
||||
}
|
||||
|
||||
add_entry(o, merge, update, CE_STAGEMASK);
|
||||
@ -998,8 +1002,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
|
||||
|
||||
/* We need timestamp when checking out the file later. */
|
||||
if (old) {
|
||||
ce->ce_ctime = old->ce_ctime;
|
||||
ce->ce_mtime = old->ce_mtime;
|
||||
ce->current_mtime = old->ce_mtime.sec;
|
||||
}
|
||||
|
||||
add_entry(o, ce, CE_REMOVE, CE_STAGEMASK);
|
||||
@ -1101,7 +1104,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
|
||||
if (head) {
|
||||
/* #5ALT, #15 */
|
||||
if (same(head, remote))
|
||||
return merged_entry(head, index, o);
|
||||
return merged_entry(remote, index, o);
|
||||
/* #13, #3ALT */
|
||||
if (!df_conflict_remote && remote_match && !head_match)
|
||||
return merged_entry(head, index, o);
|
||||
@ -1190,8 +1193,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
|
||||
|
||||
/* We need ctime and mtime of index to handle worktree conflict later. */
|
||||
if (head && index) {
|
||||
head->ce_ctime = index->ce_ctime;
|
||||
head->ce_mtime = index->ce_mtime;
|
||||
head->current_mtime = index->ce_mtime.sec;
|
||||
}
|
||||
|
||||
if (head) { count += keep_entry(head, o); }
|
||||
|
@ -316,6 +316,8 @@ vc_compare_commits (const char *repo_id, int version,
|
||||
*/
|
||||
static int
|
||||
diff_parents_with_path (SeafCommit *commit,
|
||||
const char *repo_id,
|
||||
int version,
|
||||
const char *path,
|
||||
const char *file_id,
|
||||
char *parent,
|
||||
@ -355,8 +357,8 @@ diff_parents_with_path (SeafCommit *commit,
|
||||
|
||||
if (!p2) {
|
||||
file_id_p1 = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr,
|
||||
commit->repo_id,
|
||||
commit->version,
|
||||
repo_id,
|
||||
version,
|
||||
p1->root_id, path,
|
||||
NULL,
|
||||
error);
|
||||
@ -368,15 +370,15 @@ diff_parents_with_path (SeafCommit *commit,
|
||||
memcpy (parent, p1->commit_id, 41);
|
||||
} else {
|
||||
file_id_p1 = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr,
|
||||
commit->repo_id,
|
||||
commit->version,
|
||||
repo_id,
|
||||
version,
|
||||
p1->root_id, path,
|
||||
NULL, error);
|
||||
if (*error)
|
||||
goto out;
|
||||
file_id_p2 = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr,
|
||||
commit->repo_id,
|
||||
commit->version,
|
||||
repo_id,
|
||||
version,
|
||||
p2->root_id, path,
|
||||
NULL, error);
|
||||
if (*error)
|
||||
@ -417,30 +419,31 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user who last changed a file.
|
||||
* @head: head commit to start the search.
|
||||
* @path: path of the file.
|
||||
*/
|
||||
char *
|
||||
get_last_changer_of_file (const char *repo_id, int version,
|
||||
const char *head, const char *path)
|
||||
static int
|
||||
get_file_modifier_mtime_v0 (const char *repo_id, int version,
|
||||
const char *head, const char *path,
|
||||
char **modifier, gint64 *mtime)
|
||||
{
|
||||
char commit_id[41];
|
||||
SeafCommit *commit = NULL;
|
||||
char *file_id = NULL;
|
||||
int changed;
|
||||
char *ret = NULL;
|
||||
int ret = 0;
|
||||
GError *error = NULL;
|
||||
|
||||
*modifier = NULL;
|
||||
*mtime = 0;
|
||||
|
||||
memcpy (commit_id, head, 41);
|
||||
|
||||
while (1) {
|
||||
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
repo_id, version,
|
||||
commit_id);
|
||||
if (!commit)
|
||||
if (!commit) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We hit the initial commit. */
|
||||
if (!commit->parent_id)
|
||||
@ -454,21 +457,28 @@ get_last_changer_of_file (const char *repo_id, int version,
|
||||
&error);
|
||||
if (error) {
|
||||
g_clear_error (&error);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
/* We expect commit to have this file. */
|
||||
if (!file_id)
|
||||
if (!file_id) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
changed = diff_parents_with_path (commit, path, file_id,
|
||||
changed = diff_parents_with_path (commit,
|
||||
repo_id, version,
|
||||
path, file_id,
|
||||
commit_id, &error);
|
||||
if (error) {
|
||||
g_clear_error (&error);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
ret = g_strdup (commit->creator_name);
|
||||
*modifier = g_strdup (commit->creator_name);
|
||||
*mtime = commit->ctime;
|
||||
break;
|
||||
} else {
|
||||
/* If this commit doesn't change the file, commit_id will be set
|
||||
@ -485,11 +495,94 @@ get_last_changer_of_file (const char *repo_id, int version,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
get_file_modifier_mtime_v1 (const char *repo_id, int version,
|
||||
const char *head, const char *path,
|
||||
char **modifier, gint64 *mtime)
|
||||
{
|
||||
SeafCommit *commit = NULL;
|
||||
SeafDir *dir = NULL;
|
||||
SeafDirent *dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
commit = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
repo_id, version,
|
||||
head);
|
||||
if (!commit) {
|
||||
seaf_warning ("Failed to get commit %s.\n", head);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *parent = g_path_get_dirname (path);
|
||||
if (strcmp(parent, ".") == 0) {
|
||||
g_free (parent);
|
||||
parent = g_strdup("");
|
||||
}
|
||||
char *filename = g_path_get_basename (path);
|
||||
|
||||
dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr,
|
||||
repo_id, version,
|
||||
commit->root_id,
|
||||
parent, NULL);
|
||||
if (!dir) {
|
||||
seaf_warning ("dir %s doesn't exist in repo %s.\n", parent, repo_id);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
GList *p;
|
||||
for (p = dir->entries; p; p = p->next) {
|
||||
SeafDirent *d = p->data;
|
||||
if (S_ISREG(d->mode) &&
|
||||
strcmp (d->name, filename) == 0) {
|
||||
dent = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dent) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*modifier = g_strdup(dent->modifier);
|
||||
*mtime = dent->mtime;
|
||||
|
||||
out:
|
||||
g_free (parent);
|
||||
g_free (filename);
|
||||
seaf_commit_unref (commit);
|
||||
seaf_dir_free (dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user who last changed a file and the mtime.
|
||||
* @head: head commit to start the search.
|
||||
* @path: path of the file.
|
||||
*/
|
||||
int
|
||||
get_file_modifier_mtime (const char *repo_id, int version,
|
||||
const char *head, const char *path,
|
||||
char **modifier, gint64 *mtime)
|
||||
{
|
||||
if (version > 0)
|
||||
return get_file_modifier_mtime_v1 (repo_id, version,
|
||||
head, path,
|
||||
modifier, mtime);
|
||||
else
|
||||
return get_file_modifier_mtime_v0 (repo_id, version,
|
||||
head, path,
|
||||
modifier, mtime);
|
||||
}
|
||||
|
||||
char *
|
||||
gen_conflict_path (const char *origin_path)
|
||||
gen_conflict_path (const char *origin_path,
|
||||
const char *modifier,
|
||||
gint64 mtime)
|
||||
{
|
||||
char time_buf[64];
|
||||
time_t t = time(NULL);
|
||||
time_t t = (time_t)mtime;
|
||||
char *copy = g_strdup (origin_path);
|
||||
GString *conflict_path = g_string_new (NULL);
|
||||
char *dot, *ext;
|
||||
@ -501,13 +594,28 @@ gen_conflict_path (const char *origin_path)
|
||||
if (dot != NULL) {
|
||||
*dot = '\0';
|
||||
ext = dot + 1;
|
||||
g_string_printf (conflict_path, "%s (%s).%s",
|
||||
copy, time_buf, ext);
|
||||
g_string_printf (conflict_path, "%s (%s %s).%s",
|
||||
copy, modifier, time_buf, ext);
|
||||
} else {
|
||||
g_string_printf (conflict_path, "%s (%s)",
|
||||
copy, time_buf);
|
||||
g_string_printf (conflict_path, "%s (%s %s)",
|
||||
copy, modifier, time_buf);
|
||||
}
|
||||
|
||||
g_free (copy);
|
||||
return g_string_free (conflict_path, FALSE);
|
||||
}
|
||||
|
||||
char *
|
||||
gen_conflict_path_wrapper (const char *repo_id, int version,
|
||||
const char *head, const char *in_repo_path,
|
||||
const char *original_path)
|
||||
{
|
||||
char *modifier;
|
||||
gint64 mtime;
|
||||
|
||||
if (get_file_modifier_mtime (repo_id, version, head, in_repo_path,
|
||||
&modifier, &mtime) < 0)
|
||||
return NULL;
|
||||
|
||||
return gen_conflict_path (original_path, modifier, mtime);
|
||||
}
|
||||
|
@ -33,10 +33,19 @@ vc_compare_commits (const char *repo_id, int version,
|
||||
const char *c1, const char *c2);
|
||||
|
||||
char *
|
||||
gen_conflict_path (const char *origin_path);
|
||||
gen_conflict_path (const char *original_path,
|
||||
const char *modifier,
|
||||
gint64 mtime);
|
||||
|
||||
int
|
||||
get_file_modifier_mtime (const char *repo_id, int version,
|
||||
const char *head, const char *path,
|
||||
char **modifier, gint64 *mtime);
|
||||
|
||||
/* Wrapper around the above two functions */
|
||||
char *
|
||||
get_last_changer_of_file (const char *repo_id, int version,
|
||||
const char *head, const char *path);
|
||||
gen_conflict_path_wrapper (const char *repo_id, int version,
|
||||
const char *head, const char *in_repo_path,
|
||||
const char *original_path);
|
||||
|
||||
#endif
|
||||
|
@ -483,6 +483,7 @@ index_files_job (void *data)
|
||||
CloneTask *task = aux->task;
|
||||
|
||||
if (seaf_repo_index_worktree_files (task->repo_id, task->repo_version,
|
||||
task->email,
|
||||
task->worktree,
|
||||
task->passwd, task->enc_version,
|
||||
task->random_key,
|
||||
@ -1266,7 +1267,7 @@ real_merge (SeafRepo *repo, SeafCommit *head, CloneTask *task)
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
seaf_warning ("Failed to load index.\n");
|
||||
return -1;
|
||||
}
|
||||
@ -1323,7 +1324,7 @@ fast_forward_checkout (SeafRepo *repo, SeafCommit *head, CloneTask *task)
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
seaf_warning ("Failed to load index.\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -30,9 +30,11 @@ struct stage_data
|
||||
struct
|
||||
{
|
||||
unsigned mode;
|
||||
unsigned int ctime;
|
||||
unsigned int mtime;
|
||||
guint64 ctime;
|
||||
guint64 mtime;
|
||||
guint64 current_mtime;
|
||||
unsigned char sha[20];
|
||||
char *modifier;
|
||||
} stages[4];
|
||||
unsigned processed:1;
|
||||
};
|
||||
@ -50,8 +52,11 @@ static void output(struct merge_options *o, const char *fmt, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int add_cacheinfo(struct index_state *index, unsigned int mode, const unsigned char *sha1,
|
||||
const char *path, const char *full_path, int stage, int refresh, int options)
|
||||
static int add_cacheinfo(struct index_state *index,
|
||||
unsigned int mode, const unsigned char *sha1,
|
||||
const char *modifier,
|
||||
const char *path, const char *full_path,
|
||||
int stage, int refresh, int options)
|
||||
{
|
||||
struct cache_entry *ce;
|
||||
ce = make_cache_entry(mode, sha1, path, full_path, stage, refresh);
|
||||
@ -59,6 +64,7 @@ static int add_cacheinfo(struct index_state *index, unsigned int mode, const uns
|
||||
g_warning("addinfo_cache failed for path '%s'", path);
|
||||
return -1;
|
||||
}
|
||||
ce->modifier = g_strdup(modifier);
|
||||
return add_index_entry(index, ce, options);
|
||||
}
|
||||
|
||||
@ -130,6 +136,7 @@ char *write_tree_from_memory(struct merge_options *o)
|
||||
it = cache_tree();
|
||||
|
||||
if (cache_tree_update(o->repo_id, o->version,
|
||||
o->worktree,
|
||||
it, o->index->cache, o->index->cache_nr,
|
||||
0, 0, commit_trees_cb) < 0) {
|
||||
g_warning("error building trees");
|
||||
@ -235,8 +242,10 @@ static GList *get_unmerged(struct index_state *index)
|
||||
|
||||
e->stages[ce_stage(ce)].ctime = ce->ce_ctime.sec;
|
||||
e->stages[ce_stage(ce)].mtime = ce->ce_mtime.sec;
|
||||
e->stages[ce_stage(ce)].current_mtime = ce->current_mtime;
|
||||
e->stages[ce_stage(ce)].mode = ce->ce_mode;
|
||||
hashcpy(e->stages[ce_stage(ce)].sha, ce->sha1);
|
||||
e->stages[ce_stage(ce)].modifier = g_strdup(ce->modifier);
|
||||
}
|
||||
unmerged = g_list_reverse(unmerged);
|
||||
|
||||
@ -304,7 +313,7 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
|
||||
#endif
|
||||
|
||||
static int
|
||||
remove_path (const char *worktree, const char *name, unsigned int ctime, unsigned int mtime)
|
||||
remove_path (const char *worktree, const char *name, guint64 mtime)
|
||||
{
|
||||
char *slash;
|
||||
char *path;
|
||||
@ -320,7 +329,7 @@ remove_path (const char *worktree, const char *name, unsigned int ctime, unsigne
|
||||
|
||||
if (S_ISREG (st.st_mode)) {
|
||||
/* file has been changed. */
|
||||
if (ctime != st.st_ctime || mtime != st.st_mtime) {
|
||||
if (mtime != st.st_mtime) {
|
||||
g_free (path);
|
||||
return -1;
|
||||
}
|
||||
@ -355,7 +364,7 @@ remove_path (const char *worktree, const char *name, unsigned int ctime, unsigne
|
||||
|
||||
static int remove_file(struct merge_options *o, int clean,
|
||||
const char *path, int no_wd,
|
||||
unsigned int ctime, unsigned int mtime)
|
||||
guint64 mtime)
|
||||
{
|
||||
int update_cache = o->call_depth || clean;
|
||||
int update_working_directory = !o->call_depth && !no_wd;
|
||||
@ -368,7 +377,7 @@ static int remove_file(struct merge_options *o, int clean,
|
||||
return -1;
|
||||
}
|
||||
if (update_working_directory) {
|
||||
if (remove_path(o->worktree, path, ctime, mtime) < 0)
|
||||
if (remove_path(o->worktree, path, mtime) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@ -506,6 +515,8 @@ static int make_room_for_path(struct index_state *index, const char *path,
|
||||
static int update_file_flags(struct merge_options *o,
|
||||
const unsigned char *sha,
|
||||
unsigned mode,
|
||||
const char *modifier,
|
||||
guint64 mtime,
|
||||
const char *path,
|
||||
int update_cache,
|
||||
int update_wd)
|
||||
@ -513,7 +524,7 @@ static int update_file_flags(struct merge_options *o,
|
||||
char *real_path;
|
||||
char file_id[41];
|
||||
int clean = 1;
|
||||
int refresh = update_wd;
|
||||
int refresh = 1;
|
||||
|
||||
if (update_wd && o->collect_blocks_only) {
|
||||
fill_seafile_blocks (o->repo_id, o->version, sha, o->bl);
|
||||
@ -544,8 +555,10 @@ static int update_file_flags(struct merge_options *o,
|
||||
if (S_ISDIR (mode)) {
|
||||
if (g_mkdir (real_path, 0777) < 0) {
|
||||
g_warning ("Failed to create empty dir %s in merge.\n", real_path);
|
||||
refresh = 0;
|
||||
}
|
||||
refresh = 0;
|
||||
if (mtime != 0 && seaf_set_file_time (real_path, mtime) < 0)
|
||||
g_warning ("Failed to set mtime for %s.\n", real_path);
|
||||
goto update_cache;
|
||||
}
|
||||
|
||||
@ -566,7 +579,7 @@ static int update_file_flags(struct merge_options *o,
|
||||
return clean;
|
||||
}
|
||||
|
||||
gboolean conflicted;
|
||||
gboolean conflicted = FALSE;
|
||||
rawdata_to_hex(sha, file_id, 20);
|
||||
if (seaf_fs_manager_checkout_file(seaf->fs_mgr,
|
||||
o->repo_id,
|
||||
@ -574,8 +587,10 @@ static int update_file_flags(struct merge_options *o,
|
||||
file_id,
|
||||
real_path,
|
||||
mode,
|
||||
mtime,
|
||||
o->crypt,
|
||||
NULL,
|
||||
o->remote_head,
|
||||
path,
|
||||
FALSE,
|
||||
&conflicted) < 0) {
|
||||
g_warning("Failed to checkout file %s.\n", file_id);
|
||||
@ -586,7 +601,8 @@ static int update_file_flags(struct merge_options *o,
|
||||
|
||||
update_cache:
|
||||
if (update_cache && clean)
|
||||
add_cacheinfo(o->index, mode, sha, path, real_path, 0, refresh, ADD_CACHE_OK_TO_ADD);
|
||||
add_cacheinfo(o->index, mode, sha, modifier,
|
||||
path, real_path, 0, refresh, ADD_CACHE_OK_TO_ADD);
|
||||
g_free(real_path);
|
||||
|
||||
return clean;
|
||||
@ -596,22 +612,28 @@ static int update_file(struct merge_options *o,
|
||||
int clean,
|
||||
const unsigned char *sha,
|
||||
unsigned mode,
|
||||
const char *modifier,
|
||||
guint64 mtime,
|
||||
const char *path)
|
||||
{
|
||||
return update_file_flags(o, sha, mode, path, clean, 1);
|
||||
return update_file_flags(o, sha, mode, modifier, mtime, path, clean, 1);
|
||||
}
|
||||
|
||||
static void handle_delete_modify(struct merge_options *o,
|
||||
const char *path,
|
||||
const char *new_path,
|
||||
unsigned char *a_sha, int a_mode,
|
||||
unsigned char *b_sha, int b_mode)
|
||||
const char *a_modifier,
|
||||
guint64 a_mtime,
|
||||
unsigned char *b_sha, int b_mode,
|
||||
const char *b_modifier,
|
||||
guint64 b_mtime)
|
||||
{
|
||||
/* Only need to checkout other's version if I deleted the file. */
|
||||
if (!a_sha)
|
||||
update_file(o, 1, b_sha, b_mode, new_path);
|
||||
update_file(o, 1, b_sha, b_mode, b_modifier, b_mtime, new_path);
|
||||
else
|
||||
update_file_flags (o, a_sha, a_mode, path, 1, 0);
|
||||
update_file_flags (o, a_sha, a_mode, a_modifier, a_mtime, path, 1, 0);
|
||||
}
|
||||
|
||||
/* Per entry merge function */
|
||||
@ -630,8 +652,11 @@ static int process_entry(struct merge_options *o,
|
||||
unsigned char *o_sha = o_mode ? entry->stages[1].sha : NULL;
|
||||
unsigned char *a_sha = a_mode ? entry->stages[2].sha : NULL;
|
||||
unsigned char *b_sha = b_mode ? entry->stages[3].sha : NULL;
|
||||
unsigned int a_ctime = entry->stages[2].ctime;
|
||||
unsigned int a_mtime = entry->stages[2].mtime;
|
||||
guint64 current_mtime = entry->stages[2].current_mtime;
|
||||
guint64 a_mtime = entry->stages[2].mtime;
|
||||
guint64 b_mtime = entry->stages[3].mtime;
|
||||
char *a_modifier = entry->stages[2].modifier;
|
||||
char *b_modifier = entry->stages[3].modifier;
|
||||
|
||||
/* if (entry->rename_df_conflict_info) */
|
||||
/* return 1; /\* Such cases are handled elsewhere. *\/ */
|
||||
@ -646,7 +671,7 @@ static int process_entry(struct merge_options *o,
|
||||
* unchanged in the other */
|
||||
/* do not touch working file if it did not exist */
|
||||
/* do not remove working file if it's changed. */
|
||||
remove_file(o, 1, path, !a_sha, a_ctime, a_mtime);
|
||||
remove_file(o, 1, path, !a_sha, current_mtime);
|
||||
} else if (g_hash_table_lookup(o->current_directory_set,
|
||||
path)) {
|
||||
/* file -> (file, directory), the file side. */
|
||||
@ -657,7 +682,8 @@ static int process_entry(struct merge_options *o,
|
||||
/* or directory -> (file, directory), directory side */
|
||||
/* Don't consider as unclean. */
|
||||
handle_delete_modify(o, path, path,
|
||||
a_sha, a_mode, b_sha, b_mode);
|
||||
a_sha, a_mode, a_modifier, a_mtime,
|
||||
b_sha, b_mode, b_modifier, b_mtime);
|
||||
}
|
||||
|
||||
} else if ((!o_sha && a_sha && !b_sha) ||
|
||||
@ -671,11 +697,11 @@ static int process_entry(struct merge_options *o,
|
||||
/* Added in one */
|
||||
/* or file -> (file, directory), directory side */
|
||||
if (b_sha)
|
||||
clean_merge = update_file(o, 1, b_sha, b_mode, path);
|
||||
clean_merge = update_file(o, 1, b_sha, b_mode, b_modifier, b_mtime, path);
|
||||
else
|
||||
/* For my file, just set index entry to stage 0,
|
||||
* without updating worktree. */
|
||||
update_file_flags (o, a_sha, a_mode, path, 1, 0);
|
||||
update_file_flags (o, a_sha, a_mode, a_modifier, a_mtime, path, 1, 0);
|
||||
}
|
||||
} else if (a_sha && b_sha) {
|
||||
/* Case C: Added in both (check for same permissions) and */
|
||||
@ -686,22 +712,28 @@ static int process_entry(struct merge_options *o,
|
||||
clean_merge = 0;
|
||||
|
||||
if (!o->collect_blocks_only) {
|
||||
new_path = gen_conflict_path (path);
|
||||
new_path = gen_conflict_path_wrapper (o->repo_id, o->version,
|
||||
o->remote_head, path,
|
||||
path);
|
||||
if (!new_path)
|
||||
new_path = gen_conflict_path(path,
|
||||
o->branch2,
|
||||
(gint64)time(NULL));
|
||||
}
|
||||
|
||||
/* Dont update index. */
|
||||
/* Keep my version, rename other's version. */
|
||||
update_file_flags(o, b_sha, b_mode, new_path, 0, 1);
|
||||
update_file_flags(o, b_sha, b_mode, b_modifier, b_mtime, new_path, 0, 1);
|
||||
g_free (new_path);
|
||||
} else {
|
||||
update_file_flags (o, a_sha, b_mode, path, 1, 0);
|
||||
update_file_flags (o, a_sha, a_mode, a_modifier, a_mtime, path, 1, 0);
|
||||
}
|
||||
} else if (!o_sha && !a_sha && !b_sha) {
|
||||
/*
|
||||
* this entry was deleted altogether. a_mode == 0 means
|
||||
* we had that path and want to actively remove it.
|
||||
*/
|
||||
remove_file(o, 1, path, !a_mode, a_ctime, a_mtime);
|
||||
remove_file(o, 1, path, !a_mode, current_mtime);
|
||||
} else
|
||||
g_error("Fatal merge failure, shouldn't happen.");
|
||||
|
||||
@ -759,6 +791,10 @@ static int process_df_entry(struct merge_options *o,
|
||||
unsigned char *o_sha = o_mode ? entry->stages[1].sha : NULL;
|
||||
unsigned char *a_sha = a_mode ? entry->stages[2].sha : NULL;
|
||||
unsigned char *b_sha = b_mode ? entry->stages[3].sha : NULL;
|
||||
guint64 a_mtime = entry->stages[2].mtime;
|
||||
guint64 b_mtime = entry->stages[3].mtime;
|
||||
char *a_modifier = entry->stages[2].modifier;
|
||||
char *b_modifier = entry->stages[3].modifier;
|
||||
SeafStat st;
|
||||
char *real_path = g_build_path(PATH_SEPERATOR, o->worktree, path, NULL);
|
||||
char *new_path = NULL;
|
||||
@ -772,26 +808,34 @@ static int process_df_entry(struct merge_options *o,
|
||||
clean_merge = 0;
|
||||
|
||||
if (!o->collect_blocks_only) {
|
||||
new_path = gen_conflict_path (path);
|
||||
new_path = gen_conflict_path_wrapper (o->repo_id, o->version,
|
||||
o->remote_head, path,
|
||||
path);
|
||||
if (!new_path)
|
||||
new_path = gen_conflict_path(path,
|
||||
o->branch2,
|
||||
(gint64)time(NULL));
|
||||
}
|
||||
|
||||
update_file(o, 0, b_sha, b_mode, new_path);
|
||||
update_file(o, 0, b_sha, b_mode, b_modifier, b_mtime, new_path);
|
||||
g_free (new_path);
|
||||
} else {
|
||||
/* Modify/Delete conflict. Don't consider as unclean. */
|
||||
update_file(o, 1, b_sha, b_mode, path);
|
||||
update_file(o, 1, b_sha, b_mode, b_modifier, b_mtime, path);
|
||||
}
|
||||
} else {
|
||||
if (seaf_stat (real_path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
clean_merge = 0;
|
||||
} else {
|
||||
/* Clean merge. Just need to update index. */
|
||||
update_file_flags (o, a_sha, a_mode, path, 1, 0);
|
||||
update_file_flags (o, a_sha, a_mode, a_modifier, a_mtime, path, 1, 0);
|
||||
}
|
||||
}
|
||||
} else if (!o_sha && !!a_sha != !!b_sha) {
|
||||
unsigned char *sha = a_sha ? a_sha : b_sha;
|
||||
unsigned mode = a_sha ? a_mode : b_mode;
|
||||
char *modifier = a_sha ? a_modifier : b_modifier;
|
||||
guint64 mtime = a_sha ? a_mtime : b_mtime;
|
||||
|
||||
/* directory -> (directory, empty dir) or
|
||||
* directory -> (empty dir, directory) */
|
||||
@ -802,9 +846,9 @@ static int process_df_entry(struct merge_options *o,
|
||||
if (is_garbage_empty_dir (o->index, path))
|
||||
remove_file_from_index (o->index, path);
|
||||
else if (a_sha)
|
||||
update_file_flags (o, sha, mode, path, 1, 0);
|
||||
update_file_flags (o, sha, mode, modifier, mtime, path, 1, 0);
|
||||
else
|
||||
update_file_flags (o, sha, mode, path, 1, 1);
|
||||
update_file_flags (o, sha, mode, modifier, mtime, path, 1, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -815,21 +859,27 @@ static int process_df_entry(struct merge_options *o,
|
||||
clean_merge = 0;
|
||||
|
||||
if (!o->collect_blocks_only) {
|
||||
new_path = gen_conflict_path (path);
|
||||
new_path = gen_conflict_path_wrapper (o->repo_id, o->version,
|
||||
o->remote_head, path,
|
||||
path);
|
||||
if (!new_path)
|
||||
new_path = gen_conflict_path(path,
|
||||
o->branch2,
|
||||
(gint64)time(NULL));
|
||||
}
|
||||
|
||||
update_file(o, 0, b_sha, b_mode, new_path);
|
||||
update_file(o, 0, b_sha, b_mode, b_modifier, b_mtime, new_path);
|
||||
g_free (new_path);
|
||||
} else {
|
||||
/* Clean merge. */
|
||||
clean_merge = update_file(o, 1, b_sha, b_mode, path);
|
||||
clean_merge = update_file(o, 1, b_sha, b_mode, b_modifier, b_mtime, path);
|
||||
}
|
||||
} else {
|
||||
if (seaf_stat (real_path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
clean_merge = 0;
|
||||
} else {
|
||||
/* Clean merge. Just need to update index. */
|
||||
update_file_flags (o, a_sha, a_mode, path, 1, 0);
|
||||
update_file_flags (o, a_sha, a_mode, a_modifier, a_mtime, path, 1, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -896,6 +946,9 @@ process_unmerged_entries (struct merge_options *o,
|
||||
return 0;
|
||||
}
|
||||
g_free(e->path);
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
g_free (e->stages[i].modifier);
|
||||
free(e);
|
||||
}
|
||||
g_list_free(entries);
|
||||
|
@ -13,6 +13,27 @@
|
||||
#include "vc-utils.h"
|
||||
#include "vc-common.h"
|
||||
|
||||
#if 0
|
||||
static int
|
||||
print_index (struct index_state *istate)
|
||||
{
|
||||
int i;
|
||||
struct cache_entry *ce;
|
||||
char id[41];
|
||||
g_message ("Totally %u entries in index, version %u.\n",
|
||||
istate->cache_nr, istate->version);
|
||||
for (i = 0; i < istate->cache_nr; ++i) {
|
||||
ce = istate->cache[i];
|
||||
rawdata_to_hex (ce->sha1, id, 20);
|
||||
g_message ("%s, %s, %o, %"G_GUINT64_FORMAT", %s, %d\n",
|
||||
ce->name, id, ce->ce_mode,
|
||||
ce->ce_mtime.sec, ce->modifier, ce_stage(ce));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
do_real_merge (SeafRepo *repo,
|
||||
SeafBranch *head_branch,
|
||||
@ -32,7 +53,7 @@ do_real_merge (SeafRepo *repo,
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
*error = g_strdup ("Internal error.\n");
|
||||
return -1;
|
||||
@ -128,7 +149,7 @@ get_common_ancestor_commit (const char *repo_id, int version)
|
||||
|
||||
int
|
||||
merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
|
||||
gboolean *real_merge, gboolean calculate_ca)
|
||||
gboolean *real_merge)
|
||||
{
|
||||
SeafCommit *common = NULL;
|
||||
SeafCommit *head = NULL, *remote = NULL;
|
||||
@ -187,7 +208,7 @@ merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
|
||||
* otherwise we'll use the old method to calculate
|
||||
* common ancestor from local history.
|
||||
*/
|
||||
if (!calculate_ca)
|
||||
if (repo->version > 0)
|
||||
common = get_common_ancestor_commit (repo->id, repo->version);
|
||||
else
|
||||
common = get_merge_base (head, remote);
|
||||
@ -265,7 +286,7 @@ get_new_blocks_ff (SeafRepo *repo,
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
return -1;
|
||||
}
|
||||
@ -319,7 +340,7 @@ get_new_blocks_merge (SeafRepo *repo,
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
return -1;
|
||||
}
|
||||
@ -360,8 +381,7 @@ get_new_blocks_merge (SeafRepo *repo,
|
||||
* otherwise it's set to the block list.
|
||||
*/
|
||||
int
|
||||
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl,
|
||||
gboolean calculate_ca)
|
||||
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl)
|
||||
{
|
||||
SeafCommit *common = NULL;
|
||||
SeafCommit *head = NULL;
|
||||
@ -379,7 +399,7 @@ merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl,
|
||||
* otherwise we'll use the old method to calculate
|
||||
* common ancestor from local history.
|
||||
*/
|
||||
if (!calculate_ca)
|
||||
if (repo->version > 0)
|
||||
common = get_common_ancestor_commit (repo->id, repo->version);
|
||||
else
|
||||
common = get_merge_base (head, remote);
|
||||
|
@ -10,10 +10,9 @@
|
||||
|
||||
int
|
||||
merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
|
||||
gboolean *real_merge, gboolean calculate_ca);
|
||||
gboolean *real_merge);
|
||||
|
||||
int
|
||||
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl,
|
||||
gboolean calculate_ca);
|
||||
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl);
|
||||
|
||||
#endif
|
||||
|
@ -272,7 +272,24 @@ handle_response (CcnetProcessor *processor,
|
||||
return;
|
||||
}
|
||||
|
||||
seaf_message ("protocol version is %d.\n", task->protocol_version);
|
||||
if (task->repo_version == 0)
|
||||
task->protocol_version = 5;
|
||||
else if (task->protocol_version == 5) {
|
||||
/* Syncing version 1 reop with 2.x server is not supported.
|
||||
* Actually version 1 repo can only be created by 3.x servers.
|
||||
* If version 1 repos exist on 2.x server, it means a down-grade
|
||||
* operation has been performed, which is not supported.
|
||||
*/
|
||||
seaf_warning ("Syncing version %d repo with protocol version %d "
|
||||
"is not supported.\n",
|
||||
task->repo_version, task->protocol_version);
|
||||
transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
|
||||
ccnet_processor_done (processor, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
seaf_message ("repo version is %d, protocol version is %d.\n",
|
||||
task->repo_version, task->protocol_version);
|
||||
ccnet_processor_done (processor, TRUE);
|
||||
} else {
|
||||
g_warning ("[check tx v3] Bad response: %s %s", code, code_msg);
|
||||
|
@ -380,12 +380,12 @@ static void
|
||||
fs_object_write_cb (OSAsyncResult *res, void *data)
|
||||
{
|
||||
CcnetProcessor *processor = data;
|
||||
TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task;
|
||||
USE_PRIV;
|
||||
|
||||
if (!res->success) {
|
||||
seaf_warning ("Failed to write object %.8s.\n", res->obj_id);
|
||||
transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task,
|
||||
TASK_ERR_DOWNLOAD_FS);
|
||||
transfer_task_set_error (task, TASK_ERR_DOWNLOAD_FS);
|
||||
ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
|
||||
ccnet_processor_done (processor, FALSE);
|
||||
return;
|
||||
@ -395,7 +395,8 @@ fs_object_write_cb (OSAsyncResult *res, void *data)
|
||||
|
||||
--(priv->pending_objects);
|
||||
|
||||
int type = seaf_metadata_type_from_data (res->data, res->len);
|
||||
int type = seaf_metadata_type_from_data (res->data, res->len,
|
||||
(task->repo_version > 0));
|
||||
if (type == SEAF_METADATA_TYPE_DIR)
|
||||
g_queue_push_tail (priv->inspect_queue, g_strdup(res->obj_id));
|
||||
|
||||
@ -418,7 +419,6 @@ recv_fs_object (CcnetProcessor *processor, char *content, int clen)
|
||||
{
|
||||
USE_PRIV;
|
||||
ObjectPack *pack = (ObjectPack *)content;
|
||||
uint32_t type;
|
||||
/* TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task; */
|
||||
|
||||
if (clen < sizeof(ObjectPack)) {
|
||||
@ -426,27 +426,7 @@ recv_fs_object (CcnetProcessor *processor, char *content, int clen)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
type = seaf_metadata_type_from_data(pack->object, clen);
|
||||
if (type == SEAF_METADATA_TYPE_DIR) {
|
||||
SeafDir *dir;
|
||||
dir = seaf_dir_from_data (pack->id, pack->object, clen - 41);
|
||||
if (!dir) {
|
||||
g_warning ("[getfs] Bad directory object %s.\n", pack->id);
|
||||
goto bad;
|
||||
}
|
||||
seaf_dir_free (dir);
|
||||
} else if (type == SEAF_METADATA_TYPE_FILE) {
|
||||
/* TODO: check seafile format. */
|
||||
#if 0
|
||||
int ret = seafile_check_data_format (pack->object, clen - 41);
|
||||
if (ret < 0) {
|
||||
goto bad;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
g_warning ("[getfs] Invalid object type.\n");
|
||||
goto bad;
|
||||
}
|
||||
/* TODO: check fs object integrity. */
|
||||
|
||||
if (save_fs_object (priv, pack, clen) < 0) {
|
||||
goto bad;
|
||||
|
@ -208,6 +208,29 @@ seaf_repo_set_head (SeafRepo *repo, SeafBranch *branch)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SeafCommit *
|
||||
seaf_repo_get_head_commit (const char *repo_id)
|
||||
{
|
||||
SeafRepo *repo;
|
||||
SeafCommit *head;
|
||||
|
||||
repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
|
||||
if (!repo) {
|
||||
seaf_warning ("Failed to get repo %s.\n", repo_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
head = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
repo_id, repo->version,
|
||||
repo->head->commit_id);
|
||||
if (!head) {
|
||||
seaf_warning ("Failed to get head for repo %s.\n", repo_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void
|
||||
seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
{
|
||||
@ -375,9 +398,11 @@ index_cb (const char *repo_id,
|
||||
SeafileCrypt *crypt,
|
||||
gboolean write_data)
|
||||
{
|
||||
gint64 size;
|
||||
|
||||
/* Check in blocks and get object ID. */
|
||||
if (seaf_fs_manager_index_blocks (seaf->fs_mgr, repo_id, version,
|
||||
path, sha1, crypt, write_data) < 0) {
|
||||
path, sha1, &size, crypt, write_data) < 0) {
|
||||
g_warning ("Failed to index file %s.\n", path);
|
||||
return -1;
|
||||
}
|
||||
@ -387,6 +412,7 @@ index_cb (const char *repo_id,
|
||||
static int
|
||||
add_recursive (const char *repo_id,
|
||||
int version,
|
||||
const char *modifier,
|
||||
struct index_state *istate,
|
||||
const char *worktree,
|
||||
const char *path,
|
||||
@ -418,7 +444,7 @@ add_recursive (const char *repo_id,
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
ret = add_to_index (repo_id, version, istate, path, full_path,
|
||||
&st, 0, crypt, index_cb);
|
||||
&st, 0, crypt, index_cb, modifier);
|
||||
g_free (full_path);
|
||||
return ret;
|
||||
}
|
||||
@ -444,7 +470,8 @@ add_recursive (const char *repo_id,
|
||||
#else
|
||||
subpath = g_build_path (PATH_SEPERATOR, path, dname, NULL);
|
||||
#endif
|
||||
ret = add_recursive (repo_id, version, istate, worktree, subpath,
|
||||
ret = add_recursive (repo_id, version, modifier,
|
||||
istate, worktree, subpath,
|
||||
crypt, ignore_empty_dir, ignore_list);
|
||||
g_free (subpath);
|
||||
if (ret < 0)
|
||||
@ -513,15 +540,15 @@ remove_deleted (struct index_state *istate, const char *worktree,
|
||||
if (S_ISDIR (ce->ce_mode)) {
|
||||
if ((ret < 0 || !S_ISDIR (st.st_mode)
|
||||
|| !is_empty_dir (path, ignore_list)) &&
|
||||
(ce->ce_mtime.sec != 0 || ce_stage(ce) != 0))
|
||||
(ce->ce_ctime.sec != 0 || ce_stage(ce) != 0))
|
||||
ce->ce_flags |= CE_REMOVE;
|
||||
} else {
|
||||
/* If ce->mtime is 0 and stage is 0, it was not successfully checked out.
|
||||
/* If ce->ctime is 0 and stage is 0, it was not successfully checked out.
|
||||
* In this case we don't want to mistakenly remove the file
|
||||
* from the repo.
|
||||
*/
|
||||
if ((ret < 0 || !S_ISREG (st.st_mode)) &&
|
||||
(ce->ce_mtime.sec != 0 || ce_stage(ce) != 0))
|
||||
(ce->ce_ctime.sec != 0 || ce_stage(ce) != 0))
|
||||
ce_array[i]->ce_flags |= CE_REMOVE;
|
||||
}
|
||||
}
|
||||
@ -545,7 +572,7 @@ index_add (SeafRepo *repo, struct index_state *istate, const char *path)
|
||||
|
||||
ignore_list = seaf_repo_load_ignore_files (repo->worktree);
|
||||
|
||||
if (add_recursive (repo->id, repo->version,
|
||||
if (add_recursive (repo->id, repo->version, repo->email,
|
||||
istate, repo->worktree, path, crypt, FALSE, ignore_list) < 0)
|
||||
goto error;
|
||||
|
||||
@ -568,6 +595,7 @@ error:
|
||||
int
|
||||
seaf_repo_index_worktree_files (const char *repo_id,
|
||||
int repo_version,
|
||||
const char *modifier,
|
||||
const char *worktree,
|
||||
const char *passwd,
|
||||
int enc_version,
|
||||
@ -590,7 +618,7 @@ seaf_repo_index_worktree_files (const char *repo_id,
|
||||
*/
|
||||
g_unlink (index_path);
|
||||
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo_version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
return -1;
|
||||
}
|
||||
@ -609,14 +637,14 @@ seaf_repo_index_worktree_files (const char *repo_id,
|
||||
/* Add empty dir to index. Otherwise if the repo on relay contains an empty
|
||||
* dir, we'll fail to detect fast-forward relationship later.
|
||||
*/
|
||||
if (add_recursive (repo_id, repo_version,
|
||||
if (add_recursive (repo_id, repo_version, modifier,
|
||||
&istate, worktree, "", crypt, FALSE, ignore_list) < 0)
|
||||
goto error;
|
||||
|
||||
remove_deleted (&istate, worktree, "", ignore_list);
|
||||
|
||||
it = cache_tree ();
|
||||
if (cache_tree_update (repo_id, repo_version,
|
||||
if (cache_tree_update (repo_id, repo_version, worktree,
|
||||
it, istate.cache, istate.cache_nr,
|
||||
0, 0, commit_trees_cb) < 0) {
|
||||
g_warning ("Failed to build cache tree");
|
||||
@ -663,7 +691,7 @@ seaf_repo_is_worktree_changed (SeafRepo *repo)
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
repo->index_corrupted = TRUE;
|
||||
g_warning ("Failed to load index.\n");
|
||||
goto error;
|
||||
@ -712,7 +740,7 @@ changed:
|
||||
ce = istate.cache[pos];
|
||||
|
||||
g_message ("type: %c, status: %c, name: %s, "
|
||||
"ce mtime: %d, ce size: %" G_GUINT64_FORMAT ", "
|
||||
"ce mtime: %"G_GINT64_FORMAT", ce size: %" G_GUINT64_FORMAT ", "
|
||||
"file mtime: %d, file size: %" G_GUINT64_FORMAT "\n",
|
||||
de->type, de->status, de->name,
|
||||
ce->ce_mtime.sec, ce->ce_size, (int)sb.st_mtime, sb.st_size);
|
||||
@ -780,7 +808,7 @@ seaf_repo_is_index_unmerged (SeafRepo *repo)
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
return FALSE;
|
||||
}
|
||||
@ -859,6 +887,27 @@ need_handle_unmerged_index (SeafRepo *repo, struct index_state *istate)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
print_index (struct index_state *istate)
|
||||
{
|
||||
int i;
|
||||
struct cache_entry *ce;
|
||||
char id[41];
|
||||
seaf_message ("Totally %u entries in index, version %u.\n",
|
||||
istate->cache_nr, istate->version);
|
||||
for (i = 0; i < istate->cache_nr; ++i) {
|
||||
ce = istate->cache[i];
|
||||
rawdata_to_hex (ce->sha1, id, 20);
|
||||
seaf_message ("%s, %s, %o, %"G_GINT64_FORMAT", %s, %"G_GINT64_FORMAT"\n",
|
||||
ce->name, id, ce->ce_mode,
|
||||
ce->ce_mtime.sec, ce->modifier, ce->ce_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
seaf_repo_index_commit (SeafRepo *repo, const char *desc, GError **error)
|
||||
{
|
||||
@ -874,7 +923,7 @@ seaf_repo_index_commit (SeafRepo *repo, const char *desc, GError **error)
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "Internal data structure error");
|
||||
return NULL;
|
||||
@ -908,7 +957,9 @@ seaf_repo_index_commit (SeafRepo *repo, const char *desc, GError **error)
|
||||
}
|
||||
|
||||
it = cache_tree ();
|
||||
if (cache_tree_update (repo->id, repo->version, it, istate.cache,
|
||||
if (cache_tree_update (repo->id, repo->version,
|
||||
repo->worktree,
|
||||
it, istate.cache,
|
||||
istate.cache_nr, 0, 0, commit_trees_cb) < 0) {
|
||||
g_warning ("Failed to build cache tree");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "Internal data structure error");
|
||||
@ -993,7 +1044,7 @@ seaf_repo_checkout_commit (SeafRepo *repo, SeafCommit *commit, gboolean recover_
|
||||
|
||||
memset (&istate, 0, sizeof(istate));
|
||||
snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
|
||||
if (read_index_from (&istate, index_path) < 0) {
|
||||
if (read_index_from (&istate, index_path, repo->version) < 0) {
|
||||
g_warning ("Failed to load index.\n");
|
||||
return -1;
|
||||
}
|
||||
@ -1180,7 +1231,7 @@ error:
|
||||
|
||||
int
|
||||
seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
|
||||
gboolean *real_merge, gboolean calculate_ca)
|
||||
gboolean *real_merge)
|
||||
{
|
||||
SeafBranch *remote_branch;
|
||||
int ret = 0;
|
||||
@ -1202,7 +1253,7 @@ seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = merge_branches (repo, remote_branch, error, real_merge, calculate_ca);
|
||||
ret = merge_branches (repo, remote_branch, error, real_merge);
|
||||
seaf_branch_unref (remote_branch);
|
||||
|
||||
return ret;
|
||||
|
@ -85,6 +85,9 @@ seaf_repo_free (SeafRepo *repo);
|
||||
int
|
||||
seaf_repo_set_head (SeafRepo *repo, SeafBranch *branch);
|
||||
|
||||
SeafCommit *
|
||||
seaf_repo_get_head_commit (const char *repo_id);
|
||||
|
||||
int
|
||||
seaf_repo_checkdir (SeafRepo *repo);
|
||||
|
||||
@ -111,6 +114,7 @@ seaf_repo_index_add (SeafRepo *repo, const char *path);
|
||||
int
|
||||
seaf_repo_index_worktree_files (const char *repo_id,
|
||||
int version,
|
||||
const char *modifier,
|
||||
const char *worktree,
|
||||
const char *passwd,
|
||||
int enc_version,
|
||||
@ -147,7 +151,7 @@ seaf_repo_checkout_commit (SeafRepo *repo, SeafCommit *commit, gboolean recover_
|
||||
|
||||
int
|
||||
seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
|
||||
gboolean *real_merge, gboolean calculate_ca);
|
||||
gboolean *real_merge);
|
||||
|
||||
GList *
|
||||
seaf_repo_diff (SeafRepo *repo, const char *arg1, const char *arg2, char **error);
|
||||
|
@ -264,7 +264,7 @@ void wt_status_collect_changes_worktree(struct index_state *index,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ce->ce_mtime.sec == 0) {
|
||||
if (ce->ce_ctime.sec == 0) {
|
||||
g_free (realpath);
|
||||
continue;
|
||||
}
|
||||
|
@ -512,6 +512,7 @@ static const char *sync_error_str[] = {
|
||||
"Failed to index files.",
|
||||
"Conflict in merge.",
|
||||
"Files changed in local folder, skip merge.",
|
||||
"Server version is too old.",
|
||||
"Unknown error.",
|
||||
};
|
||||
|
||||
@ -673,8 +674,7 @@ merge_job (void *vtask)
|
||||
* For 2 and 4, the errors are ignored by the merge routine (return 0).
|
||||
* For 3, just wait another merge retry.
|
||||
* */
|
||||
if (seaf_repo_merge (repo, "master", &err_msg, &res->real_merge,
|
||||
task->calculate_ca) < 0) {
|
||||
if (seaf_repo_merge (repo, "master", &err_msg, &res->real_merge) < 0) {
|
||||
seaf_message ("[Sync mgr] Merge of repo %s(%.8s) is not clean.\n",
|
||||
repo->name, repo->id);
|
||||
res->success = FALSE;
|
||||
@ -858,12 +858,9 @@ getca_done_cb (CcnetProcessor *processor, gboolean success, void *data)
|
||||
if (!success) {
|
||||
switch (processor->failure) {
|
||||
case PROC_NO_SERVICE:
|
||||
/* If the server doesn't provide this processor, it's running the
|
||||
* old protocol. We can then assume all commits will be downloaded.
|
||||
*/
|
||||
seaf_debug ("Server doesn't support putca-proc.\n");
|
||||
task->calculate_ca = TRUE;
|
||||
goto continue_sync;
|
||||
seaf_warning ("Server doesn't support putca-proc.\n");
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_DEPRECATED_SERVER);
|
||||
break;
|
||||
case GETCA_PROC_ACCESS_DENIED:
|
||||
seaf_warning ("No permission to access repo %.8s.\n", repo->id);
|
||||
seaf_sync_manager_set_task_error (task, SYNC_ERROR_ACCESS_DENIED);
|
||||
@ -894,7 +891,6 @@ getca_done_cb (CcnetProcessor *processor, gboolean success, void *data)
|
||||
proc->ca_id,
|
||||
repo->head->commit_id);
|
||||
|
||||
continue_sync:
|
||||
master = seaf_branch_manager_get_branch (seaf->branch_mgr,
|
||||
info->repo_id,
|
||||
"master");
|
||||
@ -1069,8 +1065,11 @@ update_sync_status (SyncTask *task)
|
||||
* The last result of computation is cached in local db.
|
||||
* Check if we need to re-compute the common ancestor.
|
||||
* If so we'll start a processor to do that on the server.
|
||||
* For repo version == 0, we download all commits so there is no
|
||||
* need to check.
|
||||
*/
|
||||
if (update_common_ancestor (task, last_uploaded, last_checkout))
|
||||
if (repo->version > 0 &&
|
||||
update_common_ancestor (task, last_uploaded, last_checkout))
|
||||
goto out;
|
||||
|
||||
if (!master || strcmp (info->head_commit, master->commit_id) != 0) {
|
||||
|
@ -61,6 +61,7 @@ enum {
|
||||
SYNC_ERROR_MERGE,
|
||||
SYNC_ERROR_WORKTREE_DIRTY,
|
||||
SYNC_ERROR_UNKNOWN,
|
||||
SYNC_ERROR_DEPRECATED_SERVER,
|
||||
SYNC_ERROR_NUM,
|
||||
};
|
||||
|
||||
@ -78,7 +79,6 @@ struct _SyncTask {
|
||||
char *token;
|
||||
struct CcnetTimer *commit_timer;
|
||||
struct CcnetTimer *conn_timer;
|
||||
gboolean calculate_ca; /* need calculate common ancestor from history */
|
||||
|
||||
SeafRepo *repo; /* for convenience, only valid when in_sync. */
|
||||
};
|
||||
|
@ -404,8 +404,7 @@ seaf_transfer_task_load_blocklist (TransferTask *task)
|
||||
if (!task->is_clone) {
|
||||
/* If we're merging, only get new blocks that need to be checked out.
|
||||
*/
|
||||
gboolean calculate_ca = (task->protocol_version < 6);
|
||||
if (merge_get_new_block_list (repo, remote, &bl, calculate_ca) < 0) {
|
||||
if (merge_get_new_block_list (repo, remote, &bl) < 0) {
|
||||
seaf_warning ("[tr-mgr] Failed to get new blocks for merge.\n");
|
||||
seaf_commit_unref (remote);
|
||||
return -1;
|
||||
|
@ -27,16 +27,17 @@ compare_dirents (gconstpointer a, gconstpointer b)
|
||||
|
||||
int
|
||||
commit_trees_cb (const char *repo_id, int version,
|
||||
const char *worktree,
|
||||
struct cache_tree *it, struct cache_entry **cache,
|
||||
int entries, const char *base, int baselen)
|
||||
{
|
||||
SeafDir *seaf_dir;
|
||||
GList *dirents = NULL;
|
||||
GList *dirents = NULL, *ptr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
SeafDirent *seaf_dent;
|
||||
char *dirname;
|
||||
char *name;
|
||||
struct cache_entry *ce = cache[i];
|
||||
struct cache_tree_sub *sub;
|
||||
const char *path, *slash;
|
||||
@ -44,6 +45,9 @@ commit_trees_cb (const char *repo_id, int version,
|
||||
const unsigned char *sha1;
|
||||
char hex[41];
|
||||
unsigned mode;
|
||||
guint64 mtime;
|
||||
gint64 size;
|
||||
char *modifier;
|
||||
|
||||
if (ce->ce_flags & CE_REMOVE)
|
||||
continue; /* entry being removed */
|
||||
@ -62,23 +66,35 @@ commit_trees_cb (const char *repo_id, int version,
|
||||
i += sub->cache_tree->entry_count - 1;
|
||||
|
||||
sha1 = sub->cache_tree->sha1;
|
||||
mtime = sub->cache_tree->mtime;
|
||||
mode = S_IFDIR;
|
||||
dirname = g_strndup(path + baselen, entlen);
|
||||
name = g_strndup(path + baselen, entlen);
|
||||
|
||||
rawdata_to_hex (sha1, hex, 20);
|
||||
seaf_dent = seaf_dirent_new (hex, mode, dirname);
|
||||
g_free(dirname);
|
||||
seaf_dent = seaf_dirent_new (dir_version_from_repo_version(version),
|
||||
hex, mode, name, mtime, NULL, -1);
|
||||
g_free(name);
|
||||
|
||||
dirents = g_list_prepend (dirents, seaf_dent);
|
||||
} else {
|
||||
sha1 = ce->sha1;
|
||||
mode = ce->ce_mode;
|
||||
mtime = ce->ce_mtime.sec;
|
||||
size = ce->ce_size;
|
||||
modifier = ce->modifier;
|
||||
entlen = pathlen - baselen;
|
||||
|
||||
dirname = g_strndup(path + baselen, entlen);
|
||||
name = g_strndup(path + baselen, entlen);
|
||||
rawdata_to_hex (sha1, hex, 20);
|
||||
seaf_dent = seaf_dirent_new (hex, mode, dirname);
|
||||
g_free(dirname);
|
||||
|
||||
if (version > 0) {
|
||||
seaf_dent =
|
||||
seaf_dirent_new (dir_version_from_repo_version(version),
|
||||
hex, mode, name, mtime, modifier, size);
|
||||
} else {
|
||||
seaf_dent = seaf_dirent_new (0, hex, mode, name, 0, NULL, -1);
|
||||
}
|
||||
|
||||
g_free(name);
|
||||
|
||||
dirents = g_list_prepend (dirents, seaf_dent);
|
||||
}
|
||||
@ -92,10 +108,23 @@ commit_trees_cb (const char *repo_id, int version,
|
||||
/* Sort dirents in descending order. */
|
||||
dirents = g_list_sort (dirents, compare_dirents);
|
||||
|
||||
seaf_dir = seaf_dir_new (NULL, dirents, 0);
|
||||
seaf_dir = seaf_dir_new (NULL, dirents, dir_version_from_repo_version(version));
|
||||
hex_to_rawdata (seaf_dir->dir_id, it->sha1, 20);
|
||||
|
||||
seaf_dir_save (seaf->fs_mgr, repo_id, version, seaf_dir);
|
||||
/* Dir's mtime is the latest of all dir entires. */
|
||||
guint64 dir_mtime = 0;
|
||||
SeafDirent *dent;
|
||||
for (ptr = dirents; ptr; ptr = ptr->next) {
|
||||
dent = ptr->data;
|
||||
if (dent->mtime > dir_mtime)
|
||||
dir_mtime = dent->mtime;
|
||||
}
|
||||
it->mtime = dir_mtime;
|
||||
|
||||
if (!seaf_fs_manager_object_exists (seaf->fs_mgr,
|
||||
repo_id, version,
|
||||
seaf_dir->dir_id))
|
||||
seaf_dir_save (seaf->fs_mgr, repo_id, version, seaf_dir);
|
||||
|
||||
#if DEBUG
|
||||
for (p = dirents; p; p = p->next) {
|
||||
@ -187,7 +216,7 @@ unlink_entry (struct cache_entry *ce, struct unpack_trees_options *o)
|
||||
|
||||
/* file has been changed. */
|
||||
if (!o->reset &&
|
||||
(ce->ce_ctime.sec != st.st_ctime || ce->ce_mtime.sec != st.st_mtime)) {
|
||||
(ce->current_mtime != st.st_mtime)) {
|
||||
g_warning ("File %s is changed. Skip removing the file.\n", path);
|
||||
return -1;
|
||||
}
|
||||
@ -509,7 +538,7 @@ static int
|
||||
checkout_entry (struct cache_entry *ce,
|
||||
struct unpack_trees_options *o,
|
||||
gboolean recover_merge,
|
||||
const char *conflict_suffix,
|
||||
const char *conflict_head_id,
|
||||
GHashTable *conflict_hash,
|
||||
GHashTable *no_conflict_hash)
|
||||
{
|
||||
@ -548,11 +577,15 @@ checkout_entry (struct cache_entry *ce,
|
||||
g_free (path);
|
||||
return -1;
|
||||
}
|
||||
if (ce->ce_mtime.sec != 0 &&
|
||||
seaf_set_file_time (path, ce->ce_mtime.sec) < 0) {
|
||||
g_warning ("Failed to set mtime for %s.\n", path);
|
||||
}
|
||||
goto update_cache;
|
||||
}
|
||||
|
||||
if (!o->reset && seaf_stat (path, &st) == 0 && S_ISREG(st.st_mode) &&
|
||||
(ce->ce_ctime.sec != st.st_ctime || ce->ce_mtime.sec != st.st_mtime))
|
||||
(ce->current_mtime != st.st_mtime))
|
||||
{
|
||||
/* If we're recovering an interrupted merge, we don't know whether
|
||||
* the file was changed by checkout or by the user. So we have to
|
||||
@ -579,9 +612,12 @@ checkout_entry (struct cache_entry *ce,
|
||||
o->repo_id,
|
||||
o->version,
|
||||
file_id,
|
||||
path, ce->ce_mode,
|
||||
path,
|
||||
ce->ce_mode,
|
||||
ce->ce_mtime.sec,
|
||||
o->crypt,
|
||||
conflict_suffix,
|
||||
ce->name,
|
||||
conflict_head_id,
|
||||
force_conflict,
|
||||
&conflicted) < 0) {
|
||||
g_warning ("Failed to checkout file %s.\n", path);
|
||||
@ -645,7 +681,7 @@ update_worktree (struct unpack_trees_options *o,
|
||||
ce = result->cache[i];
|
||||
if (ce->ce_flags & CE_UPDATE) {
|
||||
errs |= checkout_entry (ce, o, recover_merge,
|
||||
NULL,
|
||||
conflict_head_id,
|
||||
conflict_hash, no_conflict_hash);
|
||||
}
|
||||
if (finished_entries)
|
||||
|
@ -21,6 +21,7 @@ static inline int readlink(const char *path, char *buf, size_t bufsiz)
|
||||
|
||||
int
|
||||
commit_trees_cb (const char *repo_id, int version,
|
||||
const char *modifier,
|
||||
struct cache_tree *it, struct cache_entry **cache,
|
||||
int entries, const char *base, int baselen);
|
||||
|
||||
|
@ -13,6 +13,7 @@ namespace Seafile {
|
||||
}
|
||||
|
||||
public List<Dirent> entries;
|
||||
public int version { set; get; }
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -11,6 +11,10 @@ public class Dirent : Object {
|
||||
public string obj_name { set; get; }
|
||||
|
||||
public int mode { set; get; }
|
||||
|
||||
public int version { set; get; }
|
||||
public int64 mtime { set; get; }
|
||||
public int64 size { set; get; }
|
||||
}
|
||||
|
||||
public class FileLastModifiedInfo : Object {
|
||||
|
@ -144,7 +144,7 @@ id_from_pubkey (RSA *pubkey)
|
||||
char *id = g_malloc(41);
|
||||
|
||||
buf = public_key_to_gstring (pubkey);
|
||||
calculate_sha1 (sha1, buf->str);
|
||||
calculate_sha1 (sha1, buf->str, -1);
|
||||
sha1_to_hex (sha1, id);
|
||||
g_string_free (buf, TRUE);
|
||||
|
||||
|
79
lib/utils.c
79
lib/utils.c
@ -42,6 +42,8 @@
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <utime.h>
|
||||
|
||||
extern int inet_pton(int af, const char *src, void *dst);
|
||||
|
||||
|
||||
@ -261,6 +263,48 @@ get_utc_file_time_fd (int fd, __time64_t *mtime, __time64_t *ctime)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EPOCH_DIFF 11644473600ULL
|
||||
|
||||
inline static void
|
||||
unix_time_to_file_time (guint64 unix_time, FILETIME *ftime)
|
||||
{
|
||||
guint64 win_time;
|
||||
|
||||
win_time = (unix_time + EPOCH_DIFF) * 10000000;
|
||||
ftime->dwLowDateTime = win_time & 0xFFFFFFFF;
|
||||
ftime->dwHighDateTime = (win_time >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static int
|
||||
set_utc_file_time (const char *path, const wchar_t *wpath, guint64 mtime)
|
||||
{
|
||||
HANDLE handle;
|
||||
FILETIME write_time;
|
||||
|
||||
handle = CreateFileW (wpath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
g_warning ("Failed to open %s: %lu.\n", path, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
unix_time_to_file_time (mtime, &write_time);
|
||||
|
||||
if (!SetFileTime (handle, NULL, NULL, &write_time)) {
|
||||
g_warning ("Failed to set file time for %s: %lu.\n", path, GetLastError());
|
||||
CloseHandle (handle);
|
||||
return -1;
|
||||
}
|
||||
CloseHandle (handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
@ -302,6 +346,34 @@ seaf_fstat (int fd, SeafStat *st)
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
seaf_set_file_time (const char *path, guint64 mtime)
|
||||
{
|
||||
#ifndef WIN32
|
||||
struct stat st;
|
||||
struct utimbuf times;
|
||||
|
||||
if (stat (path, &st) < 0) {
|
||||
g_warning ("Failed to stat %s: %s.\n", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
times.actime = st.st_atime;
|
||||
times.modtime = (time_t)mtime;
|
||||
|
||||
return utime (path, ×);
|
||||
#else
|
||||
wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
|
||||
int ret = 0;
|
||||
|
||||
if (set_utc_file_time (path, wpath, mtime) < 0)
|
||||
ret = -1;
|
||||
|
||||
g_free (wpath);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t /* Read "n" bytes from a descriptor. */
|
||||
readn(int fd, void *vptr, size_t n)
|
||||
{
|
||||
@ -562,12 +634,15 @@ ccnet_expand_path (const char *src)
|
||||
|
||||
|
||||
int
|
||||
calculate_sha1 (unsigned char *sha1, const char *msg)
|
||||
calculate_sha1 (unsigned char *sha1, const char *msg, int len)
|
||||
{
|
||||
SHA_CTX c;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(msg);
|
||||
|
||||
SHA1_Init(&c);
|
||||
SHA1_Update(&c, msg, strlen(msg));
|
||||
SHA1_Update(&c, msg, len);
|
||||
SHA1_Final(sha1, &c);
|
||||
return 0;
|
||||
}
|
||||
|
@ -77,6 +77,8 @@ static inline int ccnet_rename(const char *oldfile, const char *newfile)
|
||||
int seaf_stat (const char *path, SeafStat *st);
|
||||
int seaf_fstat (int fd, SeafStat *st);
|
||||
|
||||
int seaf_set_file_time (const char *path, guint64 mtime);
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
@ -108,7 +110,8 @@ int hex_to_rawdata (const char *hex_str, unsigned char *rawdata, int n_bytes);
|
||||
#define sha1_to_hex(sha1, hex) rawdata_to_hex((sha1), (hex), 20)
|
||||
#define hex_to_sha1(hex, sha1) hex_to_rawdata((hex), (sha1), 20)
|
||||
|
||||
int calculate_sha1 (unsigned char *sha1, const char *msg);
|
||||
/* If msg is NULL-terminated, set len to -1 */
|
||||
int calculate_sha1 (unsigned char *sha1, const char *msg, int len);
|
||||
int ccnet_sha1_equal (const void *v1, const void *v2);
|
||||
unsigned int ccnet_sha1_hash (const void *v);
|
||||
|
||||
|
@ -68,6 +68,7 @@ typedef struct {
|
||||
char *session_key;
|
||||
char *peer_addr;
|
||||
char *peer_name;
|
||||
int client_version;
|
||||
|
||||
char *rsp_code;
|
||||
char *rsp_msg;
|
||||
@ -212,13 +213,24 @@ check_tx (void *vprocessor)
|
||||
|
||||
char *user = NULL;
|
||||
char *repo_id = priv->repo_id;
|
||||
SeafRepo *repo = NULL;
|
||||
|
||||
if (!seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id)) {
|
||||
repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
|
||||
if (!repo) {
|
||||
priv->rsp_code = g_strdup(SC_BAD_REPO);
|
||||
priv->rsp_msg = g_strdup(SS_BAD_REPO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (repo->version > 0 && priv->client_version < 6) {
|
||||
seaf_warning ("Client protocol version is %d, "
|
||||
"cannot sync version %d repo %s.\n",
|
||||
prov->client_version, repo->version, repo_id);
|
||||
priv->rsp_code = g_strdup(SC_PROTOCOL_MISMATCH);
|
||||
priv->rsp_msg = g_strdup(SS_PROTOCOL_MISMATCH);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (decrypt_token (processor) < 0) {
|
||||
priv->rsp_code = g_strdup(SC_ACCESS_DENIED);
|
||||
priv->rsp_msg = g_strdup(SS_ACCESS_DENIED);
|
||||
@ -272,6 +284,7 @@ check_tx (void *vprocessor)
|
||||
get_branch_head (processor);
|
||||
|
||||
out:
|
||||
seaf_repo_unref (repo);
|
||||
g_free (user);
|
||||
return vprocessor;
|
||||
}
|
||||
@ -351,6 +364,7 @@ start (CcnetProcessor *processor, int argc, char **argv)
|
||||
priv->branch_name = g_strdup(branch_name);
|
||||
|
||||
priv->token = g_strdup(token);
|
||||
priv->client_version = client_version;
|
||||
|
||||
CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, processor->peer_id);
|
||||
if (!peer || !peer->session_key) {
|
||||
|
@ -228,7 +228,8 @@ on_seafdir_read (OSAsyncResult *res, void *cb_data)
|
||||
seaf_debug ("[recvfs] Read seafdir %s.\n", res->obj_id);
|
||||
#endif
|
||||
|
||||
dir = seaf_dir_from_data (res->obj_id, res->data, res->len);
|
||||
dir = seaf_dir_from_data (res->obj_id, res->data, res->len,
|
||||
(priv->repo_version > 0));
|
||||
if (!dir) {
|
||||
g_warning ("[recvfs] Corrupt dir object %s.\n", res->obj_id);
|
||||
request_object_batch (processor, priv, res->obj_id);
|
||||
@ -435,7 +436,7 @@ recv_fs_object (CcnetProcessor *processor, char *content, int clen)
|
||||
{
|
||||
USE_PRIV;
|
||||
ObjectPack *pack = (ObjectPack *)content;
|
||||
uint32_t type;
|
||||
SeafFSObject *fs_obj = NULL;
|
||||
|
||||
if (clen < sizeof(ObjectPack)) {
|
||||
g_warning ("invalid object id.\n");
|
||||
@ -446,19 +447,20 @@ recv_fs_object (CcnetProcessor *processor, char *content, int clen)
|
||||
|
||||
--priv->pending_objects;
|
||||
|
||||
type = seaf_metadata_type_from_data(pack->object, clen);
|
||||
if (type == SEAF_METADATA_TYPE_DIR) {
|
||||
SeafDir *dir;
|
||||
dir = seaf_dir_from_data (pack->id, pack->object, clen - 41);
|
||||
if (!dir) {
|
||||
g_warning ("Bad directory object %s.\n", pack->id);
|
||||
goto bad;
|
||||
}
|
||||
fs_obj = seaf_fs_object_from_data(pack->id,
|
||||
pack->object, clen - sizeof(ObjectPack),
|
||||
(priv->repo_version > 0));
|
||||
if (!fs_obj) {
|
||||
g_warning ("Bad fs object %s.\n", pack->id);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (fs_obj->type == SEAF_METADATA_TYPE_DIR) {
|
||||
SeafDir *dir = (SeafDir *)fs_obj;
|
||||
int ret = check_seafdir (processor, dir);
|
||||
seaf_dir_free (dir);
|
||||
if (ret < 0)
|
||||
goto bad;
|
||||
} else if (type == SEAF_METADATA_TYPE_FILE) {
|
||||
} else if (fs_obj->type == SEAF_METADATA_TYPE_FILE) {
|
||||
/* TODO: check seafile format. */
|
||||
#if 0
|
||||
int ret = seafile_check_data_format (pack->object, clen - 41);
|
||||
@ -466,11 +468,10 @@ recv_fs_object (CcnetProcessor *processor, char *content, int clen)
|
||||
goto bad;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
g_warning ("Invalid object type.\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
seaf_fs_object_free (fs_obj);
|
||||
|
||||
if (save_fs_object (processor, pack, clen) < 0) {
|
||||
goto bad;
|
||||
}
|
||||
@ -483,6 +484,8 @@ bad:
|
||||
g_warning ("[recvfs] Bad fs object received.\n");
|
||||
ccnet_processor_done (processor, FALSE);
|
||||
|
||||
seaf_fs_object_free (fs_obj);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
270
server/repo-op.c
270
server/repo-op.c
@ -49,12 +49,6 @@ compare_dirents (gconstpointer a, gconstpointer b)
|
||||
return strcmp (ent_b->name, ent_a->name);
|
||||
}
|
||||
|
||||
static inline SeafDirent *
|
||||
dup_seaf_dirent (const SeafDirent *dent)
|
||||
{
|
||||
return seaf_dirent_new (dent->id, dent->mode, dent->name);
|
||||
}
|
||||
|
||||
static inline GList *
|
||||
dup_seafdir_entries (const GList *entries)
|
||||
{
|
||||
@ -64,7 +58,7 @@ dup_seafdir_entries (const GList *entries)
|
||||
|
||||
for (p = entries; p; p = p->next) {
|
||||
dent = p->data;
|
||||
newentries = g_list_prepend (newentries, dup_seaf_dirent(dent));
|
||||
newentries = g_list_prepend (newentries, seaf_dirent_dup(dent));
|
||||
}
|
||||
|
||||
return g_list_reverse(newentries);
|
||||
@ -160,7 +154,9 @@ post_file_recursive (SeafRepo *repo,
|
||||
unique_name = generate_unique_filename (newdent->name, olddir->entries);
|
||||
if (!unique_name)
|
||||
goto out;
|
||||
dent_dup = seaf_dirent_new (newdent->id, newdent->mode, unique_name);
|
||||
dent_dup = seaf_dirent_new (newdent->version,
|
||||
newdent->id, newdent->mode, unique_name,
|
||||
newdent->mtime, newdent->modifier, newdent->size);
|
||||
g_free (unique_name);
|
||||
|
||||
newentries = dup_seafdir_entries (olddir->entries);
|
||||
@ -169,7 +165,8 @@ post_file_recursive (SeafRepo *repo,
|
||||
dent_dup,
|
||||
compare_dirents);
|
||||
|
||||
newdir = seaf_dir_new (NULL, newentries, 0);
|
||||
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';
|
||||
@ -198,6 +195,8 @@ post_file_recursive (SeafRepo *repo,
|
||||
if (id != NULL) {
|
||||
memcpy(dent->id, id, 40);
|
||||
dent->id[40] = '\0';
|
||||
if (repo->version > 0)
|
||||
dent->mtime = (guint64)time(NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -207,7 +206,8 @@ post_file_recursive (SeafRepo *repo,
|
||||
GList *new_entries;
|
||||
|
||||
new_entries = dup_seafdir_entries (olddir->entries);
|
||||
newdir = seaf_dir_new (NULL, new_entries, 0);
|
||||
newdir = seaf_dir_new (NULL, new_entries,
|
||||
dir_version_from_repo_version(repo->version));
|
||||
seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir);
|
||||
|
||||
g_free(id);
|
||||
@ -629,19 +629,22 @@ seaf_repo_manager_post_file (SeafRepoManager *mgr,
|
||||
crypt = seafile_crypt_new (repo->enc_version, key, iv);
|
||||
}
|
||||
|
||||
gint64 size;
|
||||
if (seaf_fs_manager_index_blocks (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
temp_file_path,
|
||||
sha1, crypt, TRUE) < 0) {
|
||||
sha1, &size, crypt, TRUE) < 0) {
|
||||
seaf_warning ("failed to index blocks");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Failed to index blocks");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
rawdata_to_hex(sha1, hex, 20);
|
||||
new_dent = seaf_dirent_new (hex, STD_FILE_MODE, file_name);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version (repo->version),
|
||||
hex, STD_FILE_MODE, file_name,
|
||||
(gint64)time(NULL), user, size);
|
||||
|
||||
root_id = do_post_file (repo,
|
||||
head_commit->root_id, canon_path, new_dent);
|
||||
@ -680,24 +683,30 @@ out:
|
||||
}
|
||||
|
||||
static int
|
||||
add_new_entries (GList **entries, GList *filenames, GList *id_list, GList **name_list)
|
||||
add_new_entries (SeafRepo *repo, const char *user,
|
||||
GList **entries, GList *filenames, GList *id_list,
|
||||
GList *size_list, GList **name_list)
|
||||
{
|
||||
GList *ptr1, *ptr2;
|
||||
GList *ptr1, *ptr2, *ptr3;
|
||||
char *file, *id;
|
||||
gint64 *size;
|
||||
|
||||
for (ptr1 = filenames, ptr2 = id_list;
|
||||
ptr1 && ptr2;
|
||||
ptr1 = ptr1->next, ptr2 = ptr2->next)
|
||||
for (ptr1 = filenames, ptr2 = id_list, ptr3 = size_list;
|
||||
ptr1 && ptr2 && ptr3;
|
||||
ptr1 = ptr1->next, ptr2 = ptr2->next, ptr3 = ptr3->next)
|
||||
{
|
||||
file = ptr1->data;
|
||||
id = ptr2->data;
|
||||
size = ptr3->data;
|
||||
|
||||
char *unique_name;
|
||||
SeafDirent *newdent;
|
||||
|
||||
unique_name = generate_unique_filename (file, *entries);
|
||||
if (unique_name != NULL) {
|
||||
newdent = seaf_dirent_new (id, STD_FILE_MODE, unique_name);
|
||||
newdent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
id, STD_FILE_MODE, unique_name,
|
||||
(gint64)time(NULL), user, *size);
|
||||
*entries = g_list_insert_sorted (*entries, newdent, compare_dirents);
|
||||
*name_list = g_list_append (*name_list, unique_name);
|
||||
/* No need to free unique_name */
|
||||
@ -715,6 +724,8 @@ post_multi_files_recursive (SeafRepo *repo,
|
||||
const char *to_path,
|
||||
GList *filenames,
|
||||
GList *id_list,
|
||||
GList *size_list,
|
||||
const char *user,
|
||||
GList **name_list)
|
||||
{
|
||||
SeafDir *olddir, *newdir;
|
||||
@ -738,10 +749,13 @@ post_multi_files_recursive (SeafRepo *repo,
|
||||
|
||||
newentries = dup_seafdir_entries (olddir->entries);
|
||||
|
||||
if (add_new_entries (&newentries, filenames, id_list, name_list) < 0)
|
||||
if (add_new_entries (repo, user,
|
||||
&newentries, filenames, id_list, size_list,
|
||||
name_list) < 0)
|
||||
goto out;
|
||||
|
||||
newdir = seaf_dir_new (NULL, newentries, 0);
|
||||
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';
|
||||
@ -767,10 +781,13 @@ post_multi_files_recursive (SeafRepo *repo,
|
||||
continue;
|
||||
|
||||
id = post_multi_files_recursive (repo,
|
||||
dent->id, remain, filenames, id_list, name_list);
|
||||
dent->id, remain, filenames, id_list,
|
||||
size_list, user, name_list);
|
||||
if (id != NULL) {
|
||||
memcpy(dent->id, id, 40);
|
||||
dent->id[40] = '\0';
|
||||
if (repo->version > 0)
|
||||
dent->mtime = (guint64)time(NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -780,7 +797,8 @@ post_multi_files_recursive (SeafRepo *repo,
|
||||
GList *new_entries;
|
||||
|
||||
new_entries = dup_seafdir_entries (olddir->entries);
|
||||
newdir = seaf_dir_new (NULL, new_entries, 0);
|
||||
newdir = seaf_dir_new (NULL, new_entries,
|
||||
dir_version_from_repo_version(repo->version));
|
||||
seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir);
|
||||
|
||||
g_free(id);
|
||||
@ -802,6 +820,8 @@ do_post_multi_files (SeafRepo *repo,
|
||||
const char *parent_dir,
|
||||
GList *filenames,
|
||||
GList *id_list,
|
||||
GList *size_list,
|
||||
const char *user,
|
||||
GList **name_list)
|
||||
{
|
||||
/* if parent_dir is a absolutely path, we will remove the first '/' */
|
||||
@ -810,7 +830,7 @@ do_post_multi_files (SeafRepo *repo,
|
||||
|
||||
return post_multi_files_recursive(repo,
|
||||
root_id, parent_dir, filenames,
|
||||
id_list, name_list);
|
||||
id_list, size_list, user, name_list);
|
||||
}
|
||||
|
||||
static GList *
|
||||
@ -887,7 +907,8 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr,
|
||||
SeafRepo *repo = NULL;
|
||||
SeafCommit *head_commit = NULL;
|
||||
char *canon_path = NULL;
|
||||
GList *filenames = NULL, *paths = NULL, *id_list = NULL, *name_list = NULL, *ptr;
|
||||
GList *filenames = NULL, *paths = NULL, *id_list = NULL, *name_list = NULL,
|
||||
*size_list = NULL, *ptr;
|
||||
char *filename, *path;
|
||||
unsigned char sha1[20];
|
||||
GString *buf = g_string_new (NULL);
|
||||
@ -946,11 +967,14 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr,
|
||||
crypt = seafile_crypt_new (repo->enc_version, key, iv);
|
||||
}
|
||||
|
||||
gint64 *size;
|
||||
for (ptr = paths; ptr; ptr = ptr->next) {
|
||||
path = ptr->data;
|
||||
|
||||
size = g_new (gint64, 1);
|
||||
if (seaf_fs_manager_index_blocks (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
path, sha1, crypt, TRUE) < 0) {
|
||||
path, sha1, size, crypt, TRUE) < 0) {
|
||||
seaf_warning ("failed to index blocks");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Failed to index blocks");
|
||||
@ -960,13 +984,15 @@ seaf_repo_manager_post_multi_files (SeafRepoManager *mgr,
|
||||
|
||||
rawdata_to_hex(sha1, hex, 20);
|
||||
id_list = g_list_prepend (id_list, g_strdup(hex));
|
||||
size_list = g_list_prepend (size_list, size);
|
||||
}
|
||||
id_list = g_list_reverse (id_list);
|
||||
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, &name_list);
|
||||
filenames, id_list, size_list, user, &name_list);
|
||||
if (!root_id) {
|
||||
seaf_warning ("[post file] Failed to put file.\n");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL,
|
||||
@ -1001,6 +1027,9 @@ out:
|
||||
string_list_free (paths);
|
||||
string_list_free (id_list);
|
||||
string_list_free (name_list);
|
||||
for (ptr = size_list; ptr; ptr = ptr->next)
|
||||
g_free (ptr->data);
|
||||
g_list_free (size_list);
|
||||
g_string_free (buf, TRUE);
|
||||
g_free (root_id);
|
||||
g_free (canon_path);
|
||||
@ -1091,7 +1120,9 @@ seaf_repo_manager_post_file_blocks (SeafRepoManager *mgr,
|
||||
}
|
||||
|
||||
rawdata_to_hex(sha1, hex, 20);
|
||||
new_dent = seaf_dirent_new (hex, STD_FILE_MODE, file_name);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
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);
|
||||
@ -1155,14 +1186,15 @@ del_file_recursive(SeafRepo *repo,
|
||||
for (p = olddir->entries; p != NULL; p = p->next) {
|
||||
old = p->data;
|
||||
if (strcmp(old->name, filename) != 0) {
|
||||
new = seaf_dirent_new (old->id, old->mode, old->name);
|
||||
new = seaf_dirent_dup (old);
|
||||
newentries = g_list_prepend (newentries, new);
|
||||
}
|
||||
}
|
||||
|
||||
newentries = g_list_reverse (newentries);
|
||||
|
||||
newdir = seaf_dir_new(NULL, newentries, 0);
|
||||
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';
|
||||
@ -1191,6 +1223,8 @@ del_file_recursive(SeafRepo *repo,
|
||||
if (id != NULL) {
|
||||
memcpy(dent->id, id, 40);
|
||||
dent->id[40] = '\0';
|
||||
if (repo->version > 0)
|
||||
dent->mtime = (guint64)time(NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1199,7 +1233,8 @@ del_file_recursive(SeafRepo *repo,
|
||||
GList *new_entries;
|
||||
|
||||
new_entries = dup_seafdir_entries (olddir->entries);
|
||||
newdir = seaf_dir_new (NULL, new_entries, 0);
|
||||
newdir = seaf_dir_new (NULL, new_entries,
|
||||
dir_version_from_repo_version(repo->version));
|
||||
seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir);
|
||||
|
||||
g_free(id);
|
||||
@ -1301,6 +1336,7 @@ out:
|
||||
|
||||
static SeafDirent *
|
||||
get_dirent_by_path (SeafRepo *repo,
|
||||
const char *root_id,
|
||||
const char *path,
|
||||
const char *file_name,
|
||||
GError **error)
|
||||
@ -1308,19 +1344,22 @@ get_dirent_by_path (SeafRepo *repo,
|
||||
SeafCommit *head_commit = NULL;
|
||||
SeafDirent *dent = NULL;
|
||||
SeafDir *dir = NULL;
|
||||
|
||||
head_commit = seaf_commit_manager_get_commit(seaf->commit_mgr,
|
||||
repo->id, repo->version,
|
||||
repo->head->commit_id);
|
||||
if (!head_commit) {
|
||||
seaf_warning ("commit %s doesn't exist.\n", repo->head->commit_id);
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid commit");
|
||||
goto out;
|
||||
|
||||
if (!root_id) {
|
||||
head_commit = seaf_commit_manager_get_commit(seaf->commit_mgr,
|
||||
repo->id, repo->version,
|
||||
repo->head->commit_id);
|
||||
if (!head_commit) {
|
||||
seaf_warning ("commit %s doesn't exist.\n", repo->head->commit_id);
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid commit");
|
||||
goto out;
|
||||
}
|
||||
root_id = head_commit->root_id;
|
||||
}
|
||||
|
||||
dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
head_commit->root_id,
|
||||
root_id,
|
||||
path, NULL);
|
||||
if (!dir) {
|
||||
seaf_warning ("dir %s doesn't exist in repo %s.\n", path, repo->id);
|
||||
@ -1333,7 +1372,7 @@ get_dirent_by_path (SeafRepo *repo,
|
||||
SeafDirent *d = p->data;
|
||||
int r = strcmp (d->name, file_name);
|
||||
if (r == 0) {
|
||||
dent = seaf_dirent_new (d->id, d->mode, d->name);
|
||||
dent = seaf_dirent_dup(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1454,14 +1493,19 @@ seaf_repo_manager_copy_file (SeafRepoManager *mgr,
|
||||
dst_head_commit->root_id, dst_canon_path, dst_filename, NULL);
|
||||
|
||||
/* get src dirent */
|
||||
src_dent = get_dirent_by_path (src_repo, src_canon_path, src_filename, error);
|
||||
src_dent = get_dirent_by_path (src_repo, NULL,
|
||||
src_canon_path, src_filename, error);
|
||||
if (!src_dent) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
gint64 file_size = (src_dent->version > 0) ? src_dent->size : -1;
|
||||
|
||||
/* duplicate src dirent with new name */
|
||||
dst_dent = seaf_dirent_new (src_dent->id, src_dent->mode, dst_filename);
|
||||
dst_dent = seaf_dirent_new (dir_version_from_repo_version(dst_repo->version),
|
||||
src_dent->id, src_dent->mode, dst_filename,
|
||||
(gint64)time(NULL), user, file_size);
|
||||
|
||||
if (put_dirent_and_commit (dst_repo_id,
|
||||
dst_canon_path,
|
||||
@ -1597,14 +1641,19 @@ seaf_repo_manager_move_file (SeafRepoManager *mgr,
|
||||
dst_head_commit->root_id, dst_canon_path, dst_filename, NULL);
|
||||
|
||||
/* get src dirent */
|
||||
src_dent = get_dirent_by_path (src_repo, src_canon_path, src_filename, error);
|
||||
src_dent = get_dirent_by_path (src_repo, NULL,
|
||||
src_canon_path, src_filename, error);
|
||||
if (!src_dent) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
gint64 file_size = (src_dent->version > 0) ? src_dent->size : -1;
|
||||
|
||||
/* duplicate src dirent with new name */
|
||||
dst_dent = seaf_dirent_new (src_dent->id, src_dent->mode, dst_filename);
|
||||
dst_dent = seaf_dirent_new (dir_version_from_repo_version (dst_repo->version),
|
||||
src_dent->id, src_dent->mode, dst_filename,
|
||||
(gint64)time(NULL), user, file_size);
|
||||
|
||||
if (src_repo == dst_repo) {
|
||||
/* move file within the same repo */
|
||||
@ -1695,7 +1744,9 @@ seaf_repo_manager_post_dir (SeafRepoManager *mgr,
|
||||
head_commit->root_id, canon_path, new_dir_name, NULL);
|
||||
|
||||
if (!new_dent) {
|
||||
new_dent = seaf_dirent_new (EMPTY_SHA1, S_IFDIR, new_dir_name);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
EMPTY_SHA1, S_IFDIR, new_dir_name,
|
||||
(gint64)time(NULL), NULL, -1);
|
||||
}
|
||||
|
||||
root_id = do_post_file (repo,
|
||||
@ -1766,7 +1817,9 @@ seaf_repo_manager_post_empty_file (SeafRepoManager *mgr,
|
||||
head_commit->root_id, canon_path, new_file_name, NULL);
|
||||
|
||||
if (!new_dent) {
|
||||
new_dent = seaf_dirent_new (EMPTY_SHA1, STD_FILE_MODE, new_file_name);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
EMPTY_SHA1, STD_FILE_MODE, new_file_name,
|
||||
(gint64)time(NULL), user, 0);
|
||||
}
|
||||
|
||||
root_id = do_post_file (repo,
|
||||
@ -1836,9 +1889,11 @@ rename_file_recursive(SeafRepo *repo,
|
||||
for (p = olddir->entries; p != NULL; p = p->next) {
|
||||
old = p->data;
|
||||
if (strcmp(old->name, oldname) != 0) {
|
||||
newentries = g_list_prepend (newentries, dup_seaf_dirent(old));
|
||||
newentries = g_list_prepend (newentries, seaf_dirent_dup(old));
|
||||
} else {
|
||||
newdent = seaf_dirent_new (old->id, old->mode, newname);
|
||||
newdent = seaf_dirent_new (old->version, old->id, old->mode,
|
||||
newname, old->mtime,
|
||||
old->modifier, old->size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1848,7 +1903,8 @@ rename_file_recursive(SeafRepo *repo,
|
||||
newentries = g_list_insert_sorted(newentries, newdent, compare_dirents);
|
||||
}
|
||||
|
||||
newdir = seaf_dir_new (NULL, newentries, 0);
|
||||
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';
|
||||
@ -1886,7 +1942,8 @@ rename_file_recursive(SeafRepo *repo,
|
||||
GList *new_entries;
|
||||
|
||||
new_entries = dup_seafdir_entries (olddir->entries);
|
||||
newdir = seaf_dir_new (NULL, new_entries, 0);
|
||||
newdir = seaf_dir_new (NULL, new_entries,
|
||||
dir_version_from_repo_version(repo->version));
|
||||
seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir);
|
||||
|
||||
g_free(id);
|
||||
@ -2020,14 +2077,15 @@ put_file_recursive(SeafRepo *repo,
|
||||
for (p = olddir->entries; p; p = p->next) {
|
||||
dent = p->data;
|
||||
if (strcmp(dent->name, newdent->name) == 0) {
|
||||
newentries = g_list_prepend (newentries, dup_seaf_dirent(newdent));
|
||||
newentries = g_list_prepend (newentries, seaf_dirent_dup(newdent));
|
||||
} else {
|
||||
newentries = g_list_prepend (newentries, dup_seaf_dirent(dent));
|
||||
newentries = g_list_prepend (newentries, seaf_dirent_dup(dent));
|
||||
}
|
||||
}
|
||||
|
||||
newentries = g_list_reverse (newentries);
|
||||
newdir = seaf_dir_new (NULL, newentries, 0);
|
||||
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';
|
||||
@ -2056,6 +2114,8 @@ put_file_recursive(SeafRepo *repo,
|
||||
if (id != NULL) {
|
||||
memcpy(dent->id, id, 40);
|
||||
dent->id[40] = '\0';
|
||||
if (repo->version > 0)
|
||||
dent->mtime = (guint64)time(NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2065,7 +2125,8 @@ put_file_recursive(SeafRepo *repo,
|
||||
GList *new_entries;
|
||||
|
||||
new_entries = dup_seafdir_entries (olddir->entries);
|
||||
newdir = seaf_dir_new (NULL, new_entries, 0);
|
||||
newdir = seaf_dir_new (NULL, new_entries,
|
||||
dir_version_from_repo_version(repo->version));
|
||||
seaf_dir_save (seaf->fs_mgr, repo->store_id, repo->version, newdir);
|
||||
|
||||
g_free(id);
|
||||
@ -2166,10 +2227,11 @@ seaf_repo_manager_put_file (SeafRepoManager *mgr,
|
||||
crypt = seafile_crypt_new (repo->enc_version, key, iv);
|
||||
}
|
||||
|
||||
gint64 size;
|
||||
if (seaf_fs_manager_index_blocks (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
temp_file_path,
|
||||
sha1, crypt, TRUE) < 0) {
|
||||
sha1, &size, crypt, TRUE) < 0) {
|
||||
seaf_warning ("failed to index blocks");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Failed to index blocks");
|
||||
@ -2178,7 +2240,9 @@ seaf_repo_manager_put_file (SeafRepoManager *mgr,
|
||||
}
|
||||
|
||||
rawdata_to_hex(sha1, hex, 20);
|
||||
new_dent = seaf_dirent_new (hex, STD_FILE_MODE, file_name);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
hex, STD_FILE_MODE, file_name,
|
||||
(gint64)time(NULL), user, size);
|
||||
|
||||
if (!fullpath)
|
||||
fullpath = g_build_filename(parent_dir, file_name, NULL);
|
||||
@ -2301,7 +2365,9 @@ seaf_repo_manager_update_dir (SeafRepoManager *mgr,
|
||||
FAIL_IF_FILE_NOT_EXISTS(repo->store_id, repo->version,
|
||||
head_commit->root_id, canon_path, dirname, NULL);
|
||||
|
||||
new_dent = seaf_dirent_new (new_dir_id, S_IFDIR, dirname);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
new_dir_id, S_IFDIR, dirname,
|
||||
(gint64)time(NULL), NULL, -1);
|
||||
|
||||
root_id = do_put_file (repo, head_commit->root_id, canon_path, new_dent);
|
||||
if (!root_id) {
|
||||
@ -2424,7 +2490,9 @@ seaf_repo_manager_put_file_blocks (SeafRepoManager *mgr,
|
||||
}
|
||||
|
||||
rawdata_to_hex(sha1, hex, 20);
|
||||
new_dent = seaf_dirent_new (hex, STD_FILE_MODE, file_name);
|
||||
new_dent = seaf_dirent_new (dir_version_from_repo_version(repo->version),
|
||||
hex, STD_FILE_MODE, file_name,
|
||||
(gint64)time(NULL), user, file_size);
|
||||
|
||||
if (!fullpath)
|
||||
fullpath = g_build_filename(parent_dir, file_name, NULL);
|
||||
@ -2500,8 +2568,7 @@ filename_splitext (const char *filename,
|
||||
static char *
|
||||
revert_file_to_root (SeafRepo *repo,
|
||||
const char *root_id,
|
||||
const char *filename,
|
||||
const char *file_id,
|
||||
SeafDirent *old_dent,
|
||||
gboolean *skipped,
|
||||
GError **error)
|
||||
{
|
||||
@ -2523,9 +2590,9 @@ revert_file_to_root (SeafRepo *repo,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf (new_file_name, sizeof(new_file_name), "%s", filename);
|
||||
snprintf (new_file_name, sizeof(new_file_name), "%s", old_dent->name);
|
||||
|
||||
filename_splitext(filename, &basename, &ext);
|
||||
filename_splitext(old_dent->name, &basename, &ext);
|
||||
for (;;) {
|
||||
for (p = dir->entries; p; p = p->next) {
|
||||
dent = p->data;
|
||||
@ -2534,7 +2601,7 @@ revert_file_to_root (SeafRepo *repo,
|
||||
|
||||
if (S_ISREG(dent->mode)) {
|
||||
/* same named file */
|
||||
if (strcmp(dent->id, file_id) == 0) {
|
||||
if (strcmp(dent->id, old_dent->id) == 0) {
|
||||
*skipped = TRUE;
|
||||
goto out;
|
||||
} else {
|
||||
@ -2556,7 +2623,9 @@ revert_file_to_root (SeafRepo *repo,
|
||||
break;
|
||||
}
|
||||
|
||||
newdent = seaf_dirent_new (file_id, STD_FILE_MODE, new_file_name);
|
||||
newdent = seaf_dirent_new (old_dent->version,
|
||||
old_dent->id, STD_FILE_MODE, new_file_name,
|
||||
old_dent->mtime, old_dent->modifier, old_dent->size);
|
||||
new_root_id = do_post_file (repo, root_id, "/", newdent);
|
||||
|
||||
out:
|
||||
@ -2574,8 +2643,7 @@ static char *
|
||||
revert_file_to_parent_dir (SeafRepo *repo,
|
||||
const char *root_id,
|
||||
const char *parent_dir,
|
||||
const char *filename,
|
||||
const char *file_id,
|
||||
SeafDirent *old_dent,
|
||||
gboolean *skipped,
|
||||
GError **error)
|
||||
{
|
||||
@ -2598,8 +2666,8 @@ revert_file_to_parent_dir (SeafRepo *repo,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf (new_file_name, sizeof(new_file_name), "%s", filename);
|
||||
filename_splitext(filename, &basename, &ext);
|
||||
snprintf (new_file_name, sizeof(new_file_name), "%s", old_dent->name);
|
||||
filename_splitext(old_dent->name, &basename, &ext);
|
||||
while(TRUE) {
|
||||
for (p = dir->entries; p; p = p->next) {
|
||||
dent = p->data;
|
||||
@ -2608,7 +2676,7 @@ revert_file_to_parent_dir (SeafRepo *repo,
|
||||
|
||||
if (S_ISREG(dent->mode)) {
|
||||
/* same named file */
|
||||
if (strcmp(dent->id, file_id) == 0) {
|
||||
if (strcmp(dent->id, old_dent->id) == 0) {
|
||||
*skipped = TRUE;
|
||||
goto out;
|
||||
} else {
|
||||
@ -2630,7 +2698,9 @@ revert_file_to_parent_dir (SeafRepo *repo,
|
||||
}
|
||||
|
||||
do_revert:
|
||||
newdent = seaf_dirent_new (file_id, STD_FILE_MODE, new_file_name);
|
||||
newdent = seaf_dirent_new (old_dent->version,
|
||||
old_dent->id, STD_FILE_MODE, new_file_name,
|
||||
old_dent->mtime, old_dent->modifier, old_dent->size);
|
||||
if (is_overwrite) {
|
||||
new_root_id = do_put_file (repo,
|
||||
root_id, parent_dir, newdent);
|
||||
@ -2687,7 +2757,7 @@ seaf_repo_manager_revert_file (SeafRepoManager *mgr,
|
||||
SeafRepo *repo = NULL;
|
||||
SeafCommit *head_commit = NULL, *old_commit = NULL;
|
||||
char *parent_dir = NULL, *filename = NULL;
|
||||
char *revert_to_file_id = NULL;
|
||||
SeafDirent *old_dent = NULL;
|
||||
char *canon_path = NULL, *root_id = NULL;
|
||||
char buf[SEAF_PATH_MAX];
|
||||
char time_str[512];
|
||||
@ -2724,11 +2794,11 @@ seaf_repo_manager_revert_file (SeafRepoManager *mgr,
|
||||
goto out;
|
||||
}
|
||||
|
||||
revert_to_file_id =
|
||||
seaf_fs_manager_get_seafile_id_by_path (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
old_commit->root_id,
|
||||
canon_path, error);
|
||||
parent_dir = g_path_get_dirname(canon_path);
|
||||
filename = g_path_get_basename(canon_path);
|
||||
|
||||
old_dent = get_dirent_by_path (repo, old_commit->root_id,
|
||||
parent_dir, filename, error);
|
||||
if (*error) {
|
||||
seaf_warning ("[revert file] error: %s\n", (*error)->message);
|
||||
g_clear_error (error);
|
||||
@ -2737,9 +2807,6 @@ seaf_repo_manager_revert_file (SeafRepoManager *mgr,
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
parent_dir = g_path_get_dirname(canon_path);
|
||||
filename = g_path_get_basename(canon_path);
|
||||
}
|
||||
|
||||
parent_dir_exist = detect_path_exist (repo,
|
||||
@ -2759,14 +2826,13 @@ seaf_repo_manager_revert_file (SeafRepoManager *mgr,
|
||||
revert_to_root = TRUE;
|
||||
root_id = revert_file_to_root (repo,
|
||||
head_commit->root_id,
|
||||
filename,
|
||||
revert_to_file_id,
|
||||
old_dent,
|
||||
&skipped, error);
|
||||
} else {
|
||||
revert_to_root = FALSE;
|
||||
root_id = revert_file_to_parent_dir (repo,
|
||||
head_commit->root_id, parent_dir,
|
||||
filename, revert_to_file_id,
|
||||
old_dent,
|
||||
&skipped, error);
|
||||
}
|
||||
|
||||
@ -2821,7 +2887,7 @@ out:
|
||||
g_free (filename);
|
||||
|
||||
g_free (canon_path);
|
||||
g_free (revert_to_file_id);
|
||||
seaf_dirent_free (old_dent);
|
||||
|
||||
#define REVERT_TO_ROOT 0x1
|
||||
if (ret == 0) {
|
||||
@ -2836,8 +2902,7 @@ static char *
|
||||
revert_dir (SeafRepo *repo,
|
||||
const char *root_id,
|
||||
const char *parent_dir,
|
||||
const char *dirname,
|
||||
const char *dir_id,
|
||||
SeafDirent *old_dent,
|
||||
gboolean *skipped,
|
||||
GError **error)
|
||||
{
|
||||
@ -2858,7 +2923,7 @@ revert_dir (SeafRepo *repo,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf (new_dir_name, sizeof(new_dir_name), "%s", dirname);
|
||||
snprintf (new_dir_name, sizeof(new_dir_name), "%s", old_dent->name);
|
||||
|
||||
for (;;) {
|
||||
for (p = dir->entries; p; p = p->next) {
|
||||
@ -2867,13 +2932,13 @@ revert_dir (SeafRepo *repo,
|
||||
continue;
|
||||
|
||||
/* the same dir */
|
||||
if (S_ISDIR(dent->mode) && strcmp(dent->id, dir_id) == 0) {
|
||||
if (S_ISDIR(dent->mode) && strcmp(dent->id, old_dent->id) == 0) {
|
||||
*skipped = TRUE;
|
||||
goto out;
|
||||
} else {
|
||||
/* rename and retry */
|
||||
snprintf (new_dir_name, sizeof(new_dir_name), "%s (%d)",
|
||||
dirname, i++);
|
||||
old_dent->name, i++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2882,7 +2947,9 @@ revert_dir (SeafRepo *repo,
|
||||
break;
|
||||
}
|
||||
|
||||
newdent = seaf_dirent_new (dir_id, S_IFDIR, new_dir_name);
|
||||
newdent = seaf_dirent_new (old_dent->version,
|
||||
old_dent->id, S_IFDIR, new_dir_name,
|
||||
old_dent->mtime, NULL, -1);
|
||||
new_root_id = do_post_file (repo, root_id, parent_dir, newdent);
|
||||
|
||||
out:
|
||||
@ -2905,7 +2972,7 @@ seaf_repo_manager_revert_dir (SeafRepoManager *mgr,
|
||||
SeafRepo *repo = NULL;
|
||||
SeafCommit *head_commit = NULL, *old_commit = NULL;
|
||||
char *parent_dir = NULL, *dirname = NULL;
|
||||
char *revert_to_dir_id = NULL;
|
||||
SeafDirent *old_dent = NULL;
|
||||
char *canon_path = NULL, *root_id = NULL;
|
||||
char buf[SEAF_PATH_MAX];
|
||||
gboolean parent_dir_exist = FALSE;
|
||||
@ -2935,11 +3002,11 @@ seaf_repo_manager_revert_dir (SeafRepoManager *mgr,
|
||||
if (!canon_path) {
|
||||
canon_path = get_canonical_path (dir_path);
|
||||
|
||||
revert_to_dir_id =
|
||||
seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr,
|
||||
repo->store_id, repo->version,
|
||||
old_commit->root_id,
|
||||
canon_path, error);
|
||||
parent_dir = g_path_get_dirname(canon_path);
|
||||
dirname = g_path_get_basename(canon_path);
|
||||
|
||||
old_dent = get_dirent_by_path (repo, old_commit->root_id,
|
||||
parent_dir, dirname, error);
|
||||
if (*error) {
|
||||
seaf_warning ("[revert dir] error: %s\n", (*error)->message);
|
||||
g_clear_error (error);
|
||||
@ -2948,9 +3015,6 @@ seaf_repo_manager_revert_dir (SeafRepoManager *mgr,
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
parent_dir = g_path_get_dirname(canon_path);
|
||||
dirname = g_path_get_basename(canon_path);
|
||||
}
|
||||
|
||||
parent_dir_exist = detect_path_exist (repo,
|
||||
@ -2971,16 +3035,14 @@ seaf_repo_manager_revert_dir (SeafRepoManager *mgr,
|
||||
root_id = revert_dir (repo,
|
||||
head_commit->root_id,
|
||||
"/",
|
||||
dirname,
|
||||
revert_to_dir_id,
|
||||
old_dent,
|
||||
&skipped, error);
|
||||
} else {
|
||||
revert_to_root = FALSE;
|
||||
root_id = revert_dir (repo,
|
||||
head_commit->root_id,
|
||||
parent_dir,
|
||||
dirname,
|
||||
revert_to_dir_id,
|
||||
old_dent,
|
||||
&skipped, error);
|
||||
}
|
||||
|
||||
@ -3028,7 +3090,7 @@ out:
|
||||
g_free (dirname);
|
||||
|
||||
g_free (canon_path);
|
||||
g_free (revert_to_dir_id);
|
||||
seaf_dirent_free (old_dent);
|
||||
|
||||
#define REVERT_TO_ROOT 0x1
|
||||
if (ret == 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user