Merge remote-tracking branch 'origin/hidden_file_handling'

This commit is contained in:
Olivier Goffart 2015-07-17 09:32:29 +02:00
commit 0a6aa88d72
24 changed files with 346 additions and 164 deletions

View file

@ -124,6 +124,8 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
ctx->abort = false;
ctx->ignore_hidden_files = true;
*csync = ctx;
return 0;
}
@ -435,6 +437,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
trav.error_status = cur->error_status;
trav.should_update_metadata = cur->should_update_metadata;
trav.has_ignored_files = cur->has_ignored_files;
if( other_node ) {
csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
@ -592,6 +595,7 @@ int csync_commit(CSYNC *ctx) {
ctx->remote.read_from_db = 0;
ctx->read_remote_from_db = true;
ctx->db_is_empty = false;
ctx->ignore_hidden_files = true; // do NOT sync hidden files by default.
/* Create new trees */

View file

@ -49,27 +49,23 @@ struct csync_client_certs_s {
char *certificatePasswd;
};
/**
* Instruction enum. In the file traversal structure, it describes
* the csync state of a file.
*/
enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
*/
CSYNC_STATUS_UNSUCCESSFUL,
CSYNC_STATUS_UNSUCCESSFUL, /* Unspecific problem happend */
CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */
CSYNC_STATUS_STATEDB_LOAD_ERROR,
CSYNC_STATUS_STATEDB_CORRUPTED,
CSYNC_STATUS_NO_MODULE,
CSYNC_STATUS_STATEDB_LOAD_ERROR, /* Statedb can not be loaded. */
CSYNC_STATUS_STATEDB_CORRUPTED, /* Statedb is corrupted */
CSYNC_STATUS_NO_MODULE, /* URL passed to csync does not start with owncloud:// or ownclouds:// */
CSYNC_STATUS_TIMESKEW, /* OBSOLETE */
CSYNC_STATUS_FILESYSTEM_UNKNOWN, /* UNUSED */
CSYNC_STATUS_TREE_ERROR,
CSYNC_STATUS_MEMORY_ERROR,
CSYNC_STATUS_PARAM_ERROR,
CSYNC_STATUS_UPDATE_ERROR,
CSYNC_STATUS_RECONCILE_ERROR,
CSYNC_STATUS_TREE_ERROR, /* csync trees could not be created */
CSYNC_STATUS_MEMORY_ERROR, /* not enough memory problem */
CSYNC_STATUS_PARAM_ERROR, /* parameter is zero where not expected */
CSYNC_STATUS_UPDATE_ERROR, /* general update or discovery error */
CSYNC_STATUS_RECONCILE_ERROR, /* general reconcile error */
CSYNC_STATUS_PROPAGATE_ERROR, /* OBSOLETE */
CSYNC_STATUS_REMOTE_ACCESS_ERROR, /* UNUSED */
CSYNC_STATUS_REMOTE_CREATE_ERROR, /* UNUSED */
@ -77,13 +73,13 @@ enum csync_status_codes_e {
CSYNC_STATUS_LOCAL_CREATE_ERROR, /* UNUSED */
CSYNC_STATUS_LOCAL_STAT_ERROR, /* UNUSED */
CSYNC_STATUS_PROXY_ERROR, /* UNUSED */
CSYNC_STATUS_LOOKUP_ERROR,
CSYNC_STATUS_SERVER_AUTH_ERROR,
CSYNC_STATUS_PROXY_AUTH_ERROR,
CSYNC_STATUS_CONNECT_ERROR,
CSYNC_STATUS_TIMEOUT,
CSYNC_STATUS_HTTP_ERROR,
CSYNC_STATUS_PERMISSION_DENIED,
CSYNC_STATUS_LOOKUP_ERROR, /* Neon fails to find proxy. Almost OBSOLETE */
CSYNC_STATUS_SERVER_AUTH_ERROR, /* UNUSED */
CSYNC_STATUS_PROXY_AUTH_ERROR, /* UNUSED */
CSYNC_STATUS_CONNECT_ERROR, /* neon driven connection failed */
CSYNC_STATUS_TIMEOUT, /* UNUSED */
CSYNC_STATUS_HTTP_ERROR, /* UNUSED */
CSYNC_STATUS_PERMISSION_DENIED, /* */
CSYNC_STATUS_NOT_FOUND,
CSYNC_STATUS_FILE_EXISTS,
CSYNC_STATUS_OUT_OF_SPACE,
@ -103,7 +99,8 @@ enum csync_status_codes_e {
CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST,
CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS,
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME,
CYSNC_STATUS_FILE_LOCKED_OR_OPEN
CYSNC_STATUS_FILE_LOCKED_OR_OPEN,
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN
};
typedef enum csync_status_codes_e CSYNC_STATUS;
@ -119,7 +116,10 @@ typedef enum csync_status_codes_e CSYNC_STATUS;
#define CSYNC_STATUS_IS_ERR(x) (unlikely((x) >= CSYNC_STATUS_ERROR))
#define CSYNC_STATUS_IS_EQUAL(x, y) ((x) == (y))
/**
* Instruction enum. In the file traversal structure, it describes
* the csync state of a file.
*/
enum csync_instructions_e {
CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */
CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */
@ -249,6 +249,9 @@ struct csync_tree_walk_file_s {
/* For directories: If the etag has been updated and need to be writen on the db */
int should_update_metadata;
/* For directories: Does it have children that were ignored (hidden or ignore pattern) */
int has_ignored_files;
const char *rename_path;
const char *etag;
const char *file_id;

View file

@ -27,7 +27,8 @@ enum csync_exclude_type_e {
CSYNC_FILE_EXCLUDE_AND_REMOVE,
CSYNC_FILE_EXCLUDE_LIST,
CSYNC_FILE_EXCLUDE_INVALID_CHAR,
CSYNC_FILE_EXCLUDE_LONG_FILENAME
CSYNC_FILE_EXCLUDE_LONG_FILENAME,
CSYNC_FILE_EXCLUDE_HIDDEN
};
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;

View file

@ -168,6 +168,8 @@ struct csync_s {
*/
bool db_is_empty;
bool ignore_hidden_files;
struct csync_owncloud_ctx_s *owncloud_context;
};

View file

@ -283,6 +283,9 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
if(column_count > 12 && sqlite3_column_int64(stmt,12)) {
(*st)->size = sqlite3_column_int64(stmt, 12);
}
if(column_count > 13) {
(*st)->has_ignored_files = sqlite3_column_int(stmt, 13);
}
}
} else {
if( rc != SQLITE_DONE ) {
@ -435,7 +438,7 @@ char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
return ret;
}
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize FROM metadata WHERE pathlen>? AND path LIKE(?)"
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote FROM metadata WHERE pathlen>? AND path LIKE(?)"
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
int rc;

View file

@ -163,18 +163,20 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
len = strlen(path);
/* This code should probably be in csync_exclude, but it does not have the fs parameter.
Keep it here for now and TODO also find out if we want this for Windows
https://github.com/owncloud/mirall/issues/2086 */
if (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
return 0;
}
/* Check if file is excluded */
excluded = csync_excluded(ctx, path,type);
if (excluded != CSYNC_NOT_EXCLUDED) {
if( excluded == CSYNC_NOT_EXCLUDED ) {
/* Even if it is not excluded by a pattern, maybe it is to be ignored
* because it's a hidden file that should not be synced.
* This code should probably be in csync_exclude, but it does not have the fs parameter.
* Keep it here for now */
if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
}
} else {
/* File is ignored because it's matched by a user- or system exclude pattern. */
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded);
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
return 1;
@ -182,10 +184,6 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
return 1;
}
if (ctx->current_fs) {
ctx->current_fs->has_ignored_files = true;
}
}
if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
@ -208,9 +206,9 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
st->child_modified = 0;
st->has_ignored_files = 0;
/* check hardlink count */
/* FIXME: Under which conditions are the following two ifs true and the code
* is executed? */
if (type == CSYNC_FTW_TYPE_FILE ) {
if (fs->mtime == 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
@ -242,11 +240,13 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
st->instruction = CSYNC_INSTRUCTION_NONE;
goto out;
}
if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
if( type == CSYNC_FTW_TYPE_SLINK ) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
}
st->instruction = CSYNC_INSTRUCTION_IGNORE;
if (ctx->current_fs) {
ctx->current_fs->has_ignored_files = true;
}
goto out;
}
@ -268,10 +268,10 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
/* we have an update! */
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Database entry found, compare: %" PRId64 " <-> %" PRId64
", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s",
", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d",
((int64_t) fs->mtime), ((int64_t) tmp->modtime),
fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
(uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm );
(uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
if( !fs->etag) {
st->instruction = CSYNC_INSTRUCTION_EVAL;
goto out;
@ -316,6 +316,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
st->should_update_metadata = true;
}
/* If it was remembered in the db that the remote dir has ignored files, store
* that so that the reconciler can make advantage of.
*/
if( ctx->current == REMOTE_REPLICA ) {
st->has_ignored_files = tmp->has_ignored_files;
}
st->instruction = CSYNC_INSTRUCTION_NONE;
} else {
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
@ -418,12 +424,18 @@ out:
/* Set the ignored error string. */
if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
if( type == CSYNC_FTW_TYPE_SLINK ) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
} else {
if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
} else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */
} else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
} else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
}
}
}
if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE

