From a50c39cd0cdb495868766bf4047dbd3a16498c67 Mon Sep 17 00:00:00 2001 From: Klaas Freitag Date: Tue, 6 May 2014 12:55:54 +0200 Subject: [PATCH] Maintain the original inode value for renamed files. In case two renames are done on the same file/folder very quickly we lost the information that the second operation was also a rename. That was because we tried to get the inode value from a stat on the file once the first rename was finished. But at that point, the file was already gone because of the second rename. Now the original inode is kept and written to db in case the file can not be stat'ed. This fixes bug #1737 --- csync/src/csync.c | 1 + csync/src/csync.h | 1 + csync/src/csync_reconcile.c | 3 ++- csync/src/csync_update.c | 2 ++ src/mirall/syncengine.cpp | 2 ++ src/mirall/syncfileitem.h | 1 + src/mirall/syncjournalfilerecord.cpp | 16 ++++++++++------ 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/csync/src/csync.c b/csync/src/csync.c index 9a3ba6cf8..484e16519 100644 --- a/csync/src/csync.c +++ b/csync/src/csync.c @@ -444,6 +444,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) { trav.rename_path = cur->destpath; trav.etag = cur->etag; trav.file_id = cur->file_id; + trav.inode = cur->inode; trav.error_status = cur->error_status; trav.should_update_etag = cur->should_update_etag; diff --git a/csync/src/csync.h b/csync/src/csync.h index 1d83ada63..d15ac6667 100644 --- a/csync/src/csync.h +++ b/csync/src/csync.h @@ -170,6 +170,7 @@ enum csync_notify_type_e { struct csync_tree_walk_file_s { const char *path; int64_t size; + int64_t inode; time_t modtime; #ifdef _WIN32 uint32_t uid; diff --git a/csync/src/csync_reconcile.c b/csync/src/csync_reconcile.c index 649b3228d..8cddd0a11 100644 --- a/csync/src/csync_reconcile.c +++ b/csync/src/csync_reconcile.c @@ -183,6 +183,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) { if( !c_streq(cur->file_id, "") ) { csync_vio_set_file_id( other->file_id, cur->file_id ); } + other->inode = cur->inode; cur->instruction = CSYNC_INSTRUCTION_NONE; } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) { other->instruction = CSYNC_INSTRUCTION_RENAME; @@ -191,7 +192,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) { if( !c_streq(cur->file_id, "") ) { csync_vio_set_file_id( other->file_id, cur->file_id ); } - + other->inode = cur->inode; cur->instruction = CSYNC_INSTRUCTION_NONE; } else if (other->instruction == CSYNC_INSTRUCTION_NEW) { CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!"); diff --git a/csync/src/csync_update.c b/csync/src/csync_update.c index 0378e6afc..444f11c71 100644 --- a/csync/src/csync_update.c +++ b/csync/src/csync_update.c @@ -276,6 +276,8 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, /* check if it's a file and has been renamed */ if (ctx->current == LOCAL_REPLICA) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode); + tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode); /* translate the file type between the two stat types csync has. */ diff --git a/src/mirall/syncengine.cpp b/src/mirall/syncengine.cpp index 1549dc02d..14e42aaed 100644 --- a/src/mirall/syncengine.cpp +++ b/src/mirall/syncengine.cpp @@ -292,6 +292,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote ) item._modtime = file->modtime; item._etag = file->etag; item._size = file->size; + item._inode = file->inode; + item._should_update_etag = file->should_update_etag; switch( file->type ) { case CSYNC_FTW_TYPE_DIR: diff --git a/src/mirall/syncfileitem.h b/src/mirall/syncfileitem.h index fa88e49c0..e062cae07 100644 --- a/src/mirall/syncfileitem.h +++ b/src/mirall/syncfileitem.h @@ -83,6 +83,7 @@ public: time_t _modtime; QByteArray _etag; quint64 _size; + quint64 _inode; bool _should_update_etag; QByteArray _fileId; bool _blacklistedInDb; diff --git a/src/mirall/syncjournalfilerecord.cpp b/src/mirall/syncjournalfilerecord.cpp index 317643ca2..b50148284 100644 --- a/src/mirall/syncjournalfilerecord.cpp +++ b/src/mirall/syncjournalfilerecord.cpp @@ -36,15 +36,20 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt _type(item._type), _etag(item._etag), _fileId(item._fileId), _uid(0), _gid(0), _mode(0) { + // use the "old" inode coming with the item for the case where the + // filesystem stat fails. That can happen if the the file was removed + // or renamed meanwhile. For the rename case we still need the inode to + // detect the rename tough. + _inode = item._inode; - // Query the inode: - // based on code from csync_vio_local.c (csync_vio_local_stat) #ifdef Q_OS_WIN - /* Get the Windows file id as an inode replacement. */ + /* Query the inode: + based on code from csync_vio_local.c (csync_vio_local_stat) + Get the Windows file id as an inode replacement. */ HANDLE h = CreateFileW( (wchar_t*)localFileName.utf16(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL ); + if( h == INVALID_HANDLE_VALUE ) { - _inode = 0; qWarning() << "Failed to query the 'inode' because CreateFileW failed for file " << localFileName; } else { BY_HANDLE_FILE_INFORMATION fileInfo; @@ -60,7 +65,7 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt _inode = FileIndex.QuadPart; } else { qWarning() << "Failed to query the 'inode' for file " << localFileName; - _inode = 0; + } CloseHandle(h); } @@ -68,7 +73,6 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt struct stat sb; if( stat(QFile::encodeName(localFileName).constData(), &sb) < 0) { qWarning() << "Failed to query the 'inode' for file " << localFileName; - _inode = 0; } else { _inode = sb.st_ino; }