Skip to content

Commit c67aa8d

Browse files
committed
detect NTFS file system type to avoid permissions check
NTFS file system on Linux reports wrong permissions client believes they need to be fixed but as they cannot, we end-up having an infinite loop Signed-off-by: Matthieu Gallien <[email protected]>
1 parent 5a4ded1 commit c67aa8d

File tree

9 files changed

+64
-26
lines changed

9 files changed

+64
-26
lines changed

src/csync/vio/csync_vio_local.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class Vfs;
3030

3131
csync_vio_handle_t OCSYNC_EXPORT *csync_vio_local_opendir(const QString &name);
3232
int OCSYNC_EXPORT csync_vio_local_closedir(csync_vio_handle_t *dhandle);
33-
std::unique_ptr<csync_file_stat_t> OCSYNC_EXPORT csync_vio_local_readdir(csync_vio_handle_t *dhandle, OCC::Vfs *vfs);
33+
std::unique_ptr<csync_file_stat_t> OCSYNC_EXPORT csync_vio_local_readdir(csync_vio_handle_t *dhandle, OCC::Vfs *vfs, bool checkPermissionsValidity);
3434

35-
int OCSYNC_EXPORT csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf);
35+
int OCSYNC_EXPORT csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf, bool checkPermissionsValidity);
3636

3737
#endif /* _CSYNC_VIO_LOCAL_H */

src/csync/vio/csync_vio_local_unix.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
#include "vio/csync_vio_local.h"
3636
#include "common/vfs.h"
3737

38-
#include <QtCore/QLoggingCategory>
39-
#include <QtCore/QFile>
38+
#include <QLoggingCategory>
39+
#include <QFile>
4040

4141
Q_LOGGING_CATEGORY(lcCSyncVIOLocal, "nextcloud.sync.csync.vio_local", QtInfoMsg)
4242

@@ -49,7 +49,7 @@ struct csync_vio_handle_t {
4949
QByteArray path;
5050
};
5151

52-
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf);
52+
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf, bool checkPermissionsValidity);
5353

5454
csync_vio_handle_t *csync_vio_local_opendir(const QString &name) {
5555
auto handle = std::make_unique<csync_vio_handle_t>();
@@ -71,7 +71,7 @@ int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
7171
return rc;
7272
}
7373

74-
std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *handle, OCC::Vfs *vfs) {
74+
std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *handle, OCC::Vfs *vfs, bool checkPermissionsValidity) {
7575

7676
struct _tdirent *dirent = nullptr;
7777
std::unique_ptr<csync_file_stat_t> file_stat;
@@ -114,7 +114,7 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
114114
if (file_stat->path.isNull())
115115
return file_stat;
116116

117-
if (_csync_vio_local_stat_mb(fullPath.constData(), file_stat.get()) < 0) {
117+
if (_csync_vio_local_stat_mb(fullPath.constData(), file_stat.get(), checkPermissionsValidity) < 0) {
118118
// Will get excluded by _csync_detect_update.
119119
file_stat->type = ItemTypeSkip;
120120
}
@@ -131,12 +131,12 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
131131
}
132132

133133

134-
int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf)
134+
int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf, bool checkPermissionsValidity)
135135
{
136-
return _csync_vio_local_stat_mb(QFile::encodeName(uri).constData(), buf);
136+
return _csync_vio_local_stat_mb(QFile::encodeName(uri).constData(), buf, checkPermissionsValidity);
137137
}
138138

139-
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf)
139+
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf, bool checkPermissionsValidity)
140140
{
141141
csync_stat_t sb;
142142

@@ -169,6 +169,9 @@ static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf
169169
buf->inode = sb.st_ino;
170170
buf->modtime = sb.st_mtime;
171171
buf->size = sb.st_size;
172+
if (checkPermissionsValidity) {
173+
buf->isPermissionsInvalid = (sb.st_mode & S_IWOTH) == S_IWOTH;
174+
}
172175

173176
return 0;
174177
}

src/libsync/discovery.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
943943