View file

@ -224,7 +224,12 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
break;
} while (0);
/* TODO Do we want to parse for CSYNC_VIO_FILE_FLAGS_HIDDEN ? */
/* Check for the hidden flag */
if( fileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) {
buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;

View file

@ -55,6 +55,7 @@ struct CmdOptions {
bool trustSSL;
bool useNetrc;
bool interactive;
bool ignoreHiddenFiles;
QString exclude;
QString unsyncedfolders;
};
@ -154,6 +155,7 @@ void help()
std::cout << " --password, -p [pass] Use [pass] as password" << std::endl;
std::cout << " -n Use netrc (5) for login" << std::endl;
std::cout << " --non-interactive Do not block execution with interaction" << std::endl;
std::cout << " -h Sync hidden files,do not ignore them" << std::endl;
std::cout << " --version, -v Display version and exit" << std::endl;
std::cout << "" << std::endl;
exit(1);
@ -216,6 +218,8 @@ void parseOptions( const QStringList& app_args, CmdOptions *options )
options->trustSSL = true;
} else if( option == "-n") {
options->useNetrc = true;
} else if( option == "-h") {
options->ignoreHiddenFiles = false;
} else if( option == "--non-interactive") {
options->interactive = false;
} else if( (option == "-u" || option == "--user") && !it.peekNext().startsWith("-") ) {
@ -269,6 +273,7 @@ int main(int argc, char **argv) {
options.trustSSL = false;
options.useNetrc = false;
options.interactive = true;
options.ignoreHiddenFiles = true;
ClientProxy clientProxy;
parseOptions( app.arguments(), &options );
@ -364,6 +369,9 @@ restart_sync:
return EXIT_FAILURE;
}
// ignore hidden files or not
_csync_ctx->ignore_hidden_files = options.ignoreHiddenFiles;
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
if( !options.proxy.isNull() ) {
QString host;

View file

@ -192,6 +192,17 @@ void AccountSettings::slotFolderWizardAccepted()
definition.alias = folderWizard->field(QLatin1String("alias")).toString();
definition.localPath = folderWizard->field(QLatin1String("sourceFolder")).toString();
definition.targetPath = folderWizard->property("targetPath").toString();
bool ignoreHidden = true;
/* take the value from the definition of already existing folders. All folders have
* the same setting so far, that's why it's ok to check the first one.
* The default is to not sync hidden files
*/
if( folderMan->map().count() > 0) {
ignoreHidden = folderMan->map().first()->ignoreHiddenFiles();
}
definition.ignoreHiddenFiles = ignoreHidden;
auto selectiveSyncBlackList = folderWizard->property("selectiveSyncBlackList").toStringList();
folderMan->setSyncEnabled(true);

View file

@ -191,6 +191,17 @@ QString Folder::path() const
return p;
}
bool Folder::ignoreHiddenFiles()
{
bool re(_definition.ignoreHiddenFiles);
return re;
}
void Folder::setIgnoreHiddenFiles(bool ignore)
{
_definition.ignoreHiddenFiles = ignore;
}
QString Folder::cleanPath()
{
QString cleanedPath = QDir::cleanPath(_definition.localPath);
@ -813,6 +824,9 @@ void Folder::startSync(const QStringList &pathList)
return;
}
// pass the setting if hidden files are to be ignored, will be read in csync_update
_csync_ctx->ignore_hidden_files = _definition.ignoreHiddenFiles;
_engine.reset(new SyncEngine( _accountState->account(), _csync_ctx, path(), remoteUrl().path(), remotePath(), &_journal));
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
@ -1086,6 +1100,7 @@ void FolderDefinition::save(QSettings& settings, const FolderDefinition& folder)
settings.setValue(QLatin1String("localPath"), folder.localPath);
settings.setValue(QLatin1String("targetPath"), folder.targetPath);
settings.setValue(QLatin1String("paused"), folder.paused);
settings.setValue(QLatin1String("ignoreHiddenFiles"), folder.ignoreHiddenFiles);
settings.endGroup();
}
@ -1097,6 +1112,7 @@ bool FolderDefinition::load(QSettings& settings, const QString& alias,
folder->localPath = settings.value(QLatin1String("localPath")).toString();
folder->targetPath = settings.value(QLatin1String("targetPath")).toString();
folder->paused = settings.value(QLatin1String("paused")).toBool();
folder->ignoreHiddenFiles = settings.value(QLatin1String("ignoreHiddenFiles"), QVariant(true)).toBool();
settings.endGroup();
return true;
}

