Skip to content

Commit 365d2d7

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 6f26503 commit 365d2d7

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
@@ -18,8 +18,8 @@ class Vfs;
1818

1919
csync_vio_handle_t OCSYNC_EXPORT *csync_vio_local_opendir(const QString &name);
2020
int OCSYNC_EXPORT csync_vio_local_closedir(csync_vio_handle_t *dhandle);
21-
std::unique_ptr<csync_file_stat_t> OCSYNC_EXPORT csync_vio_local_readdir(csync_vio_handle_t *dhandle, OCC::Vfs *vfs);
21+
std::unique_ptr<csync_file_stat_t> OCSYNC_EXPORT csync_vio_local_readdir(csync_vio_handle_t *dhandle, OCC::Vfs *vfs, bool checkPermissionsValidity);
2222

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

2525
#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
@@ -23,8 +23,8 @@
2323
#include "vio/csync_vio_local.h"
2424
#include "common/vfs.h"
2525

26-
#include <QtCore/QLoggingCategory>
27-
#include <QtCore/QFile>
26+
#include <QLoggingCategory>
27+
#include <QFile>
2828

2929
Q_LOGGING_CATEGORY(lcCSyncVIOLocal, "nextcloud.sync.csync.vio_local", QtInfoMsg)
3030

@@ -37,7 +37,7 @@ struct csync_vio_handle_t {
3737
QByteArray path;
3838
};
3939

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

4242
csync_vio_handle_t *csync_vio_local_opendir(const QString &name) {
4343
auto handle = std::make_unique<csync_vio_handle_t>();
@@ -59,7 +59,7 @@ int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
5959
return rc;
6060
}
6161

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

6464
struct _tdirent *dirent = nullptr;
6565
std::unique_ptr<csync_file_stat_t> file_stat;
@@ -102,7 +102,7 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
102102
if (file_stat->path.isNull())
103103
return file_stat;
104104

105-
if (_csync_vio_local_stat_mb(fullPath.constData(), file_stat.get()) < 0) {
105+
if (_csync_vio_local_stat_mb(fullPath.constData(), file_stat.get(), checkPermissionsValidity) < 0) {
106106
// Will get excluded by _csync_detect_update.
107107
file_stat->type = ItemTypeSkip;
108108
}
@@ -119,12 +119,12 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
119119
}
120120

121121

122-
int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf)
122+
int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf, bool checkPermissionsValidity)
123123
{
124-
return _csync_vio_local_stat_mb(QFile::encodeName(uri).constData(), buf);
124+
return _csync_vio_local_stat_mb(QFile::encodeName(uri).constData(), buf, checkPermissionsValidity);
125125
}
126126

127-
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf)
127+
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf, bool checkPermissionsValidity)
128128
{
129129
csync_stat_t sb;
130130

@@ -157,6 +157,9 @@ static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf
157157
buf->inode = sb.st_ino;
158158
buf->modtime = sb.st_mtime;
159159
buf->size = sb.st_size;
160+
if (checkPermissionsValidity) {
161+
buf->isPermissionsInvalid = (sb.st_mode & S_IWOTH) == S_IWOTH;
162+
}
160163

161164
return 0;
162165
}

src/libsync/discovery.cpp

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

