Skip to content

Commit

Permalink
Merge branch 'develop' into kdesktop-1252-handle-error-bad-netpath-li…
Browse files Browse the repository at this point in the history
…ke-file-not-found
  • Loading branch information
ClementKunz authored Oct 31, 2024
2 parents 840b45a + 17d8d57 commit 01fd0fc
Show file tree
Hide file tree
Showing 103 changed files with 1,556 additions and 1,346 deletions.
21 changes: 3 additions & 18 deletions src/gui/parametersdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,6 @@ QString ParametersDialog::getAppErrorText(QString fctCode, ExitCode exitCode, Ex
case ExitCode::Ok:
case ExitCode::NeedRestart:
case ExitCode::LogicError:
case ExitCode::NoWritePermission:
case ExitCode::TokenRefreshed:
case ExitCode::RateLimited:
case ExitCode::InvalidSync:
Expand All @@ -419,23 +418,14 @@ QString ParametersDialog::getAppErrorText(QString fctCode, ExitCode exitCode, Ex

QString ParametersDialog::getSyncPalSystemErrorText(const QString &err, ExitCause exitCause) const {
switch (exitCause) {
case ExitCause::NoSearchPermission:
return tr("The item misses search permission (error %1).<br>"
"Please check that you have search/exec access to the parent folder.")
.arg(err);
case ExitCause::SyncDirDoesntExist:
return tr("The synchronization folder is no longer accessible (error %1).<br>"
"Synchronization will resume as soon as the folder is accessible.")
.arg(err);

case ExitCause::SyncDirReadError:
return tr("The synchronization folder is inaccessible (error %1).<br>"
"Please check that you have read access to this folder.")
.arg(err);

case ExitCause::SyncDirWriteError:
case ExitCause::SyncDirAccesError:
return tr("The synchronization folder is inaccessible (error %1).<br>"
"Please check that you have write access to this folder.")
"Please check that you have read and write access to this folder.")
.arg(err);

case ExitCause::NotEnoughDiskSpace:
Expand Down Expand Up @@ -576,11 +566,6 @@ QString ParametersDialog::getSyncPalErrorText(QString fctCode, ExitCode exitCode
return tr("Nested synchronizations are prohibited (error %1).<br>"
"You should only keep synchronizations whose folders are not nested.")
.arg(err);
case ExitCode::NoWritePermission:
return tr(
"The app does not have write rights to the synchronization folder.<br>"
"The synchronization has been stopped.");
break;
case ExitCode::LogicError:
if (exitCause == ExitCause::FullListParsingError) {
return tr("File name parsing error (error %1).<br>"
Expand Down Expand Up @@ -839,7 +824,7 @@ QString ParametersDialog::getErrorLevelNodeText(const ErrorInfo &errorInfo) cons
if (errorInfo.exitCause() == ExitCause::FileAccessError) {
return tr(
"Can't access item.<br>"
"Please fix the write permissions and restart the synchronization.");
"Please fix the read and write permissions.");
}

if (errorInfo.exitCause() == ExitCause::MoveToTrashFailed) {
Expand Down
10 changes: 2 additions & 8 deletions src/libcommon/utility/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ std::string toString(const ExitCode e) {
return "LogicError";
case ExitCode::TokenRefreshed:
return "TokenRefreshed";
case ExitCode::NoWritePermission:
return "NoWritePermission";
case ExitCode::RateLimited:
return "RateLimited";
case ExitCode::InvalidSync:
Expand Down Expand Up @@ -134,10 +132,8 @@ std::string toString(const ExitCause e) {
return "InvalidSnapshot";
case ExitCause::SyncDirDoesntExist:
return "SyncDirDoesntExist";
case ExitCause::SyncDirReadError:
return "SyncDirReadError";
case ExitCause::SyncDirWriteError:
return "SyncDirWriteError";
case ExitCause::SyncDirAccesError:
return "SyncDirAccesError";
case ExitCause::HttpErr:
return "HttpErr";
case ExitCause::HttpErrForbidden:
Expand Down Expand Up @@ -190,8 +186,6 @@ std::string toString(const ExitCause e) {
return "NetworkTimeout";
case ExitCause::SocketsDefuncted:
return "SocketsDefuncted";
case ExitCause::NoSearchPermission:
return "NoSearchPermission";
case ExitCause::NotFound:
return "NotFound";
case ExitCause::QuotaExceeded:
Expand Down
67 changes: 41 additions & 26 deletions src/libcommon/utility/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,27 @@ static constexpr std::string_view clientSendEventFileName(
"kdrive_client.send.event"); // Name of the debug file generated by Sentry before_send callback of the client
} // namespace event_dump_files

// Concepts
template<class C> // Any enum class
concept EnumClass = std::is_enum_v<C>;

template<class C> // Any enum class that can be converted to (and from) int
concept IntegralEnum = EnumClass<C> && std::is_convertible_v<std::underlying_type_t<C>, int>;

template<class C> // Any enum class that can be printed (with enumClassToString)
concept PrintableEnum = EnumClass<C> && requires(C e) { toString(e); };

// Converters
template<IntegralEnum C>
inline constexpr int toInt(C e) {
return static_cast<int>(e);
}

template<IntegralEnum C>
inline constexpr C fromInt(int e) {
return static_cast<C>(e);
}

enum class AppType { None, Server, Client };
std::string toString(AppType e);

Expand Down Expand Up @@ -151,8 +172,8 @@ enum class OperationType { None = 0x00, Create = 0x01, Move = 0x02, Edit = 0x04,
std::string toString(OperationType e);

enum class ExitCode {
Unknown,
Ok,
Unknown,
NeedRestart, // A propagation job cannot be executed because the situation that led to its creation is no longer
// verified
NetworkError,
Expand All @@ -165,7 +186,6 @@ enum class ExitCode {
LogicError, // Consequence of faulty logic within the program such as violating logical preconditions or class
// invariants and may be preventable
TokenRefreshed,
NoWritePermission,
RateLimited,
InvalidSync, // The sync configuration is not valid
InvalidOperation,
Expand All @@ -183,8 +203,7 @@ enum class ExitCause {
DbEntryNotFound,
InvalidSnapshot,
SyncDirDoesntExist,
SyncDirReadError,
SyncDirWriteError,
SyncDirAccesError,
HttpErr,
HttpErrForbidden,
RedirectionError,
Expand All @@ -211,14 +230,30 @@ enum class ExitCause {
LiteSyncNotAllowed,
NetworkTimeout,
SocketsDefuncted, // macOS: sockets defuncted by kernel
NoSearchPermission,
NotFound,
QuotaExceeded,
FullListParsingError,
OperationCanceled
};
std::string toString(ExitCause e);

struct ExitInfo {
ExitInfo() = default;
constexpr ExitInfo(const ExitCode &code, const ExitCause &cause) : _code(code), _cause(cause) {}
ExitInfo(const ExitCode &code) : _code(code) {}
const ExitCode &code() const { return _code; }
const ExitCause &cause() const { return _cause; }
operator ExitCode() const { return _code; }
operator ExitCause() const { return _cause; }
constexpr operator bool() const { return _code == ExitCode::Ok; }
constexpr explicit operator int() const { return toInt(_code) * 100 + toInt(_cause); }
constexpr bool operator==(const ExitInfo &other) const { return _code == other._code && _cause == other._cause; }

private:
ExitCode _code{ExitCode::Unknown};
ExitCause _cause{ExitCause::Unknown};
};

// Conflict types ordered by priority
enum class ConflictType {
None,
Expand Down Expand Up @@ -506,28 +541,8 @@ using AppStateValue = std::variant<std::string, int, int64_t, LogUploadState>;
*/

// Concepts
template<class C> // Any enum class
concept EnumClass = std::is_enum_v<C>;

template<class C> // Any enum class that can be converted to (and from) int
concept IntableEnum = EnumClass<C> && std::is_convertible_v<std::underlying_type_t<C>, int>;

template<class C> // Any enum class we want to allow bitwise operations (OperationType & InconsistencyType)
concept AllowBitWiseOpEnum = IntableEnum<C> && (std::is_same_v<C, OperationType> || std::is_same_v<C, InconsistencyType>);

template<class C> // Any enum class that can be printed (with enumClassToString)
concept PrintableEnum = EnumClass<C> && requires(C e) { toString(e); };

// Converters
template<IntableEnum C>
inline int toInt(C e) {
return static_cast<int>(e);
}

template<IntableEnum C>
inline C fromInt(int e) {
return static_cast<C>(e);
}
concept AllowBitWiseOpEnum = IntegralEnum<C> && (std::is_same_v<C, OperationType> || std::is_same_v<C, InconsistencyType>);

// Operators
template<AllowBitWiseOpEnum C>
Expand Down
2 changes: 1 addition & 1 deletion src/libcommonserver/io/iohelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ bool IoHelper::DirectoryIterator::next(DirectoryEntry &nextEntry, bool &endOfDir
nextEntry = *_dirIterator;
return true;
} catch (std::filesystem::filesystem_error &) {
_dirIterator.disable_recursion_pending();
disableRecursionPending();
return next(nextEntry, endOfDirectory, ioError);
}

Expand Down
9 changes: 5 additions & 4 deletions src/libcommonserver/io/iohelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,15 @@ bool IoHelper::getFileStat(const SyncPath &path, FileStat *filestat, IoError &io
ioError = IoError::NoSuchFileOrDirectory;
return true;
}
if (counter) {
ioError = dWordError2ioError(dwError, logger());
if (counter && ioError != IoError::AccessDenied) {
retry = true;
Utility::msleep(10);
LOGW_DEBUG(logger(), L"Retrying to get handle: " << Utility::formatSyncPath(path.parent_path()).c_str());
counter--;
continue;
}

ioError = dWordError2ioError(dwError, logger());
LOGW_WARN(logger(), L"Error in CreateFileW: " << Utility::formatIoError(path.parent_path(), ioError).c_str());

return isExpectedError(ioError);
Expand Down Expand Up @@ -243,14 +243,15 @@ bool IoHelper::getFileStat(const SyncPath &path, FileStat *filestat, IoError &io
if ((isNtfs && !NT_SUCCESS(status)) ||
(!isNtfs && dwError != 0)) { // On FAT32 file system, NT_SUCCESS will return false even if it is a success, therefore we
// also check GetLastError
LOGW_DEBUG(logger(), L"Error in zwQueryDirectoryFile: " << Utility::formatSyncPath(path.parent_path()).c_str());
CloseHandle(hParent);

if (!NT_SUCCESS(status)) {
ioError = ntStatus2ioError(status);
} else if (dwError != 0) {
ioError = dWordError2ioError(dwError, logger());
}
LOGW_DEBUG(logger(), L"Error in zwQueryDirectoryFile: " << Utility::formatIoError(path, ioError));

return isExpectedError(ioError);
}

Expand Down Expand Up @@ -714,7 +715,7 @@ bool IoHelper::checkIfIsJunction(const SyncPath &path, bool &isJunction, IoError
ioError = IoError::Success;

HANDLE hFile =
CreateFileW(Path2WStr(path).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
CreateFileW(Path2WStr(path).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
ioError = dWordError2ioError(GetLastError(), logger());
Expand Down
33 changes: 25 additions & 8 deletions src/libcommonserver/utility/utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,19 @@ bool Utility::checkIfSameNormalization(const SyncPath &a, const SyncPath &b, boo
return true;
}

bool Utility::isDescendantOrEqual(const SyncPath &potentialChild, const SyncPath &path) {
if (path == potentialChild) return true;
for (auto it = potentialChild.begin(), it2 = path.begin(); it != potentialChild.end(); ++it, ++it2) {
if (it2 == path.end()) {
return true;
}
if (*it != *it2) {
return false;
}
}
return false;
}

bool Utility::moveItemToTrash(const SyncPath &itemPath) {
return moveItemToTrash_private(itemPath);
}
Expand Down Expand Up @@ -708,36 +721,40 @@ bool Utility::normalizedSyncPath(const SyncPath &path, SyncPath &normalizedPath)
return true;
}

bool Utility::checkIfDirEntryIsManaged(std::filesystem::recursive_directory_iterator &dirIt, bool &isManaged, bool &isLink,
bool Utility::checkIfDirEntryIsManaged(const std::filesystem::recursive_directory_iterator &dirIt, bool &isManaged, bool &isLink,
IoError &ioError) {
return checkIfDirEntryIsManaged(*dirIt, isManaged, isLink, ioError);
}

bool Utility::checkIfDirEntryIsManaged(const DirectoryEntry &dirEntry, bool &isManaged, bool &isLink, IoError &ioError) {
isManaged = true;
isLink = false;
ioError = IoError::Success;

ItemType itemType;
bool result = IoHelper::getItemType(dirIt->path(), itemType);
bool result = IoHelper::getItemType(dirEntry.path(), itemType);
ioError = itemType.ioError;
if (!result) {
LOGW_WARN(logger(), L"Error in IoHelper::getItemType: " << Utility::formatIoError(dirIt->path(), ioError).c_str());
LOGW_WARN(logger(), L"Error in IoHelper::getItemType: " << Utility::formatIoError(dirEntry.path(), ioError).c_str());
return false;
}

if (itemType.ioError == IoError::NoSuchFileOrDirectory || itemType.ioError == IoError::AccessDenied) {
LOGW_DEBUG(logger(), L"Error in IoHelper::getItemType: " << formatIoError(dirIt->path(), ioError).c_str());
LOGW_DEBUG(logger(), L"Error in IoHelper::getItemType: " << formatIoError(dirEntry.path(), ioError).c_str());
return true;
}

isLink = itemType.linkType != LinkType::None;
if (!dirIt->is_directory() && !dirIt->is_regular_file() && !isLink) {
LOGW_WARN(logger(), L"Ignore " << formatSyncPath(dirIt->path()).c_str()
if (!dirEntry.is_directory() && !dirEntry.is_regular_file() && !isLink) {
LOGW_WARN(logger(), L"Ignore " << formatSyncPath(dirEntry.path()).c_str()
<< L" because it's not a directory, a regular file or a symlink");
isManaged = false;
return true;
}

if (dirIt->path().native().length() > CommonUtility::maxPathLength()) {
if (dirEntry.path().native().length() > CommonUtility::maxPathLength()) {
LOGW_WARN(logger(),
L"Ignore " << formatSyncPath(dirIt->path()).c_str() << L" because size > " << CommonUtility::maxPathLength());
L"Ignore " << formatSyncPath(dirEntry.path()).c_str() << L" because size > " << CommonUtility::maxPathLength());
isManaged = false;
return true;
}
Expand Down
6 changes: 4 additions & 2 deletions src/libcommonserver/utility/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ struct COMMONSERVER_EXPORT Utility {
static bool endsWithInsensitive(const SyncName &str, const SyncName &suffix);
static bool isEqualInsensitive(const SyncName &a, const SyncName &b);
#endif
static bool isDescendantOrEqual(const SyncPath &potentialDescendant, const SyncPath &path);
/**
* Normalize the SyncName parameters before comparing them.
* @param a SyncName value to be compared.
Expand Down Expand Up @@ -165,8 +166,9 @@ struct COMMONSERVER_EXPORT Utility {
static bool longPath(const SyncPath &shortPathIn, SyncPath &longPathOut, bool &notFound);
static bool runDetachedProcess(std::wstring cmd);
#endif
static bool checkIfDirEntryIsManaged(std::filesystem::recursive_directory_iterator &dirIt, bool &isManaged, bool &isLink,
IoError &ioError);
static bool checkIfDirEntryIsManaged(const DirectoryEntry &dirEntry, bool &isManaged, bool &isLink, IoError &ioError);
static bool checkIfDirEntryIsManaged(const std::filesystem::recursive_directory_iterator &dirIt, bool &isManaged,
bool &isLink, IoError &ioError);

/* Resources analyser */
static bool totalRamAvailable(uint64_t &ram, int &errorCode);
Expand Down
1 change: 1 addition & 0 deletions src/libparms/db/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

#include "error.h"
#include "libcommonserver/utility/utility.h"

#include <ctime>
#include <sstream>
Expand Down
7 changes: 4 additions & 3 deletions src/libparms/db/parmsdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@

#define UPDATE_ERROR_REQUEST_ID "update_error"
#define UPDATE_ERROR_REQUEST \
"UPDATE error SET time=?1 " \
"WHERE dbId=?2;"
"UPDATE error SET time=?1, path=?2 " \
"WHERE dbId=?3;"

#define DELETE_ALL_ERROR_BY_EXITCODE_REQUEST_ID "delete_error_by_exitcode"
#define DELETE_ALL_ERROR_BY_EXITCODE_REQUEST \
Expand Down Expand Up @@ -2750,7 +2750,8 @@ bool ParmsDb::updateError(const Error &err, bool &found) {

ASSERT(queryResetAndClearBindings(UPDATE_ERROR_REQUEST_ID));
ASSERT(queryBindValue(UPDATE_ERROR_REQUEST_ID, 1, err.time()));
ASSERT(queryBindValue(UPDATE_ERROR_REQUEST_ID, 2, err.dbId()));
ASSERT(queryBindValue(UPDATE_ERROR_REQUEST_ID, 2, err.path()));
ASSERT(queryBindValue(UPDATE_ERROR_REQUEST_ID, 3, err.dbId()));
if (!queryExec(UPDATE_ERROR_REQUEST_ID, errId, error)) {
LOG_WARN(_logger, "Error running query: " << UPDATE_ERROR_REQUEST_ID);
return false;
Expand Down
Loading

0 comments on commit 01fd0fc

Please sign in to comment.