View file

@ -63,6 +63,8 @@ public:
QString targetPath;
/// whether the folder is paused
bool paused;
/// whether the folder syncs hidden files
bool ignoreHiddenFiles;
/// Saves the folder definition, creating a new settings group.
static void save(QSettings& settings, const FolderDefinition& folder);
@ -168,6 +170,13 @@ public:
void setDirtyNetworkLimits();
/**
* Ignore syncing of hidden files or not. This is defined in the
* folder definition
*/
bool ignoreHiddenFiles();
void setIgnoreHiddenFiles(bool ignore);
// Used by the Socket API
SyncJournalDb *journalDb() { return &_journal; }

View file

@ -151,6 +151,7 @@ void FolderMan::registerFolderMonitor( Folder *folder )
ConfigFile cfg;
fw->addIgnoreListFile( cfg.excludeFile(ConfigFile::SystemScope) );
fw->addIgnoreListFile( cfg.excludeFile(ConfigFile::UserScope) );
fw->setIgnoreHidden( folder->ignoreHiddenFiles() );
// Connect the pathChanged signal, which comes with the changed path,
// to the signal mapper which maps to the folder alias. The changed path

View file

@ -36,7 +36,8 @@
namespace OCC {
FolderWatcher::FolderWatcher(const QString &root, QObject *parent)
: QObject(parent)
: QObject(parent),
_ignoreHidden(true)
{
_d.reset(new FolderWatcherPrivate(this, root));
@ -46,6 +47,16 @@ FolderWatcher::FolderWatcher(const QString &root, QObject *parent)
FolderWatcher::~FolderWatcher()
{ }
void FolderWatcher::setIgnoreHidden(bool ignore)
{
_ignoreHidden = ignore;
}
bool FolderWatcher::ignoreHidden()
{
return _ignoreHidden;
}
void FolderWatcher::addIgnoreListFile( const QString& file )
{
if( file.isEmpty() ) return;
@ -71,11 +82,15 @@ bool FolderWatcher::pathIsIgnored( const QString& path )
{
if( path.isEmpty() ) return true;
// if events caused by changes to hidden files should be ignored, a QFileInfo
// object will tell us if the file is hidden
if( _ignoreHidden ) {
QFileInfo fInfo(path);
if( fInfo.isHidden() ) {
qDebug() << "* Discarded as is hidden!" << fInfo.filePath();
return true;
}
}
// TODO: Best use csync_excluded_no_ctx() here somehow!
foreach (QString pattern, _ignores) {

View file

@ -77,6 +77,10 @@ public:
/* Check if the path is ignored. */
bool pathIsIgnored( const QString& path );
/* set if the folderwatcher ignores events of hidden files */
void setIgnoreHidden(bool ignore);
bool ignoreHidden();
signals:
/** Emitted when one of the watched directories or one
* of the contained files is changed. */
@ -98,6 +102,7 @@ private:
QStringList _ignores;
QTime _timer;
QSet<QString> _lastPaths;
bool _ignoreHidden;
friend class FolderWatcherPrivate;
};

View file

@ -57,6 +57,13 @@ IgnoreListEditor::IgnoreListEditor(QWidget *parent) :
ui->tableWidget->horizontalHeader()->setResizeMode(patternCol, QHeaderView::Stretch);
ui->tableWidget->verticalHeader()->setVisible(false);
/* value for syncing hidden files */
bool ignoreHidden = true;
if( FolderMan::instance()->map().count() > 0 ) {
ignoreHidden = FolderMan::instance()->map().first()->ignoreHiddenFiles();
}
ui->ignoreHiddenFilesCheckBox->setChecked( !ignoreHidden );
}
IgnoreListEditor::~IgnoreListEditor()
@ -64,6 +71,11 @@ IgnoreListEditor::~IgnoreListEditor()
delete ui;
}
bool IgnoreListEditor::ignoreHiddenFiles()
{
return ! ui->ignoreHiddenFilesCheckBox->isChecked();
}
void IgnoreListEditor::slotItemSelectionChanged()
{
QTableWidgetItem *item = ui->tableWidget->currentItem();
@ -110,6 +122,17 @@ void IgnoreListEditor::slotUpdateLocalIgnoreList()
QMessageBox::warning(this, tr("Could not open file"),
tr("Cannot write changes to '%1'.").arg(ignoreFile));
}
/* handle the hidden file checkbox */
bool ignoreHiddenFiles = ! ui->ignoreHiddenFilesCheckBox->isChecked();
/* the ignoreHiddenFiles flag is a folder specific setting, but for now, it is
* handled globally. Save it to every folder that is defined.
*/
foreach (Folder* folder, FolderMan::instance()->map()) {
folder->setIgnoreHiddenFiles(ignoreHiddenFiles);
folder->saveToSettings();
}
}
void IgnoreListEditor::slotAddPattern()

View file

@ -36,6 +36,8 @@ public:
explicit IgnoreListEditor(QWidget *parent = 0);
~IgnoreListEditor();
bool ignoreHiddenFiles();
private slots:
void slotItemSelectionChanged();
void slotRemoveCurrentItem();

View file

@ -6,48 +6,37 @@
<rect>
<x>0</x>
<y>0</y>
<width>471</width>
<height>359</height>
<width>438</width>
<height>463</height>
</rect>
</property>
<property name="windowTitle">
<string>Ignored Files Editor</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="enabled">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>213</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="addPushButton">
<property name="enabled">
<bool>true</bool>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Global Ignore Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="ignoreHiddenFilesCheckBox">
<property name="text">
<string>Add</string>
<string>Sync hidden files</string>
</property>
</widget>
</item>
<item row="2" column="1">
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Files Ingored by Patterns</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPushButton" name="removePushButton">
<property name="enabled">
<bool>true</bool>
@ -57,20 +46,17 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="descriptionLabel">
<item row="0" column="1">
<widget class="QPushButton" name="addPushButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
<string>Add</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="3">
<item row="0" column="0" rowspan="3">
<widget class="QTableWidget" name="tableWidget">
<property name="enabled">
<bool>true</bool>
@ -96,6 +82,45 @@
</column>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="enabled">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>213</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="descriptionLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View file

@ -311,6 +311,9 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file,QMap
if (!file_stat->etag || strlen(file_stat->etag) == 0) {
qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen.";
}
if( file.startsWith(QChar('.')) ) {
file_stat->flags = CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
//qDebug() << "!!!!" << file_stat << file_stat->name << file_stat->file_id << map.count();
_results.append(file_stat);
}

View file

@ -106,7 +106,8 @@ void FileSystem::setFileHidden(const QString& filename, bool hidden)
}
}
#else
Q_UNUSED(filename) Q_UNUSED(hidden)
Q_UNUSED(filename);
Q_UNUSED(hidden);
#endif
}