10061006
if (!base.isDirectory()) {
10071007
csync_file_stat_t buf;
1008-
if (csync_vio_local_stat(_discoveryData->_localDir + originalPathAdjusted, &buf)) {
1008+
if (csync_vio_local_stat(_discoveryData->_localDir + originalPathAdjusted, &buf, true)) {
10091009
qCInfo(lcDisco) << "Local file does not exist anymore." << originalPathAdjusted;
10101010
return;
10111011
}
@@ -2331,7 +2331,7 @@ void ProcessDirectoryJob::setFolderQuota(const FolderQuota &folderQuota)
23312331
void ProcessDirectoryJob::startAsyncLocalQuery()
23322332
{
23332333
QString localPath = _discoveryData->_localDir + _currentFolder._local;
2334-
auto localJob = new DiscoverySingleLocalDirectoryJob(_discoveryData->_account, localPath, _discoveryData->_syncOptions._vfs.data());
2334+
auto localJob = new DiscoverySingleLocalDirectoryJob(_discoveryData->_account, localPath, _discoveryData->_syncOptions._vfs.data(), _discoveryData->_fileSystemReliablePermissions);
23352335

23362336
_discoveryData->_currentlyActiveJobs++;
23372337
_pendingAsyncJobs++;

src/libsync/discoveryphase.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,17 @@ void DiscoveryPhase::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
302302
}
303303
}
304304

305-
DiscoverySingleLocalDirectoryJob::DiscoverySingleLocalDirectoryJob(const AccountPtr &account, const QString &localPath, OCC::Vfs *vfs, QObject *parent)
306-
: QObject(parent), QRunnable(), _localPath(localPath), _account(account), _vfs(vfs)
305+
DiscoverySingleLocalDirectoryJob::DiscoverySingleLocalDirectoryJob(const AccountPtr &account,
306+
const QString &localPath,
307+
OCC::Vfs *vfs,
308+
bool fileSystemReliablePermissions,
309+
QObject *parent)
310+
: QObject{parent}
311+
, QRunnable{}
312+
, _localPath{localPath}
313+
, _account{account}
314+
, _vfs{vfs}
315+
, _fileSystemReliablePermissions{fileSystemReliablePermissions}
307316
{
308317
qRegisterMetaType<QVector<OCC::LocalInfo> >("QVector<OCC::LocalInfo>");
309318
}
@@ -336,7 +345,7 @@ void DiscoverySingleLocalDirectoryJob::run() {
336345
QVector<LocalInfo> results;
337346
while (true) {
338347
errno = 0;
339-
auto dirent = csync_vio_local_readdir(dh, _vfs);
348+
auto dirent = csync_vio_local_readdir(dh, _vfs, _fileSystemReliablePermissions);
340349
if (!dirent)
341350
break;
342351
if (dirent->type == ItemTypeSkip)

src/libsync/discoveryphase.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ class DiscoverySingleLocalDirectoryJob : public QObject, public QRunnable
7676
{
7777
Q_OBJECT
7878
public:
79-
explicit DiscoverySingleLocalDirectoryJob(const AccountPtr &account, const QString &localPath, OCC::Vfs *vfs, QObject *parent = nullptr);
79+
explicit DiscoverySingleLocalDirectoryJob(const AccountPtr &account,
80+
const QString &localPath,
81+
OCC::Vfs *vfs,
82+
bool fileSystemReliablePermissions,
83+
QObject *parent = nullptr);
8084

8185
void run() override;
8286
signals:
@@ -91,6 +95,7 @@ private slots:
9195
QString _localPath;
9296
AccountPtr _account;
9397
OCC::Vfs* _vfs;
98+
bool _fileSystemReliablePermissions = false;
9499
public:
95100
};
96101

@@ -315,6 +320,8 @@ class DiscoveryPhase : public QObject
315320

316321
bool _noCaseConflictRecordsInDb = false;
317322

323+
bool _fileSystemReliablePermissions = false;
324+
318325
QSet<QString> _topLevelE2eeFolderPaths;
319326

320327
signals:

src/libsync/filesystem.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ time_t FileSystem::getModTime(const QString &filename)
176176
{
177177
csync_file_stat_t stat;
178178
time_t result = -1;
179-
if (csync_vio_local_stat(filename, &stat) != -1 && (stat.modtime != 0)) {
179+
if (csync_vio_local_stat(filename, &stat, true) != -1 && (stat.modtime != 0)) {
180180
result = stat.modtime;
181181
} else {
182182
result = Utility::qDateTimeToTime_t(QFileInfo(filename).lastModified());
@@ -337,7 +337,7 @@ bool FileSystem::removeRecursively(const QString &path, const std::function<void
337337
bool FileSystem::getInode(const QString &filename, quint64 *inode)
338338
{
339339
csync_file_stat_t fs;
340-
if (csync_vio_local_stat(filename, &fs) == 0) {
340+
if (csync_vio_local_stat(filename, &fs, true) == 0) {
341341
*inode = fs.inode;
342342
return true;
343343
}

src/libsync/syncengine.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <QProcess>
4949
#include <QElapsedTimer>
5050
#include <QFileInfo>
51+
#include <QStorageInfo>
5152
#include <qtextcodec.h>
5253

5354
namespace OCC {
@@ -632,6 +633,19 @@ void SyncEngine::startSync()
632633
_remnantReadOnlyFolders.clear();
633634

634635
_discoveryPhase = std::make_unique<DiscoveryPhase>();
636+
637+
#if defined Q_OS_LINUX
638+
const auto fileSystemInfo = QStorageInfo{_localPath};
639+
qCInfo(lcEngine()) << "File system type for current sync folder:" << fileSystemInfo.fileSystemType();
640+
if (fileSystemInfo.fileSystemType() == "NTFS") {
641+
_discoveryPhase->_fileSystemReliablePermissions = false;
642+
} else {
643+
_discoveryPhase->_fileSystemReliablePermissions = true;
644+
}
645+
#else
646+
_discoveryPhase->_fileSystemReliablePermissions = true;
647+
#endif
648+
635649
_discoveryPhase->_leadingAndTrailingSpacesFilesAllowed = _leadingAndTrailingSpacesFilesAllowed;
636650
_discoveryPhase->_account = _account;
637651
_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
@@ -135,7 +135,7 @@ static void create_dirs( const char *path )
135135
* whole tree.
136136
*
137137
*/
138-
static void traverse_dir(void **state, const QString &dir, int *cnt)
138+
static void traverse_dir(void **state, const QString &dir, int *cnt, bool checkPermissionsValidity)
139139
{
140140
csync_vio_handle_t *dh = nullptr;
141141
std::unique_ptr<csync_file_stat_t> dirent;
@@ -149,7 +149,7 @@ static void traverse_dir(void **state, const QString &dir, int *cnt)
149149
assert_non_null(dh);
150150

151151
OCC::Vfs *vfs = nullptr;
152-
while( (dirent = csync_vio_local_readdir(dh, vfs)) ) {
152+
while( (dirent = csync_vio_local_readdir(dh, vfs, checkPermissionsValidity)) ) {
153153
assert_non_null(dirent.get());
154154
if (!dirent->original_path.isEmpty()) {
155155
sv->ignored_dir = dirent->original_path;
@@ -178,7 +178,7 @@ static void traverse_dir(void **state, const QString &dir, int *cnt)
178178
}
179179
output(subdir_out.constData());
180180
if( is_dir ) {
181-
traverse_dir(state, QString::fromUtf8(subdir), cnt);
181+
traverse_dir(state, QString::fromUtf8(subdir), cnt, checkPermissionsValidity);
182182
}
183183
}
184184

@@ -198,11 +198,12 @@ static void check_readdir_shorttree(void **state)
198198
{
199199
auto sv = (statevar*) *state;
200200

201+
bool checkPermissionsValidity = true;
201202
const char *t1 = "alibaba/und/die/vierzig/räuber/";
202203
create_dirs( t1 );
203204
int files_cnt = 0;
204205

205-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
206+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
206207

207208
assert_string_equal(sv->result.constData(),
208209
QString::fromUtf8("<DIR> %1/alibaba"
@@ -221,14 +222,15 @@ static void check_readdir_with_content(void **state)
221222
auto sv = (statevar*) *state;
222223
int files_cnt = 0;
223224

225+
bool checkPermissionsValidity = true;
224226
const char *t1 = "warum/nur/40/Räuber/";
225227
create_dirs( t1 );
226228

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

230232

231-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
233+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
232234

233235
assert_string_equal(sv->result.constData(),
234236
QString::fromUtf8("<DIR> %1/warum"
@@ -247,6 +249,8 @@ static void check_readdir_longtree(void **state)
247249
{
248250
auto sv = (statevar*) *state;
249251

252+
bool checkPermissionsValidity = true;
253+
250254
/* Strange things here: Compilers only support strings with length of 4k max.
251255
* The expected result string is longer, so it needs to be split up in r1, r2 and r3
252256
*/
@@ -306,7 +310,7 @@ static void check_readdir_longtree(void **state)
306310
/* assemble the result string ... */
307311
const auto result = (r1 + r2 + r3).toUtf8();
308312
int files_cnt = 0;
309-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
313+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
310314
assert_int_equal(files_cnt, 0);
311315
/* and compare. */
312316
assert_string_equal(sv->result.constData(), result.constData());
@@ -321,6 +325,7 @@ static void check_readdir_bigunicode(void **state)
321325
// 3: ? ASCII: 191 - BF
322326
// 4: ASCII: 32 - 20
323327

328+
bool checkPermissionsValidity = true;
324329
QString p = QStringLiteral("%1/%2").arg(CSYNC_TEST_DIR, QStringLiteral("goodone/"));
325330
int rc = oc_mkdir(p);
326331
assert_int_equal(rc, 0);
@@ -332,7 +337,7 @@ static void check_readdir_bigunicode(void **state)
332337
assert_int_equal(rc, 0);
333338

334339
int files_cnt = 0;
335-
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
340+
traverse_dir(state, CSYNC_TEST_DIR, &files_cnt, checkPermissionsValidity);
336341
const auto expected_result = QStringLiteral("<DIR> %1/goodone"
337342
"<DIR> %1/goodone/ugly\xEF\xBB\xBF\x32.txt")
338343
.arg(CSYNC_TEST_DIR);

test/testlongpath.cpp

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

130130
csync_file_stat_t buf;
131-
QVERIFY(csync_vio_local_stat(longPath.filePath(), &buf) != -1);
131+
QVERIFY(csync_vio_local_stat(longPath.filePath(), &buf, true) != -1);
132132
QVERIFY(buf.size == data.size());
133133
QVERIFY(buf.size == longPath.size());
134134

0 commit comments

Comments
 (0)