944944
if (!base.isDirectory()) {
945945
csync_file_stat_t buf;
946-
if (csync_vio_local_stat(_discoveryData->_localDir + originalPathAdjusted, &buf)) {
946+
if (csync_vio_local_stat(_discoveryData->_localDir + originalPathAdjusted, &buf, true)) {
947947
qCInfo(lcDisco) << "Local file does not exist anymore." << originalPathAdjusted;
948948
return;
949949
}
@@ -2137,7 +2137,7 @@ DiscoverySingleDirectoryJob *ProcessDirectoryJob::startAsyncServerQuery()
21372137
void ProcessDirectoryJob::startAsyncLocalQuery()
21382138
{
21392139
QString localPath = _discoveryData->_localDir + _currentFolder._local;
2140-
auto localJob = new DiscoverySingleLocalDirectoryJob(_discoveryData->_account, localPath, _discoveryData->_syncOptions._vfs.data());
2140+
auto localJob = new DiscoverySingleLocalDirectoryJob(_discoveryData->_account, localPath, _discoveryData->_syncOptions._vfs.data(), _discoveryData->_fileSystemReliablePermissions);
21412141

21422142
_discoveryData->_currentlyActiveJobs++;
21432143
_pendingAsyncJobs++;

src/libsync/discoveryphase.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,17 @@ void DiscoveryPhase::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
284284
}
285285
}
286286

287-
DiscoverySingleLocalDirectoryJob::DiscoverySingleLocalDirectoryJob(const AccountPtr &account, const QString &localPath, OCC::Vfs *vfs, QObject *parent)
288-
: QObject(parent), QRunnable(), _localPath(localPath), _account(account), _vfs(vfs)
287+
DiscoverySingleLocalDirectoryJob::DiscoverySingleLocalDirectoryJob(const AccountPtr &account,
288+
const QString &localPath,
289+
OCC::Vfs *vfs,
290+
bool fileSystemReliablePermissions,
291+
QObject *parent)
292+
: QObject{parent}
293+
, QRunnable{}
294+
, _localPath{localPath}
295+
, _account{account}
296+
, _vfs{vfs}
297+
, _fileSystemReliablePermissions{fileSystemReliablePermissions}
289298
{
290299
qRegisterMetaType<QVector<OCC::LocalInfo> >("QVector<OCC::LocalInfo>");
291300
}
@@ -318,7 +327,7 @@ void DiscoverySingleLocalDirectoryJob::run() {
318327
QVector<LocalInfo> results;
319328
while (true) {
320329
errno = 0;
321-
auto dirent = csync_vio_local_readdir(dh, _vfs);
330+
auto dirent = csync_vio_local_readdir(dh, _vfs, _fileSystemReliablePermissions);
322331
if (!dirent)
323332
break;
324333
if (dirent->type == ItemTypeSkip)

src/libsync/discoveryphase.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ class DiscoverySingleLocalDirectoryJob : public QObject, public QRunnable
119119
{
120120
Q_OBJECT
121121
public:
122-
explicit DiscoverySingleLocalDirectoryJob(const AccountPtr &account, const QString &localPath, OCC::Vfs *vfs, QObject *parent = nullptr);
122+
explicit DiscoverySingleLocalDirectoryJob(const AccountPtr &account,
123+
const QString &localPath,
124+
OCC::Vfs *vfs,
125+
bool fileSystemReliablePermissions,
126+
QObject *parent = nullptr);
123127

124128
void run() override;
125129
signals:
@@ -134,6 +138,7 @@ private slots:
134138
QString _localPath;
135139
AccountPtr _account;
136140
OCC::Vfs* _vfs;
141+
bool _fileSystemReliablePermissions = false;
137142
public:
138143
};
139144

@@ -343,6 +348,8 @@ class DiscoveryPhase : public QObject
343348

344349
bool _noCaseConflictRecordsInDb = false;
345350

351+
bool _fileSystemReliablePermissions = false;
352+
346353
QSet<QString> _topLevelE2eeFolderPaths;
347354

348355
signals:

src/libsync/filesystem.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ time_t FileSystem::getModTime(const QString &filename)
184184
{
185185
csync_file_stat_t stat;
186186
time_t result = -1;
187-
if (csync_vio_local_stat(filename, &stat) != -1 && (stat.modtime != 0)) {
187+
if (csync_vio_local_stat(filename, &stat, true) != -1 && (stat.modtime != 0)) {
188188
result = stat.modtime;
189189
} else {
190190
result = Utility::qDateTimeToTime_t(QFileInfo(filename).lastModified());
@@ -319,7 +319,7 @@ bool FileSystem::removeRecursively(const QString &path, const std::function<void
319319
bool FileSystem::getInode(const QString &filename, quint64 *inode)
320320
{
321321
csync_file_stat_t fs;
322-
if (csync_vio_local_stat(filename, &fs) == 0) {
322+
if (csync_vio_local_stat(filename, &fs, true) == 0) {
323323
*inode = fs.inode;
324324
return true;
325325
}

src/libsync/syncengine.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <QProcess>
5858
#include <QElapsedTimer>
5959
#include <QFileInfo>
60+
#include <QStorageInfo>
6061
#include <qtextcodec.h>
6162

6263
namespace OCC {
@@ -638,6 +639,19 @@ void SyncEngine::startSync()
638639
_remnantReadOnlyFolders.clear();
639640

640641
_discoveryPhase = std::make_unique<DiscoveryPhase>();
642+
643+
#if defined Q_OS_LINUX
644+
const auto fileSystemInfo = QStorageInfo{_localPath};
645+
qCInfo(lcEngine()) << "File system type for current sync folder:" << fileSystemInfo.fileSystemType();
646+
if (fileSystemInfo.fileSystemType() == "NTFS") {
647+
_discoveryPhase->_fileSystemReliablePermissions = false;
648+
} else {
649+
_discoveryPhase->_fileSystemReliablePermissions = true;
650+
}
651+
#else
652+
_discoveryPhase->_fileSystemReliablePermissions = true;
653+
#endif
654+
641655
_discoveryPhase->_leadingAndTrailingSpacesFilesAllowed = _leadingAndTrailingSpacesFilesAllowed;
642656
_discoveryPhase->_account = _account;
643657
_discoveryPhase->_excludes = _excludedFiles.data();

test/csync/vio_tests/check_vio_ext.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static void create_dirs( const char *path )
147147
* whole tree.
148148
*
149149
*/
150-
static void traverse_dir(void **state, const QString &dir, int *cnt)
150+
static void traverse_dir(void **state, const QString &dir, int *cnt, bool checkPermissionsValidity)
151151
{
152152
csync_vio_handle_t *dh = nullptr;
153153
std::unique_ptr<csync_file_stat_t> dirent;
@@ -161,7 +161,7 @@ static void traverse_dir(void **state, const QString &dir, int *cnt)
161161
assert_non_null(dh);
162162

163163
OCC::Vfs *vfs = nullptr;
164-
while( (dirent = csync_vio_local_readdir(dh, vfs)) ) {
164+
while( (dirent = csync_vio_local_readdir(dh, vfs, checkPermissionsValidity)) ) {
165165
assert_non_null(dirent.get());
166166
if (!dirent->original_path.isEmpty()) {
167167
sv->ignored_dir = dirent->original_path;
@@ -190,7 +190,7 @@ static void traverse_dir(void **state, const QString &dir, int *cnt)
190190
}
191191
output(subdir_out.constData());
192192
if( is_dir ) {
193-
traverse_dir(state, QString::fromUtf8(subdir), cnt);
193+
traverse_dir(state, QString::fromUtf8(subdir), cnt, checkPermissionsValidity);
194194
}
195195
}
196196

@@ -210,11 +210,12 @@ static void check_readdir_shorttree(void **state)
210210
{
211211
auto sv = (statevar*) *state;
212212

213+
bool checkPermissionsValidity = true;
213214
const char *t1 = "alibaba/und/die/vierzig/räuber/";
214215
create_dirs( t1 );
215216
int files_cnt = 0;
216217

217-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
218+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
218219

219220
assert_string_equal(sv->result.constData(),
220221
QString::fromUtf8("<DIR> %1/alibaba"
@@ -233,14 +234,15 @@ static void check_readdir_with_content(void **state)
233234
auto sv = (statevar*) *state;
234235
int files_cnt = 0;
235236

237+
bool checkPermissionsValidity = true;
236238
const char *t1 = "warum/nur/40/Räuber/";
237239
create_dirs( t1 );
238240

239241
create_file( t1, "Räuber Max.txt", "Der Max ist ein schlimmer finger");
240242
create_file( t1, "пя́тница.txt", "Am Freitag tanzt der Ürk");
241243

242244

243-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
245+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
244246

245247
assert_string_equal(sv->result.constData(),
246248
QString::fromUtf8("<DIR> %1/warum"
@@ -259,6 +261,8 @@ static void check_readdir_longtree(void **state)
259261
{
260262
auto sv = (statevar*) *state;
261263

264+
bool checkPermissionsValidity = true;
265+
262266
/* Strange things here: Compilers only support strings with length of 4k max.
263267
* The expected result string is longer, so it needs to be split up in r1, r2 and r3
264268
*/
@@ -318,7 +322,7 @@ static void check_readdir_longtree(void **state)
318322
/* assemble the result string ... */
319323
const auto result = (r1 + r2 + r3).toUtf8();
320324
int files_cnt = 0;
321-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
325+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
322326
assert_int_equal(files_cnt, 0);
323327
/* and compare. */
324328
assert_string_equal(sv->result.constData(), result.constData());
@@ -333,6 +337,7 @@ static void check_readdir_bigunicode(void **state)
333337
// 3: ? ASCII: 191 - BF
334338
// 4: ASCII: 32 - 20
335339

340+
bool checkPermissionsValidity = true;
336341
QString p = QStringLiteral("%1/%2").arg(CSYNC_TEST_DIR, QStringLiteral("goodone/"));
337342
int rc = oc_mkdir(p);
338343
assert_int_equal(rc, 0);
@@ -344,7 +349,7 @@ static void check_readdir_bigunicode(void **state)
344349
assert_int_equal(rc, 0);
345350

346351
int files_cnt = 0;
347-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
352+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
348353
const auto expected_result = QStringLiteral("<DIR> %1/goodone"
349354
"<DIR> %1/goodone/ugly\xEF\xBB\xBF\x32.txt")
350355
.arg(CSYNC_TEST_DIR);

test/testlongpath.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ private Q_SLOTS:
139139
file.close();
140140

141141
csync_file_stat_t buf;
142-
QVERIFY(csync_vio_local_stat(longPath.filePath(), &buf) != -1);
142+
QVERIFY(csync_vio_local_stat(longPath.filePath(), &buf, true) != -1);
143143
QVERIFY(buf.size == data.size());
144144
QVERIFY(buf.size == longPath.size());
145145

0 commit comments

Comments
 (0)