View file

@ -348,8 +348,24 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
if (file->remotePerm && file->remotePerm[0]) {
item->_remotePerm = QByteArray(file->remotePerm);
}
item->_should_update_metadata = item->_should_update_metadata || file->should_update_metadata;
/* The flag "serverHasIgnoredFiles" is true if item in question is a directory
* that has children which are ignored in sync, either because the files are
* matched by an ignore pattern, or because they are hidden.
*
* Only the information about the server side ignored files is stored to the
* database and thus written to the item here. For the local repository its
* generated by the walk through the real file tree by discovery phase.
*
* It needs to go to the sync journal becasue the stat information about remote
* files are often read from database rather than being pulled from remote.
*/
if( remote ) {
item->_serverHasIgnoredFiles = (file->has_ignored_files > 0);
}
// record the seen files to be able to clean the journal later
_seenFiles.insert(item->_file);
if (!renameTarget.isEmpty()) {
@ -376,6 +392,9 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME:
item->_errorString = tr("Filename is too long.");
break;
case CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN:
item->_errorString = tr("File is ignored because it's hidden.");
break;
case CYSNC_STATUS_FILE_LOCKED_OR_OPEN:
item->_errorString = QLatin1String("File locked"); // don't translate, internal use!
break;
@ -423,7 +442,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item->_type = SyncFileItem::UnknownType;
}
SyncFileItem::Direction dir;
SyncFileItem::Direction dir = SyncFileItem::None;
int re = 0;
switch(file->instruction) {

View file

@ -64,7 +64,7 @@ public:
};
SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false),
_hasBlacklistEntry(false), _status(NoStatus),
_serverHasIgnoredFiles(false), _hasBlacklistEntry(false), _status(NoStatus),
_isRestoration(false), _should_update_metadata(false),
_httpErrorCode(0), _requestDuration(0), _affectedItems(1),
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0), _size(0), _inode(0)
@ -130,6 +130,7 @@ public:
Type _type BITFIELD(3);
Direction _direction BITFIELD(2);
bool _isDirectory BITFIELD(1);
bool _serverHasIgnoredFiles BITFIELD(1);
/// Whether there's an entry in the blacklist table.
/// Note: that entry may have retries left, so this can be true

