Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/owncloud/client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/csync/csync_update.cpp')
-rw-r--r--src/csync/csync_update.cpp117
1 files changed, 106 insertions, 11 deletions
diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp
index 852ef0c20..2f180dda4 100644
--- a/src/csync/csync_update.cpp
+++ b/src/csync/csync_update.cpp
@@ -47,6 +47,7 @@
#include "common/asserts.h"
#include <QtCore/QTextCodec>
+#include <QtCore/QFile>
// Needed for PRIu64 on MinGW in C++ mode.
#define __STDC_FORMAT_MACROS
@@ -186,21 +187,64 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
return -1;
}
+ // The db entry might be for a placeholder, so look for that on the
+ // remote side. If we find one, change the current fs to look like a
+ // placeholder too, because that's what one would see if the remote
+ // db was filled from the database.
+ if (ctx->current == REMOTE_REPLICA && !base.isValid() && fs->type == ItemTypeFile) {
+ auto placeholderPath = fs->path;
+ placeholderPath.append(ctx->placeholder_suffix);
+ ctx->statedb->getFileRecord(placeholderPath, &base);
+ if (base.isValid() && base._type == ItemTypePlaceholder) {
+ fs->type = ItemTypePlaceholder;
+ fs->path = placeholderPath;
+ } else {
+ base = OCC::SyncJournalFileRecord();
+ }
+ }
+
if(base.isValid()) { /* there is an entry in the database */
/* we have an update! */
qCInfo(lcUpdate, "Database entry found, compare: %" PRId64 " <-> %" PRId64
", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
- ", size: %" PRId64 " <-> %" PRId64 ", perms: %x <-> %x"
- ", checksum: %s <-> %s , ignore: %d",
+ ", size: %" PRId64 " <-> %" PRId64
+ ", perms: %x <-> %x"
+ ", type: %d <-> %d"
+ ", checksum: %s <-> %s"
+ ", ignore: %d",
((int64_t) fs->modtime), ((int64_t) base._modtime),
fs->etag.constData(), base._etag.constData(), (uint64_t) fs->inode, (uint64_t) base._inode,
- (uint64_t) fs->size, (uint64_t) base._fileSize, *reinterpret_cast<short*>(&fs->remotePerm), *reinterpret_cast<short*>(&base._remotePerm), fs->checksumHeader.constData(),
- base._checksumHeader.constData(), base._serverHasIgnoredFiles);
+ (uint64_t) fs->size, (uint64_t) base._fileSize,
+ *reinterpret_cast<short*>(&fs->remotePerm), *reinterpret_cast<short*>(&base._remotePerm),
+ fs->type, base._type,
+ fs->checksumHeader.constData(), base._checksumHeader.constData(),
+ base._serverHasIgnoredFiles );
+
+ // If the db suggests a placeholder should be downloaded,
+ // treat the file as new on the remote.
+ if (ctx->current == REMOTE_REPLICA && base._type == ItemTypePlaceholderDownload) {
+ fs->instruction = CSYNC_INSTRUCTION_NEW;
+ fs->type = ItemTypePlaceholderDownload;
+ goto out;
+ }
+
+ // If what the db thinks is a placeholder is actually a file/dir,
+ // treat it as new locally.
+ if (ctx->current == LOCAL_REPLICA
+ && (base._type == ItemTypePlaceholder || base._type == ItemTypePlaceholderDownload)
+ && fs->type != ItemTypePlaceholder) {
+ fs->instruction = CSYNC_INSTRUCTION_EVAL;
+ goto out;
+ }
+
if (ctx->current == REMOTE_REPLICA && fs->etag != base._etag) {
fs->instruction = CSYNC_INSTRUCTION_EVAL;
- // Preserve the EVAL flag later on if the type has changed.
- if (base._type != fs->type) {
+ if (fs->type == ItemTypePlaceholder) {
+ // If the local thing is a placeholder, we just update the metadata
+ fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+ } else if (base._type != fs->type) {
+ // Preserve the EVAL flag later on if the type has changed.
fs->child_modified = true;
}
@@ -321,10 +365,19 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
if (!base.isValid())
return;
+ if (base._type == ItemTypePlaceholderDownload) {
+ // Remote rename of a placeholder file we have locally scheduled
+ // for download. We just consider this NEW but mark it for download.
+ fs->type = ItemTypePlaceholderDownload;
+ done = true;
+ return;
+ }
+
// Some things prohibit rename detection entirely.
// Since we don't do the same checks again in reconcile, we can't
// just skip the candidate, but have to give up completely.
- if (base._type != fs->type) {
+ if (base._type != fs->type
+ && base._type != ItemTypePlaceholder) {
qCWarning(lcUpdate, "file types different, not a rename");
done = true;
return;
@@ -336,6 +389,14 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
return;
}
+ // Now we know there is a sane rename candidate.
+
+ // Rename of a placeholder
+ if (base._type == ItemTypePlaceholder && fs->type == ItemTypeFile) {
+ fs->type = ItemTypePlaceholder;
+ fs->path.append(ctx->placeholder_suffix);
+ }
+
// Record directory renames
if (fs->type == ItemTypeDirectory) {
// If the same folder was already renamed by a different entry,
@@ -365,6 +426,15 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
return 1;
}
}
+
+ // Turn new remote files into placeholders if the option is enabled.
+ if (ctx->new_files_are_placeholders
+ && fs->instruction == CSYNC_INSTRUCTION_NEW
+ && fs->type == ItemTypeFile) {
+ fs->type = ItemTypePlaceholder;
+ fs->path.append(ctx->placeholder_suffix);
+ }
+
goto out;
}
}
@@ -467,7 +537,7 @@ int csync_walker(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs) {
return rc;
}
-static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
+static bool fill_tree_from_db(CSYNC *ctx, const char *uri, bool singleFile = false)
{
int64_t count = 0;
QByteArray skipbase;
@@ -522,9 +592,19 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
++count;
};
- if (!ctx->statedb->getFilesBelowPath(uri, rowCallback)) {
- ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
- return false;
+ if (singleFile) {
+ OCC::SyncJournalFileRecord record;
+ if (ctx->statedb->getFileRecord(QByteArray(uri), &record) && record.isValid()) {
+ rowCallback(record);
+ } else {
+ ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
+ return false;
+ }
+ } else {
+ if (!ctx->statedb->getFilesBelowPath(uri, rowCallback)) {
+ ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
+ return false;
+ }
}
qInfo(lcUpdate, "%" PRId64 " entries read below path %s from db.", count, uri);
@@ -661,6 +741,21 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
fullpath = QByteArray() % uri % '/' % filename;
}
+ // When encountering placeholder files, read the relevant
+ // entry from the db instead.
+ if (ctx->current == LOCAL_REPLICA
+ && dirent->type == ItemTypeFile
+ && filename.endsWith(ctx->placeholder_suffix)) {
+ QByteArray db_uri = fullpath.mid(strlen(ctx->local.uri) + 1);
+
+ if( ! fill_tree_from_db(ctx, db_uri.constData(), true) ) {
+ qCWarning(lcUpdate) << "Placeholder without db entry for" << filename;
+ QFile::remove(fullpath);
+ }
+
+ continue;
+ }
+
/* if the filename starts with a . we consider it a hidden file
* For windows, the hidden state is also discovered within the vio
* local stat function.