Use JSON for fs object format and store modifier, size, mtime in direcotry objects.

This commit is contained in:
Jiaqiang Xu 2014-03-22 12:58:49 +08:00
parent bf51101235
commit 2983357dfb
35 changed files with 1816 additions and 564 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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); }

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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) {

View File

@ -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. */
};

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -13,6 +13,7 @@ namespace Seafile {
}
public List<Dirent> entries;
public int version { set; get; }
}
} // namespace
} // namespace

View File

@ -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 {

View File

@ -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);

View File

@ -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, &times);
#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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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) {