View file

@ -346,13 +346,13 @@ bool SyncJournalDb::checkConnect()
}
_getFileRecordQuery.reset(new SqlQuery(_db));
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize FROM "
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote FROM "
"metadata WHERE phash=?1" );
_setFileRecordQuery.reset(new SqlQuery(_db) );
_setFileRecordQuery->prepare("INSERT OR REPLACE INTO metadata "
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13);" );
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14);" );
_getDownloadInfoQuery.reset(new SqlQuery(_db) );
_getDownloadInfoQuery->prepare( "SELECT tmpfile, etag, errorcount FROM "
@ -516,6 +516,16 @@ bool SyncJournalDb::updateMetadataTableStructure()
commitInternal("update database structure: add pathlen index");
}
if( columns.indexOf(QLatin1String("ignoredChildrenRemote")) == -1 ) {
SqlQuery query(_db);
query.prepare("ALTER TABLE metadata ADD COLUMN ignoredChildrenRemote INT;");
if( !query.exec()) {
sqlFail("updateMetadataTableStructure: add ignoredChildrenRemote column", query);
re = false;
}
commitInternal("update database structure: add ignoredChildrenRemote col");
}
return re;
}
@ -630,6 +640,7 @@ bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& _record )
_setFileRecordQuery->bindValue(11, fileId );
_setFileRecordQuery->bindValue(12, remotePerm );
_setFileRecordQuery->bindValue(13, record._fileSize );
_setFileRecordQuery->bindValue(14, record._serverHasIgnoredFiles ? 1:0);
if( !_setFileRecordQuery->exec() ) {
qWarning() << "Error SQL statement setFileRecord: " << _setFileRecordQuery->lastQuery() << " :"
@ -640,7 +651,7 @@ bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& _record )
qDebug() << _setFileRecordQuery->lastQuery() << phash << plen << record._path << record._inode
<< record._mode
<< QString::number(Utility::qDateTimeToTime_t(record._modtime)) << QString::number(record._type)
<< record._etag << record._fileId << record._remotePerm << record._fileSize;
<< record._etag << record._fileId << record._remotePerm << record._fileSize << (record._serverHasIgnoredFiles ? 1:0);
_setFileRecordQuery->reset();
return true;
@ -719,6 +730,7 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
rec._fileId = _getFileRecordQuery->baValue(8);
rec._remotePerm = _getFileRecordQuery->baValue(9);
rec._fileSize = _getFileRecordQuery->int64Value(10);
rec._serverHasIgnoredFiles = (_getFileRecordQuery->intValue(11) > 0);
} else {
QString err = _getFileRecordQuery->error();
qDebug() << "No journal entry found for " << filename;

View file

@ -28,14 +28,14 @@
namespace OCC {
SyncJournalFileRecord::SyncJournalFileRecord()
:_inode(0), _type(0), _fileSize(0), _mode(0)
:_inode(0), _type(0), _fileSize(0), _mode(0), _serverHasIgnoredFiles(false)
{
}
SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QString &localFileName)
: _path(item._file), _modtime(Utility::qDateTimeFromTime_t(item._modtime)),
_type(item._type), _etag(item._etag), _fileId(item._fileId), _fileSize(item._size),
_remotePerm(item._remotePerm), _mode(0)
_remotePerm(item._remotePerm), _mode(0), _serverHasIgnoredFiles(item._serverHasIgnoredFiles)
{
// 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

View file

@ -46,6 +46,7 @@ public:
qint64 _fileSize;
QByteArray _remotePerm;
int _mode;
bool _serverHasIgnoredFiles;
};
bool OWNCLOUDSYNC_EXPORT