diff --git a/src/common/common.cmake b/src/common/common.cmake index a26e76d74..ab1ca1e83 100644 --- a/src/common/common.cmake +++ b/src/common/common.cmake @@ -2,5 +2,6 @@ # Essentially they could be in the same directory but are separate to # help keep track of the different code licenses. set(common_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/filesystembase.cpp ${CMAKE_CURRENT_LIST_DIR}/utility.cpp ) diff --git a/src/common/filesystembase.cpp b/src/common/filesystembase.cpp new file mode 100644 index 000000000..879b2f85c --- /dev/null +++ b/src/common/filesystembase.cpp @@ -0,0 +1,488 @@ +/* + * Copyright (C) by Daniel Molkentin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "filesystembase.h" + +#include +#include +#include + +#include +#include + +#ifdef ZLIB_FOUND +#include +#endif + +#ifdef Q_OS_WIN +#include +#include +#include +#include +#include +#endif + +namespace OCC { + +Q_LOGGING_CATEGORY(lcFileSystem, "sync.filesystem", QtInfoMsg) + +QString FileSystem::longWinPath(const QString &inpath) +{ +#ifdef Q_OS_WIN + return pathtoUNC(inpath); +#else + return inpath; +#endif +} + +void FileSystem::setFileHidden(const QString &filename, bool hidden) +{ +#ifdef _WIN32 + QString fName = longWinPath(filename); + DWORD dwAttrs; + + dwAttrs = GetFileAttributesW((wchar_t *)fName.utf16()); + + if (dwAttrs != INVALID_FILE_ATTRIBUTES) { + if (hidden && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) { + SetFileAttributesW((wchar_t *)fName.utf16(), dwAttrs | FILE_ATTRIBUTE_HIDDEN); + } else if (!hidden && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) { + SetFileAttributesW((wchar_t *)fName.utf16(), dwAttrs & ~FILE_ATTRIBUTE_HIDDEN); + } + } +#else + Q_UNUSED(filename); + Q_UNUSED(hidden); +#endif +} + +static QFile::Permissions getDefaultWritePermissions() +{ + QFile::Permissions result = QFile::WriteUser; +#ifndef Q_OS_WIN + mode_t mask = umask(0); + umask(mask); + if (!(mask & S_IWGRP)) { + result |= QFile::WriteGroup; + } + if (!(mask & S_IWOTH)) { + result |= QFile::WriteOther; + } +#endif + return result; +} + +void FileSystem::setFileReadOnly(const QString &filename, bool readonly) +{ + QFile file(filename); + QFile::Permissions permissions = file.permissions(); + + QFile::Permissions allWritePermissions = + QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther | QFile::WriteOwner; + static QFile::Permissions defaultWritePermissions = getDefaultWritePermissions(); + + permissions &= ~allWritePermissions; + if (!readonly) { + permissions |= defaultWritePermissions; + } + file.setPermissions(permissions); +} + +void FileSystem::setFolderMinimumPermissions(const QString &filename) +{ +#ifdef Q_OS_MAC + QFile::Permissions perm = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner; + QFile file(filename); + file.setPermissions(perm); +#else + Q_UNUSED(filename); +#endif +} + + +void FileSystem::setFileReadOnlyWeak(const QString &filename, bool readonly) +{ + QFile file(filename); + QFile::Permissions permissions = file.permissions(); + + if (!readonly && (permissions & QFile::WriteOwner)) { + return; // already writable enough + } + + setFileReadOnly(filename, readonly); +} + +bool FileSystem::rename(const QString &originFileName, + const QString &destinationFileName, + QString *errorString) +{ + bool success = false; + QString error; +#ifdef Q_OS_WIN + QString orig = longWinPath(originFileName); + QString dest = longWinPath(destinationFileName); + + if (isLnkFile(originFileName) || isLnkFile(destinationFileName)) { + success = MoveFileEx((wchar_t *)orig.utf16(), + (wchar_t *)dest.utf16(), + MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH); + if (!success) { + wchar_t *string = 0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&string, 0, NULL); + + error = QString::fromWCharArray(string); + LocalFree((HLOCAL)string); + } + } else +#endif + { + QFile orig(originFileName); + success = orig.rename(destinationFileName); + if (!success) { + error = orig.errorString(); + } + } + + if (!success) { + qCWarning(lcFileSystem) << "Error renaming file" << originFileName + << "to" << destinationFileName + << "failed: " << error; + if (errorString) { + *errorString = error; + } + } + return success; +} + +bool FileSystem::uncheckedRenameReplace(const QString &originFileName, + const QString &destinationFileName, + QString *errorString) +{ +#ifndef Q_OS_WIN + bool success; + QFile orig(originFileName); + // We want a rename that also overwites. QFile::rename does not overwite. + // Qt 5.1 has QSaveFile::renameOverwrite we could use. + // ### FIXME + success = true; + bool destExists = fileExists(destinationFileName); + if (destExists && !QFile::remove(destinationFileName)) { + *errorString = orig.errorString(); + qCWarning(lcFileSystem) << "Target file could not be removed."; + success = false; + } + if (success) { + success = orig.rename(destinationFileName); + } + if (!success) { + *errorString = orig.errorString(); + qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; + return false; + } + +#else //Q_OS_WIN + // You can not overwrite a read-only file on windows. + if (!QFileInfo(destinationFileName).isWritable()) { + setFileReadOnly(destinationFileName, false); + } + + BOOL ok; + QString orig = longWinPath(originFileName); + QString dest = longWinPath(destinationFileName); + + ok = MoveFileEx((wchar_t *)orig.utf16(), + (wchar_t *)dest.utf16(), + MOVEFILE_REPLACE_EXISTING + MOVEFILE_COPY_ALLOWED + MOVEFILE_WRITE_THROUGH); + if (!ok) { + wchar_t *string = 0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&string, 0, NULL); + + *errorString = QString::fromWCharArray(string); + qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; + LocalFree((HLOCAL)string); + return false; + } +#endif + return true; +} + +bool FileSystem::openAndSeekFileSharedRead(QFile *file, QString *errorOrNull, qint64 seek) +{ + QString errorDummy; + // avoid many if (errorOrNull) later. + QString &error = errorOrNull ? *errorOrNull : errorDummy; + error.clear(); + +#ifdef Q_OS_WIN + // + // The following code is adapted from Qt's QFSFileEnginePrivate::nativeOpen() + // by including the FILE_SHARE_DELETE share mode. + // + + // Enable full sharing. + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + int accessRights = GENERIC_READ; + DWORD creationDisp = OPEN_EXISTING; + + // Create the file handle. + SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; + QString fName = longWinPath(file->fileName()); + + HANDLE fileHandle = CreateFileW( + (const wchar_t *)fName.utf16(), + accessRights, + shareMode, + &securityAtts, + creationDisp, + FILE_ATTRIBUTE_NORMAL, + NULL); + + // Bail out on error. + if (fileHandle == INVALID_HANDLE_VALUE) { + error = qt_error_string(); + return false; + } + + // Convert the HANDLE to an fd and pass it to QFile's foreign-open + // function. The fd owns the handle, so when QFile later closes + // the fd the handle will be closed too. + int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY); + if (fd == -1) { + error = "could not make fd from handle"; + return false; + } + if (!file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle)) { + error = file->errorString(); + return false; + } + + // Seek to the right spot + LARGE_INTEGER *li = reinterpret_cast(&seek); + DWORD newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN); + if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { + error = qt_error_string(); + return false; + } + + return true; +#else + if (!file->open(QFile::ReadOnly)) { + error = file->errorString(); + return false; + } + if (!file->seek(seek)) { + error = file->errorString(); + return false; + } + return true; +#endif +} + +#ifdef Q_OS_WIN +static bool fileExistsWin(const QString &filename) +{ + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + QString fName = FileSystem::longWinPath(filename); + + hFind = FindFirstFileW((wchar_t *)fName.utf16(), &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) { + return false; + } + FindClose(hFind); + return true; +} +#endif + +bool FileSystem::fileExists(const QString &filename, const QFileInfo &fileInfo) +{ +#ifdef Q_OS_WIN + if (isLnkFile(filename)) { + // Use a native check. + return fileExistsWin(filename); + } +#endif + bool re = fileInfo.exists(); + // if the filename is different from the filename in fileInfo, the fileInfo is + // not valid. There needs to be one initialised here. Otherwise the incoming + // fileInfo is re-used. + if (fileInfo.filePath() != filename) { + QFileInfo myFI(filename); + re = myFI.exists(); + } + return re; +} + +#ifdef Q_OS_WIN +QString FileSystem::fileSystemForPath(const QString &path) +{ + // See also QStorageInfo (Qt >=5.4) and GetVolumeInformationByHandleW (>= Vista) + QString drive = path.left(2); + if (!drive.endsWith(":")) + return QString(); + drive.append('\\'); + + const size_t fileSystemBufferSize = 4096; + TCHAR fileSystemBuffer[fileSystemBufferSize]; + + if (!GetVolumeInformationW( + reinterpret_cast(drive.utf16()), + NULL, 0, + NULL, NULL, NULL, + fileSystemBuffer, fileSystemBufferSize)) { + return QString(); + } + return QString::fromUtf16(reinterpret_cast(fileSystemBuffer)); +} +#endif + +#define BUFSIZE qint64(500 * 1024) // 500 KiB + +static QByteArray readToCrypto(const QString &filename, QCryptographicHash::Algorithm algo) +{ + QFile file(filename); + const qint64 bufSize = qMin(BUFSIZE, file.size() + 1); + QByteArray buf(bufSize, Qt::Uninitialized); + QByteArray arr; + QCryptographicHash crypto(algo); + + if (file.open(QIODevice::ReadOnly)) { + qint64 size; + while (!file.atEnd()) { + size = file.read(buf.data(), bufSize); + if (size > 0) { + crypto.addData(buf.data(), size); + } + } + arr = crypto.result().toHex(); + } + return arr; +} + +QByteArray FileSystem::calcMd5(const QString &filename) +{ + return readToCrypto(filename, QCryptographicHash::Md5); +} + +QByteArray FileSystem::calcSha1(const QString &filename) +{ + return readToCrypto(filename, QCryptographicHash::Sha1); +} + +#ifdef ZLIB_FOUND +QByteArray FileSystem::calcAdler32(const QString &filename) +{ + QFile file(filename); + const qint64 bufSize = qMin(BUFSIZE, file.size() + 1); + QByteArray buf(bufSize, Qt::Uninitialized); + + unsigned int adler = adler32(0L, Z_NULL, 0); + if (file.open(QIODevice::ReadOnly)) { + qint64 size; + while (!file.atEnd()) { + size = file.read(buf.data(), bufSize); + if (size > 0) + adler = adler32(adler, (const Bytef *)buf.data(), size); + } + } + + return QByteArray::number(adler, 16); +} +#endif + +QString FileSystem::makeConflictFileName(const QString &fn, const QDateTime &dt) +{ + QString conflictFileName(fn); + // Add _conflict-XXXX before the extension. + int dotLocation = conflictFileName.lastIndexOf('.'); + // If no extension, add it at the end (take care of cases like foo/.hidden or foo.bar/file) + if (dotLocation <= conflictFileName.lastIndexOf('/') + 1) { + dotLocation = conflictFileName.size(); + } + QString timeString = dt.toString("yyyyMMdd-hhmmss"); + + // Additional marker + QByteArray conflictFileUserName = qgetenv("CSYNC_CONFLICT_FILE_USERNAME"); + if (conflictFileUserName.isEmpty()) + conflictFileName.insert(dotLocation, "_conflict-" + timeString); + else + conflictFileName.insert(dotLocation, "_conflict_" + QString::fromUtf8(conflictFileUserName) + "-" + timeString); + + return conflictFileName; +} + +bool FileSystem::remove(const QString &fileName, QString *errorString) +{ +#ifdef Q_OS_WIN + // You cannot delete a read-only file on windows, but we want to + // allow that. + if (!QFileInfo(fileName).isWritable()) { + setFileReadOnly(fileName, false); + } +#endif + QFile f(fileName); + if (!f.remove()) { + if (errorString) { + *errorString = f.errorString(); + } + return false; + } + return true; +} + +bool FileSystem::isFileLocked(const QString &fileName) +{ +#ifdef Q_OS_WIN + const wchar_t *wuri = reinterpret_cast(fileName.utf16()); + // Check if file exists + DWORD attr = GetFileAttributesW(wuri); + if (attr != INVALID_FILE_ATTRIBUTES) { + // Try to open the file with as much access as possible.. + HANDLE win_h = CreateFileW( + wuri, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (win_h == INVALID_HANDLE_VALUE) { + /* could not be opened, so locked? */ + /* 32 == ERROR_SHARING_VIOLATION */ + return true; + } else { + CloseHandle(win_h); + } + } +#else + Q_UNUSED(fileName); +#endif + return false; +} + +bool FileSystem::isLnkFile(const QString &filename) +{ + return filename.endsWith(".lnk"); +} + +} // namespace OCC diff --git a/src/common/filesystembase.h b/src/common/filesystembase.h new file mode 100644 index 000000000..9568dac12 --- /dev/null +++ b/src/common/filesystembase.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) by Olivier Goffart + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "config.h" + +#include +#include +#include +#include + +#include + +class QFile; + +namespace OCC { + +OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcFileSystem) + +/** + * \addtogroup libsync + * @{ + */ + +/** + * @brief This file contains file system helper + */ +namespace FileSystem { + + /** + * @brief Mark the file as hidden (only has effects on windows) + */ + void OCSYNC_EXPORT setFileHidden(const QString &filename, bool hidden); + + /** + * @brief Marks the file as read-only. + * + * On linux this either revokes all 'w' permissions or restores permissions + * according to the umask. + */ + void OCSYNC_EXPORT setFileReadOnly(const QString &filename, bool readonly); + + /** + * @brief Marks the file as read-only. + * + * It's like setFileReadOnly(), but weaker: if readonly is false and the user + * already has write permissions, no change to the permissions is made. + * + * This means that it will preserve explicitly set rw-r--r-- permissions even + * when the umask is 0002. (setFileReadOnly() would adjust to rw-rw-r--) + */ + void OCSYNC_EXPORT setFileReadOnlyWeak(const QString &filename, bool readonly); + + /** + * @brief Try to set permissions so that other users on the local machine can not + * go into the folder. + */ + void OCSYNC_EXPORT setFolderMinimumPermissions(const QString &filename); + + /** convert a "normal" windows path into a path that can be 32k chars long. */ + QString OCSYNC_EXPORT longWinPath(const QString &inpath); + + /** + * @brief Checks whether a file exists. + * + * Use this over QFileInfo::exists() and QFile::exists() to avoid bugs with lnk + * files, see above. + */ + bool OCSYNC_EXPORT fileExists(const QString &filename, const QFileInfo & = QFileInfo()); + + /** + * @brief Rename the file \a originFileName to \a destinationFileName. + * + * It behaves as QFile::rename() but handles .lnk files correctly on Windows. + */ + bool OCSYNC_EXPORT rename(const QString &originFileName, + const QString &destinationFileName, + QString *errorString = NULL); + + /** + * Rename the file \a originFileName to \a destinationFileName, and + * overwrite the destination if it already exists - without extra checks. + */ + bool OCSYNC_EXPORT uncheckedRenameReplace(const QString &originFileName, + const QString &destinationFileName, + QString *errorString); + + /** + * Removes a file. + * + * Equivalent to QFile::remove(), except on Windows, where it will also + * successfully remove read-only files. + */ + bool OCSYNC_EXPORT remove(const QString &fileName, QString *errorString = 0); + + /** + * Replacement for QFile::open(ReadOnly) followed by a seek(). + * This version sets a more permissive sharing mode on Windows. + * + * Warning: The resulting file may have an empty fileName and be unsuitable for use + * with QFileInfo! Calling seek() on the QFile with >32bit signed values will fail! + */ + bool OCSYNC_EXPORT openAndSeekFileSharedRead(QFile *file, QString *error, qint64 seek); + +#ifdef Q_OS_WIN + /** + * Returns the file system used at the given path. + */ + QString fileSystemForPath(const QString &path); +#endif + + QByteArray OCSYNC_EXPORT calcMd5(const QString &fileName); + QByteArray OCSYNC_EXPORT calcSha1(const QString &fileName); +#ifdef ZLIB_FOUND + QByteArray OCSYNC_EXPORT calcAdler32(const QString &fileName); +#endif + + /** + * Returns a file name based on \a fn that's suitable for a conflict. + */ + QString OCSYNC_EXPORT makeConflictFileName(const QString &fn, const QDateTime &dt); + + /** + * Returns true when a file is locked. (Windows only) + */ + bool OCSYNC_EXPORT isFileLocked(const QString &fileName); + + bool OCSYNC_EXPORT isLnkFile(const QString &filename); + + /* + * This function takes a path and converts it to a UNC representation of the + * string. That means that it prepends a \\?\ (unless already UNC) and converts + * all slashes to backslashes. + * + * Note the following: + * - The string must be absolute. + * - it needs to contain a drive character to be a valid UNC + * - A conversion is only done if the path len is larger than 245. Otherwise + * the windows API functions work with the normal "unixoid" representation too. + */ + template + S pathtoUNC(const S &str) + { + int len = 0; + S longStr; + + len = str.length(); + longStr.reserve(len+4); + + // prepend \\?\ and convert '/' => '\' to support long names + if( str[0] == '/' || str[0] == '\\' ) { + // Don't prepend if already UNC + if( !(len > 1 && (str[1] == '/' || str[1] == '\\')) ) { + longStr.append("\\\\?"); + } + } else { + longStr.append("\\\\?\\"); // prepend string by this four magic chars. + } + longStr += str; + + /* replace all occurences of / with the windows native \ */ + + for (auto it = longStr.begin(); it != longStr.end(); ++it) { + if(*it == '/') { + *it = '\\'; + } + } + return longStr; + } +} + +/** @} */ +} diff --git a/src/csync/CMakeLists.txt b/src/csync/CMakeLists.txt index 7ab4f7326..e265b95d9 100644 --- a/src/csync/CMakeLists.txt +++ b/src/csync/CMakeLists.txt @@ -128,6 +128,11 @@ generate_export_header( ${CSYNC_LIBRARY} target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES}) #target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES}) +if(ZLIB_FOUND) + target_link_libraries(${CSYNC_LIBRARY} ${ZLIB_LIBRARIES}) + include_directories(${ZLIB_INCLUDE_DIRS}) +endif(ZLIB_FOUND) + find_package(Qt5Core REQUIRED) qt5_use_modules(${CSYNC_LIBRARY} Core) diff --git a/src/csync/std/c_path.c b/src/csync/std/c_path.c index 497ce411e..f81799c05 100644 --- a/src/csync/std/c_path.c +++ b/src/csync/std/c_path.c @@ -390,63 +390,3 @@ int c_parse_uri(const char *uri, return -1; } - - -/* - * This function takes a path and converts it to a UNC representation of the - * string. That means that it prepends a \\?\ (unless already UNC) and converts - * all slashes to backslashes. - * - * Note the following: - * - The string must be absolute. - * - it needs to contain a drive character to be a valid UNC - * - A conversion is only done if the path len is larger than 245. Otherwise - * the windows API functions work with the normal "unixoid" representation too. - * - * This function allocates memory that must be freed by the caller. - */ - const char *c_path_to_UNC(const char *str) - { - int len = 0; - char *longStr = NULL; - - len = strlen(str); - longStr = c_malloc(len+5); - *longStr = '\0'; - - // prepend \\?\ and convert '/' => '\' to support long names - if( str[0] == '/' || str[0] == '\\' ) { - // Don't prepend if already UNC - if( !(len > 1 && (str[1] == '/' || str[1] == '\\')) ) { - strcpy( longStr, "\\\\?"); - } - } else { - strcpy( longStr, "\\\\?\\"); // prepend string by this four magic chars. - } - strncat( longStr, str, len ); - - /* replace all occurences of / with the windows native \ */ - char *c = longStr; - for (; *c; ++c) { - if(*c == '/') { - *c = '\\'; - } - } - return longStr; - } - - mbchar_t* c_utf8_path_to_locale(const char *str) - { - if( str == NULL ) { - return NULL; - } else { - #ifdef _WIN32 - const char *unc_str = c_path_to_UNC(str); - mbchar_t *dst = c_utf8_string_to_locale(unc_str); - SAFE_FREE(unc_str); - return dst; - #else - return c_utf8_string_to_locale(str); - #endif - } - } diff --git a/src/csync/std/c_path.h b/src/csync/std/c_path.h index f17c5f480..d0dd43d9e 100644 --- a/src/csync/std/c_path.h +++ b/src/csync/std/c_path.h @@ -112,34 +112,6 @@ typedef struct char * extension; } C_PATHINFO; -/** - * @brief c_path_to_UNC converts a unixoid path to UNC format. - * - * It converts the '/' to '\' and prepends \\?\ to the path. - * - * A proper windows path has to have a drive letter, otherwise it is not - * valid UNC. - * - * @param str The path to convert - * - * @return a pointer to the converted string. Caller has to free it. - */ -const char *c_path_to_UNC(const char *str); - -/** - * @brief c_utf8_path_to_locale converts a unixoid path to the locale aware format - * - * On windows, it converts to UNC and multibyte. - * On Mac, it converts to the correct utf8 using iconv. - * On Linux, it returns utf8 - * - * @param str The path to convert - * - * @return a pointer to the converted string. Caller has to free it using the - * function c_free_locale_string. - */ -mbchar_t* c_utf8_path_to_locale(const char *str); - /** * }@ */ diff --git a/src/csync/std/c_utf8.cpp b/src/csync/std/c_utf8.cpp index ae61170a9..f4f5d1ac2 100644 --- a/src/csync/std/c_utf8.cpp +++ b/src/csync/std/c_utf8.cpp @@ -37,6 +37,7 @@ #include "c_alloc.h" #include "c_string.h" +#include "common/filesystembase.h" /* Convert a locale String to UTF8 */ QByteArray c_utf8_from_locale(const mbchar_t *wstr) @@ -99,4 +100,19 @@ mbchar_t* c_utf8_string_to_locale(const char *str) #endif } + mbchar_t* c_utf8_path_to_locale(const char *str) + { + if( str == NULL ) { + return NULL; + } else { + #ifdef _WIN32 + QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, strlen(str))); + mbchar_t *dst = c_utf8_string_to_locale(unc_str); + return dst; + #else + return c_utf8_string_to_locale(str); + #endif + } + } + } diff --git a/src/csync/std/c_utf8.h b/src/csync/std/c_utf8.h index 522cab34d..6fbb8afe9 100644 --- a/src/csync/std/c_utf8.h +++ b/src/csync/std/c_utf8.h @@ -91,6 +91,20 @@ extern "C" { */ mbchar_t* c_utf8_string_to_locale(const char *wstr); +/** + * @brief c_utf8_path_to_locale converts a unixoid path to the locale aware format + * + * On windows, it converts to UNC and multibyte. + * On Mac, it converts to the correct utf8 using iconv. + * On Linux, it returns utf8 + * + * @param str The path to convert + * + * @return a pointer to the converted string. Caller has to free it using the + * function c_free_locale_string. + */ +mbchar_t* c_utf8_path_to_locale(const char *str); + /** * @brief Free buffer malloced by c_utf8_to_locale(). * diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index a475aa3c0..3015d7fe3 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -115,11 +115,6 @@ if(INOTIFY_FOUND) link_directories(${INOTIFY_LIBRARY_DIR}) endif() -if(ZLIB_FOUND) - list(APPEND libsync_LINK_TARGETS ${ZLIB_LIBRARIES}) - include_directories(${ZLIB_INCLUDE_DIRS}) -endif(ZLIB_FOUND) - add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc}) GENERATE_EXPORT_HEADER( ${synclib_NAME} BASE_NAME ${synclib_NAME} diff --git a/src/libsync/filesystem.cpp b/src/libsync/filesystem.cpp index b027db4d7..69bbbe3f1 100644 --- a/src/libsync/filesystem.cpp +++ b/src/libsync/filesystem.cpp @@ -17,21 +17,6 @@ #include "common/utility.h" #include #include -#include -#include -#include - -#ifdef ZLIB_FOUND -#include -#endif - -#ifdef Q_OS_WIN -#include -#include -#include -#include -#include -#endif // We use some internals of csync: extern "C" int c_utimes(const char *, const struct timeval *); @@ -44,20 +29,6 @@ extern "C" int c_utimes(const char *, const struct timeval *); namespace OCC { -Q_LOGGING_CATEGORY(lcFileSystem, "sync.filesystem", QtInfoMsg) - -QString FileSystem::longWinPath(const QString &inpath) -{ -#ifdef Q_OS_WIN - const char *unc_str = c_path_to_UNC(inpath.toUtf8()); - QString path = QString::fromUtf8(unc_str); - free((void*)unc_str); - return path; -#else - return inpath; -#endif -} - bool FileSystem::fileEquals(const QString &fn1, const QString &fn2) { // compare two files with given filename and return true if they have the same content @@ -91,83 +62,6 @@ bool FileSystem::fileEquals(const QString &fn1, const QString &fn2) return false; } -void FileSystem::setFileHidden(const QString &filename, bool hidden) -{ -#ifdef _WIN32 - QString fName = longWinPath(filename); - DWORD dwAttrs; - - dwAttrs = GetFileAttributesW((wchar_t *)fName.utf16()); - - if (dwAttrs != INVALID_FILE_ATTRIBUTES) { - if (hidden && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) { - SetFileAttributesW((wchar_t *)fName.utf16(), dwAttrs | FILE_ATTRIBUTE_HIDDEN); - } else if (!hidden && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) { - SetFileAttributesW((wchar_t *)fName.utf16(), dwAttrs & ~FILE_ATTRIBUTE_HIDDEN); - } - } -#else - Q_UNUSED(filename); - Q_UNUSED(hidden); -#endif -} - -static QFile::Permissions getDefaultWritePermissions() -{ - QFile::Permissions result = QFile::WriteUser; -#ifndef Q_OS_WIN - mode_t mask = umask(0); - umask(mask); - if (!(mask & S_IWGRP)) { - result |= QFile::WriteGroup; - } - if (!(mask & S_IWOTH)) { - result |= QFile::WriteOther; - } -#endif - return result; -} - -void FileSystem::setFileReadOnly(const QString &filename, bool readonly) -{ - QFile file(filename); - QFile::Permissions permissions = file.permissions(); - - QFile::Permissions allWritePermissions = - QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther | QFile::WriteOwner; - static QFile::Permissions defaultWritePermissions = getDefaultWritePermissions(); - - permissions &= ~allWritePermissions; - if (!readonly) { - permissions |= defaultWritePermissions; - } - file.setPermissions(permissions); -} - -void FileSystem::setFolderMinimumPermissions(const QString &filename) -{ -#ifdef Q_OS_MAC - QFile::Permissions perm = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner; - QFile file(filename); - file.setPermissions(perm); -#else - Q_UNUSED(filename); -#endif -} - - -void FileSystem::setFileReadOnlyWeak(const QString &filename, bool readonly) -{ - QFile file(filename); - QFile::Permissions permissions = file.permissions(); - - if (!readonly && (permissions & QFile::WriteOwner)) { - return; // already writable enough - } - - setFileReadOnly(filename, readonly); -} - time_t FileSystem::getModTime(const QString &filename) { csync_file_stat_t stat; @@ -197,57 +91,6 @@ bool FileSystem::setModTime(const QString &filename, time_t modTime) return true; } -#ifdef Q_OS_WIN -static bool isLnkFile(const QString &filename) -{ - return filename.endsWith(".lnk"); -} -#endif - -bool FileSystem::rename(const QString &originFileName, - const QString &destinationFileName, - QString *errorString) -{ - bool success = false; - QString error; -#ifdef Q_OS_WIN - QString orig = longWinPath(originFileName); - QString dest = longWinPath(destinationFileName); - - if (isLnkFile(originFileName) || isLnkFile(destinationFileName)) { - success = MoveFileEx((wchar_t *)orig.utf16(), - (wchar_t *)dest.utf16(), - MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH); - if (!success) { - wchar_t *string = 0; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&string, 0, NULL); - - error = QString::fromWCharArray(string); - LocalFree((HLOCAL)string); - } - } else -#endif - { - QFile orig(originFileName); - success = orig.rename(destinationFileName); - if (!success) { - error = orig.errorString(); - } - } - - if (!success) { - qCWarning(lcFileSystem) << "Error renaming file" << originFileName - << "to" << destinationFileName - << "failed: " << error; - if (errorString) { - *errorString = error; - } - } - return success; -} - bool FileSystem::fileChanged(const QString &fileName, qint64 previousSize, time_t previousMtime) @@ -271,151 +114,6 @@ bool FileSystem::verifyFileUnchanged(const QString &fileName, return true; } -bool FileSystem::renameReplace(const QString &originFileName, - const QString &destinationFileName, - qint64 destinationSize, - time_t destinationMtime, - QString *errorString) -{ - if (fileExists(destinationFileName) - && fileChanged(destinationFileName, destinationSize, destinationMtime)) { - if (errorString) { - *errorString = qApp->translate("FileSystem", - "The destination file has an unexpected size or modification time"); - } - return false; - } - - return uncheckedRenameReplace(originFileName, destinationFileName, errorString); -} - -bool FileSystem::uncheckedRenameReplace(const QString &originFileName, - const QString &destinationFileName, - QString *errorString) -{ -#ifndef Q_OS_WIN - bool success; - QFile orig(originFileName); - // We want a rename that also overwites. QFile::rename does not overwite. - // Qt 5.1 has QSaveFile::renameOverwrite we could use. - // ### FIXME - success = true; - bool destExists = fileExists(destinationFileName); - if (destExists && !QFile::remove(destinationFileName)) { - *errorString = orig.errorString(); - qCWarning(lcFileSystem) << "Target file could not be removed."; - success = false; - } - if (success) { - success = orig.rename(destinationFileName); - } - if (!success) { - *errorString = orig.errorString(); - qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; - return false; - } - -#else //Q_OS_WIN - // You can not overwrite a read-only file on windows. - if (!QFileInfo(destinationFileName).isWritable()) { - setFileReadOnly(destinationFileName, false); - } - - BOOL ok; - QString orig = longWinPath(originFileName); - QString dest = longWinPath(destinationFileName); - - ok = MoveFileEx((wchar_t *)orig.utf16(), - (wchar_t *)dest.utf16(), - MOVEFILE_REPLACE_EXISTING + MOVEFILE_COPY_ALLOWED + MOVEFILE_WRITE_THROUGH); - if (!ok) { - wchar_t *string = 0; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&string, 0, NULL); - - *errorString = QString::fromWCharArray(string); - qCWarning(lcFileSystem) << "Renaming temp file to final failed: " << *errorString; - LocalFree((HLOCAL)string); - return false; - } -#endif - return true; -} - -bool FileSystem::openAndSeekFileSharedRead(QFile *file, QString *errorOrNull, qint64 seek) -{ - QString errorDummy; - // avoid many if (errorOrNull) later. - QString &error = errorOrNull ? *errorOrNull : errorDummy; - error.clear(); - -#ifdef Q_OS_WIN - // - // The following code is adapted from Qt's QFSFileEnginePrivate::nativeOpen() - // by including the FILE_SHARE_DELETE share mode. - // - - // Enable full sharing. - DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - - int accessRights = GENERIC_READ; - DWORD creationDisp = OPEN_EXISTING; - - // Create the file handle. - SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; - QString fName = longWinPath(file->fileName()); - - HANDLE fileHandle = CreateFileW( - (const wchar_t *)fName.utf16(), - accessRights, - shareMode, - &securityAtts, - creationDisp, - FILE_ATTRIBUTE_NORMAL, - NULL); - - // Bail out on error. - if (fileHandle == INVALID_HANDLE_VALUE) { - error = qt_error_string(); - return false; - } - - // Convert the HANDLE to an fd and pass it to QFile's foreign-open - // function. The fd owns the handle, so when QFile later closes - // the fd the handle will be closed too. - int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY); - if (fd == -1) { - error = "could not make fd from handle"; - return false; - } - if (!file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle)) { - error = file->errorString(); - return false; - } - - // Seek to the right spot - LARGE_INTEGER *li = reinterpret_cast(&seek); - DWORD newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN); - if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { - error = qt_error_string(); - return false; - } - - return true; -#else - if (!file->open(QFile::ReadOnly)) { - error = file->errorString(); - return false; - } - if (!file->seek(seek)) { - error = file->errorString(); - return false; - } - return true; -#endif -} - #ifdef Q_OS_WIN static qint64 getSizeWithCsync(const QString &filename) { @@ -441,190 +139,5 @@ qint64 FileSystem::getSize(const QString &filename) return QFileInfo(filename).size(); } -#ifdef Q_OS_WIN -static bool fileExistsWin(const QString &filename) -{ - WIN32_FIND_DATA FindFileData; - HANDLE hFind; - QString fName = FileSystem::longWinPath(filename); - - hFind = FindFirstFileW((wchar_t *)fName.utf16(), &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) { - return false; - } - FindClose(hFind); - return true; -} -#endif - -bool FileSystem::fileExists(const QString &filename, const QFileInfo &fileInfo) -{ -#ifdef Q_OS_WIN - if (isLnkFile(filename)) { - // Use a native check. - return fileExistsWin(filename); - } -#endif - bool re = fileInfo.exists(); - // if the filename is different from the filename in fileInfo, the fileInfo is - // not valid. There needs to be one initialised here. Otherwise the incoming - // fileInfo is re-used. - if (fileInfo.filePath() != filename) { - QFileInfo myFI(filename); - re = myFI.exists(); - } - return re; -} - -#ifdef Q_OS_WIN -QString FileSystem::fileSystemForPath(const QString &path) -{ - // See also QStorageInfo (Qt >=5.4) and GetVolumeInformationByHandleW (>= Vista) - QString drive = path.left(2); - if (!drive.endsWith(":")) - return QString(); - drive.append('\\'); - - const size_t fileSystemBufferSize = 4096; - TCHAR fileSystemBuffer[fileSystemBufferSize]; - - if (!GetVolumeInformationW( - reinterpret_cast(drive.utf16()), - NULL, 0, - NULL, NULL, NULL, - fileSystemBuffer, fileSystemBufferSize)) { - return QString(); - } - return QString::fromUtf16(reinterpret_cast(fileSystemBuffer)); -} -#endif - -#define BUFSIZE qint64(500 * 1024) // 500 KiB - -static QByteArray readToCrypto(const QString &filename, QCryptographicHash::Algorithm algo) -{ - QFile file(filename); - const qint64 bufSize = qMin(BUFSIZE, file.size() + 1); - QByteArray buf(bufSize, Qt::Uninitialized); - QByteArray arr; - QCryptographicHash crypto(algo); - - if (file.open(QIODevice::ReadOnly)) { - qint64 size; - while (!file.atEnd()) { - size = file.read(buf.data(), bufSize); - if (size > 0) { - crypto.addData(buf.data(), size); - } - } - arr = crypto.result().toHex(); - } - return arr; -} - -QByteArray FileSystem::calcMd5(const QString &filename) -{ - return readToCrypto(filename, QCryptographicHash::Md5); -} - -QByteArray FileSystem::calcSha1(const QString &filename) -{ - return readToCrypto(filename, QCryptographicHash::Sha1); -} - -#ifdef ZLIB_FOUND -QByteArray FileSystem::calcAdler32(const QString &filename) -{ - QFile file(filename); - const qint64 bufSize = qMin(BUFSIZE, file.size() + 1); - QByteArray buf(bufSize, Qt::Uninitialized); - - unsigned int adler = adler32(0L, Z_NULL, 0); - if (file.open(QIODevice::ReadOnly)) { - qint64 size; - while (!file.atEnd()) { - size = file.read(buf.data(), bufSize); - if (size > 0) - adler = adler32(adler, (const Bytef *)buf.data(), size); - } - } - - return QByteArray::number(adler, 16); -} -#endif - -QString FileSystem::makeConflictFileName(const QString &fn, const QDateTime &dt) -{ - QString conflictFileName(fn); - // Add _conflict-XXXX before the extension. - int dotLocation = conflictFileName.lastIndexOf('.'); - // If no extension, add it at the end (take care of cases like foo/.hidden or foo.bar/file) - if (dotLocation <= conflictFileName.lastIndexOf('/') + 1) { - dotLocation = conflictFileName.size(); - } - QString timeString = dt.toString("yyyyMMdd-hhmmss"); - - // Additional marker - QByteArray conflictFileUserName = qgetenv("CSYNC_CONFLICT_FILE_USERNAME"); - if (conflictFileUserName.isEmpty()) - conflictFileName.insert(dotLocation, "_conflict-" + timeString); - else - conflictFileName.insert(dotLocation, "_conflict_" + QString::fromUtf8(conflictFileUserName) + "-" + timeString); - - return conflictFileName; -} - -bool FileSystem::remove(const QString &fileName, QString *errorString) -{ -#ifdef Q_OS_WIN - // You cannot delete a read-only file on windows, but we want to - // allow that. - if (!QFileInfo(fileName).isWritable()) { - setFileReadOnly(fileName, false); - } -#endif - QFile f(fileName); - if (!f.remove()) { - if (errorString) { - *errorString = f.errorString(); - } - return false; - } - return true; -} - -bool FileSystem::isFileLocked(const QString &fileName) -{ -#ifdef Q_OS_WIN - mbchar_t *wuri = c_utf8_path_to_locale(fileName.toUtf8()); - - // Check if file exists - DWORD attr = GetFileAttributesW(wuri); - if (attr != INVALID_FILE_ATTRIBUTES) { - // Try to open the file with as much access as possible.. - HANDLE win_h = CreateFileW( - wuri, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, - NULL); - - c_free_locale_string(wuri); - if (win_h == INVALID_HANDLE_VALUE) { - /* could not be opened, so locked? */ - /* 32 == ERROR_SHARING_VIOLATION */ - return true; - } else { - CloseHandle(win_h); - } - } else { - c_free_locale_string(wuri); - } -#else - Q_UNUSED(fileName); -#endif - return false; -} } // namespace OCC diff --git a/src/libsync/filesystem.h b/src/libsync/filesystem.h index 7494bdbd4..302a1790a 100644 --- a/src/libsync/filesystem.h +++ b/src/libsync/filesystem.h @@ -18,13 +18,12 @@ #include #include -#include -#include #include +// Chain in the base include and extend the namespace +#include "common/filesystembase.h" class QFile; -class QFileInfo; namespace OCC { @@ -43,39 +42,6 @@ namespace FileSystem { */ bool fileEquals(const QString &fn1, const QString &fn2); - /** - * @brief Mark the file as hidden (only has effects on windows) - */ - void OWNCLOUDSYNC_EXPORT setFileHidden(const QString &filename, bool hidden); - - /** - * @brief Marks the file as read-only. - * - * On linux this either revokes all 'w' permissions or restores permissions - * according to the umask. - */ - void OWNCLOUDSYNC_EXPORT setFileReadOnly(const QString &filename, bool readonly); - - /** - * @brief Marks the file as read-only. - * - * It's like setFileReadOnly(), but weaker: if readonly is false and the user - * already has write permissions, no change to the permissions is made. - * - * This means that it will preserve explicitly set rw-r--r-- permissions even - * when the umask is 0002. (setFileReadOnly() would adjust to rw-rw-r--) - */ - void OWNCLOUDSYNC_EXPORT setFileReadOnlyWeak(const QString &filename, bool readonly); - - /** - * @brief Try to set permissions so that other users on the local machine can not - * go into the folder. - */ - void OWNCLOUDSYNC_EXPORT setFolderMinimumPermissions(const QString &filename); - - /** convert a "normal" windows path into a path that can be 32k chars long. */ - QString OWNCLOUDSYNC_EXPORT longWinPath(const QString &inpath); - /** * @brief Get the mtime for a filepath * @@ -94,23 +60,6 @@ namespace FileSystem { */ qint64 OWNCLOUDSYNC_EXPORT getSize(const QString &filename); - /** - * @brief Checks whether a file exists. - * - * Use this over QFileInfo::exists() and QFile::exists() to avoid bugs with lnk - * files, see above. - */ - bool OWNCLOUDSYNC_EXPORT fileExists(const QString &filename, const QFileInfo & = QFileInfo()); - - /** - * @brief Rename the file \a originFileName to \a destinationFileName. - * - * It behaves as QFile::rename() but handles .lnk files correctly on Windows. - */ - bool OWNCLOUDSYNC_EXPORT rename(const QString &originFileName, - const QString &destinationFileName, - QString *errorString = NULL); - /** * @brief Check if \a fileName has changed given previous size and mtime * @@ -128,71 +77,6 @@ namespace FileSystem { bool verifyFileUnchanged(const QString &fileName, qint64 previousSize, time_t previousMtime); - - /** - * @brief renames a file, overriding the target if it exists - * - * Rename the file \a originFileName to \a destinationFileName, and - * overwrite the destination if it already exists - as long as the - * destination file has the expected \a destinationSize and - * \a destinationMtime. - * - * If the destination file does not exist, the given size and mtime are - * ignored. - */ - bool renameReplace(const QString &originFileName, - const QString &destinationFileName, - qint64 destinationSize, - time_t destinationMtime, - QString *errorString); - - /** - * Rename the file \a originFileName to \a destinationFileName, and - * overwrite the destination if it already exists - without extra checks. - */ - bool uncheckedRenameReplace(const QString &originFileName, - const QString &destinationFileName, - QString *errorString); - - /** - * Removes a file. - * - * Equivalent to QFile::remove(), except on Windows, where it will also - * successfully remove read-only files. - */ - bool OWNCLOUDSYNC_EXPORT remove(const QString &fileName, QString *errorString = 0); - - /** - * Replacement for QFile::open(ReadOnly) followed by a seek(). - * This version sets a more permissive sharing mode on Windows. - * - * Warning: The resulting file may have an empty fileName and be unsuitable for use - * with QFileInfo! Calling seek() on the QFile with >32bit signed values will fail! - */ - bool openAndSeekFileSharedRead(QFile *file, QString *error, qint64 seek); - -#ifdef Q_OS_WIN - /** - * Returns the file system used at the given path. - */ - QString fileSystemForPath(const QString &path); -#endif - - QByteArray OWNCLOUDSYNC_EXPORT calcMd5(const QString &fileName); - QByteArray OWNCLOUDSYNC_EXPORT calcSha1(const QString &fileName); -#ifdef ZLIB_FOUND - QByteArray OWNCLOUDSYNC_EXPORT calcAdler32(const QString &fileName); -#endif - - /** - * Returns a file name based on \a fn that's suitable for a conflict. - */ - QString OWNCLOUDSYNC_EXPORT makeConflictFileName(const QString &fn, const QDateTime &dt); - - /** - * Returns true when a file is locked. (Windows only) - */ - bool OWNCLOUDSYNC_EXPORT isFileLocked(const QString &fileName); } /** @} */ diff --git a/src/libsync/syncjournaldb.cpp b/src/libsync/syncjournaldb.cpp index d963b8667..5f344fa08 100644 --- a/src/libsync/syncjournaldb.cpp +++ b/src/libsync/syncjournaldb.cpp @@ -12,6 +12,7 @@ * for more details. */ +#include #include #include #include diff --git a/test/csync/encoding_tests/check_encoding.cpp b/test/csync/encoding_tests/check_encoding.cpp index 2f327a3b0..d2459b8d2 100644 --- a/test/csync/encoding_tests/check_encoding.cpp +++ b/test/csync/encoding_tests/check_encoding.cpp @@ -21,6 +21,8 @@ #include "c_string.h" #include "c_path.h" #include "c_utf8.h" +#include "common/filesystembase.h" +#include "torture.h" #ifdef _WIN32 #include @@ -116,41 +118,36 @@ static void check_long_win_path(void **state) { const char *path = "C://DATA/FILES/MUSIC/MY_MUSIC.mp3"; // check a short path const char *exp_path = "\\\\?\\C:\\\\DATA\\FILES\\MUSIC\\MY_MUSIC.mp3"; - const char *new_short = c_path_to_UNC(path); + QByteArray new_short = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(path, strlen(path))); assert_string_equal(new_short, exp_path); - SAFE_FREE(new_short); } { const char *path = "\\\\foo\\bar/MY_MUSIC.mp3"; const char *exp_path = "\\\\foo\\bar\\MY_MUSIC.mp3"; - const char *new_short = c_path_to_UNC(path); + QByteArray new_short = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(path, strlen(path))); assert_string_equal(new_short, exp_path); - SAFE_FREE(new_short); } { const char *path = "//foo\\bar/MY_MUSIC.mp3"; const char *exp_path = "\\\\foo\\bar\\MY_MUSIC.mp3"; - const char *new_short = c_path_to_UNC(path); + QByteArray new_short = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(path, strlen(path))); assert_string_equal(new_short, exp_path); - SAFE_FREE(new_short); } { const char *path = "\\foo\\bar"; const char *exp_path = "\\\\?\\foo\\bar"; - const char *new_short = c_path_to_UNC(path); + QByteArray new_short = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(path, strlen(path))); assert_string_equal(new_short, exp_path); - SAFE_FREE(new_short); } { const char *path = "/foo/bar"; const char *exp_path = "\\\\?\\foo\\bar"; - const char *new_short = c_path_to_UNC(path); + QByteArray new_short = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(path, strlen(path))); assert_string_equal(new_short, exp_path); - SAFE_FREE(new_short); } const char *longPath = "D://alonglonglonglong/blonglonglonglong/clonglonglonglong/dlonglonglonglong/" @@ -162,14 +159,13 @@ static void check_long_win_path(void **state) "jlonglonglonglong\\klonglonglonglong\\llonglonglonglong\\mlonglonglonglong\\nlonglonglonglong\\" "olonglonglonglong\\file.txt"; - const char *new_long = c_path_to_UNC(longPath); + QByteArray new_long = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(longPath, strlen(longPath))); // printf( "XXXXXXXXXXXX %s %d\n", new_long, mem_reserved); assert_string_equal(new_long, longPathConv); // printf( "YYYYYYYYYYYY %ld\n", strlen(new_long)); assert_int_equal( strlen(new_long), 286); - SAFE_FREE(new_long); } int torture_run_tests(void)