diff options
Diffstat (limited to 'src/corelib/io/qfilesystemengine_win.cpp')
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 317 |
1 files changed, 170 insertions, 147 deletions
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 0542d9e16c..79a9936785 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -48,7 +48,6 @@ #include "qfile.h" #include "qdir.h" -#include "private/qmutexpool_p.h" #include "qvarlengtharray.h" #include "qdatetime.h" #include "qt_windows.h" @@ -60,6 +59,7 @@ #include <objbase.h> #ifndef Q_OS_WINRT # include <shlobj.h> +# include <lm.h> # include <accctrl.h> #endif #include <initguid.h> @@ -147,48 +147,30 @@ typedef struct _REPARSE_DATA_BUFFER { # define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif -QT_BEGIN_NAMESPACE - -Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0; - -#if defined(Q_OS_WINRT) -// As none of the functions we try to resolve do exist on WinRT we -// avoid library loading on WinRT in general to shorten everything -// up a little bit. +#if defined(Q_OS_WINRT) || defined(QT_BOOTSTRAPPED) # define QT_FEATURE_fslibs -1 #else -# define QT_FEATURE_fslibs QT_FEATURE_library +# define QT_FEATURE_fslibs 1 #endif // Q_OS_WINRT #if QT_CONFIG(fslibs) -QT_BEGIN_INCLUDE_NAMESPACE -typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); -static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; -typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); -static PtrLookupAccountSidW ptrLookupAccountSidW = 0; -typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); -static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; -typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); -static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; -typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD); -static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0; -QT_END_INCLUDE_NAMESPACE - +#include <aclapi.h> +#include <userenv.h> static TRUSTEE_W currentUserTrusteeW; static TRUSTEE_W worldTrusteeW; static PSID currentUserSID = 0; static PSID worldSID = 0; -/* - Deletes the allocated SIDs during global static cleanup -*/ -class SidCleanup +QT_BEGIN_NAMESPACE + +namespace { +struct GlobalSid { -public: - ~SidCleanup(); + GlobalSid(); + ~GlobalSid(); }; -SidCleanup::~SidCleanup() +GlobalSid::~GlobalSid() { free(currentUserSID); currentUserSID = 0; @@ -200,39 +182,13 @@ SidCleanup::~SidCleanup() } } -Q_GLOBAL_STATIC(SidCleanup, initSidCleanup) - -static void resolveLibs() +GlobalSid::GlobalSid() { - static bool triedResolve = false; - if (!triedResolve) { - // need to resolve the security info functions - - // protect initialization -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - // check triedResolve again, since another thread may have already - // done the initialization - if (triedResolve) { - // another thread did initialize the security function pointers, - // so we shouldn't do it again. - return; - } -#endif - - triedResolve = true; - HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32"); - if (advapiHnd) { - ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); - ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW"); - ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW"); - ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW"); - } - if (ptrBuildTrusteeWithSidW) { + { + { // Create TRUSTEE for current user HANDLE hnd = ::GetCurrentProcess(); HANDLE token = 0; - initSidCleanup(); if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) { DWORD retsize = 0; // GetTokenInformation requires a buffer big enough for the TOKEN_USER struct and @@ -247,61 +203,69 @@ static void resolveLibs() DWORD sidLen = ::GetLengthSid(tokenSid); currentUserSID = reinterpret_cast<PSID>(malloc(sidLen)); if (::CopySid(sidLen, currentUserSID, tokenSid)) - ptrBuildTrusteeWithSidW(¤tUserTrusteeW, currentUserSID); + BuildTrusteeWithSid(¤tUserTrusteeW, currentUserSID); } free(tokenBuffer); } ::CloseHandle(token); } - typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); - PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid"); - if (ptrAllocateAndInitializeSid) { + { // Create TRUSTEE for Everyone (World) SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY }; - if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID)) - ptrBuildTrusteeWithSidW(&worldTrusteeW, worldSID); + if (AllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID)) + BuildTrusteeWithSid(&worldTrusteeW, worldSID); } } - HINSTANCE userenvHnd = QSystemLibrary::load(L"userenv"); - if (userenvHnd) - ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); } } + +Q_GLOBAL_STATIC(GlobalSid, initGlobalSid) + +QT_END_NAMESPACE + +} // anonymous namespace #endif // QT_CONFIG(fslibs) -typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); -static PtrNetShareEnum ptrNetShareEnum = 0; -typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID); -static PtrNetApiBufferFree ptrNetApiBufferFree = 0; -typedef struct _SHARE_INFO_1 { - LPWSTR shi1_netname; - DWORD shi1_type; - LPWSTR shi1_remark; -} SHARE_INFO_1; +QT_BEGIN_NAMESPACE +Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0; -static bool resolveUNCLibs() +static inline bool toFileTime(const QDateTime &date, FILETIME *fileTime) { - static bool triedResolve = false; - if (!triedResolve) { -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - if (triedResolve) { - return ptrNetShareEnum && ptrNetApiBufferFree; - } -#endif - triedResolve = true; -#if !defined(Q_OS_WINRT) - HINSTANCE hLib = QSystemLibrary::load(L"Netapi32"); - if (hLib) { - ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum"); - if (ptrNetShareEnum) - ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree"); - } -#endif // !Q_OS_WINRT + SYSTEMTIME sTime; + if (date.timeSpec() == Qt::LocalTime) { + SYSTEMTIME lTime; + const QDate d = date.date(); + const QTime t = date.time(); + + lTime.wYear = d.year(); + lTime.wMonth = d.month(); + lTime.wDay = d.day(); + lTime.wHour = t.hour(); + lTime.wMinute = t.minute(); + lTime.wSecond = t.second(); + lTime.wMilliseconds = t.msec(); + lTime.wDayOfWeek = d.dayOfWeek() % 7; + + if (!::TzSpecificLocalTimeToSystemTime(0, &lTime, &sTime)) + return false; + } else { + QDateTime utcDate = date.toUTC(); + const QDate d = utcDate.date(); + const QTime t = utcDate.time(); + + sTime.wYear = d.year(); + sTime.wMonth = d.month(); + sTime.wDay = d.day(); + sTime.wHour = t.hour(); + sTime.wMinute = t.minute(); + sTime.wSecond = t.second(); + sTime.wMilliseconds = t.msec(); + sTime.wDayOfWeek = d.dayOfWeek() % 7; } - return ptrNetShareEnum && ptrNetApiBufferFree; + + return ::SystemTimeToFileTime(&sTime, fileTime); } static QString readSymLink(const QFileSystemEntry &link) @@ -339,7 +303,7 @@ static QString readSymLink(const QFileSystemEntry &link) CloseHandle(handle); #if QT_CONFIG(fslibs) - resolveLibs(); + initGlobalSid(); QRegExp matchVolName(QLatin1String("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"), Qt::CaseInsensitive); if (matchVolName.indexIn(result) == 0) { DWORD len; @@ -436,32 +400,35 @@ static inline bool getFindData(QString path, WIN32_FIND_DATA &findData) bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list) { - if (resolveUNCLibs()) { - SHARE_INFO_1 *BufPtr, *p; - DWORD res; - DWORD er = 0, tr = 0, resume = 0, i; - do { - res = ptrNetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume); - if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { - p = BufPtr; - for (i = 1; i <= er; ++i) { - if (list && p->shi1_type == 0) - list->append(QString::fromWCharArray(p->shi1_netname)); - p++; - } + DWORD res = ERROR_NOT_SUPPORTED; +#ifndef Q_OS_WINRT + SHARE_INFO_1 *BufPtr, *p; + DWORD er = 0, tr = 0, resume = 0, i; + do { + res = NetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume); + if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { + p = BufPtr; + for (i = 1; i <= er; ++i) { + if (list && p->shi1_type == 0) + list->append(QString::fromWCharArray(p->shi1_netname)); + p++; } - ptrNetApiBufferFree(BufPtr); - } while (res == ERROR_MORE_DATA); - return res == ERROR_SUCCESS; - } - return false; + } + NetApiBufferFree(BufPtr); + } while (res == ERROR_MORE_DATA); +#else + Q_UNUSED(server); + Q_UNUSED(list); +#endif + return res == ERROR_SUCCESS; } void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data) { data.size_ = 0; data.fileAttribute_ = 0; - data.creationTime_ = FILETIME(); + data.birthTime_ = FILETIME(); + data.changeTime_ = FILETIME(); data.lastAccessTime_ = FILETIME(); data.lastWriteTime_ = FILETIME(); } @@ -642,36 +609,72 @@ QByteArray QFileSystemEngine::id(HANDLE fHandle) } //static +bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate, + QAbstractFileEngine::FileTime time, QSystemError &error) +{ + FILETIME fTime; + FILETIME *pLastWrite = NULL; + FILETIME *pLastAccess = NULL; + FILETIME *pCreationTime = NULL; + + switch (time) { + case QAbstractFileEngine::ModificationTime: + pLastWrite = &fTime; + break; + + case QAbstractFileEngine::AccessTime: + pLastAccess = &fTime; + break; + + case QAbstractFileEngine::BirthTime: + pCreationTime = &fTime; + break; + + default: + error = QSystemError(ERROR_INVALID_PARAMETER, QSystemError::NativeError); + return false; + } + + if (!toFileTime(newDate, &fTime)) + return false; + + if (!::SetFileTime(fHandle, pCreationTime, pLastAccess, pLastWrite)) { + error = QSystemError(::GetLastError(), QSystemError::NativeError); + return false; + } + return true; +} + QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own) { QString name; #if QT_CONFIG(fslibs) extern int qt_ntfs_permission_lookup; - if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { - resolveLibs(); - if (ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) { + if (qt_ntfs_permission_lookup > 0) { + initGlobalSid(); + { PSID pOwner = 0; PSECURITY_DESCRIPTOR pSD; - if (ptrGetNamedSecurityInfoW((wchar_t*)entry.nativeFilePath().utf16(), SE_FILE_OBJECT, - own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, - own == QAbstractFileEngine::OwnerUser ? &pOwner : 0, own == QAbstractFileEngine::OwnerGroup ? &pOwner : 0, - 0, 0, &pSD) == ERROR_SUCCESS) { + if (GetNamedSecurityInfo(reinterpret_cast<const wchar_t*>(entry.nativeFilePath().utf16()), SE_FILE_OBJECT, + own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION, + own == QAbstractFileEngine::OwnerUser ? &pOwner : 0, own == QAbstractFileEngine::OwnerGroup ? &pOwner : 0, + 0, 0, &pSD) == ERROR_SUCCESS) { DWORD lowner = 64; DWORD ldomain = 64; QVarLengthArray<wchar_t, 64> owner(lowner); QVarLengthArray<wchar_t, 64> domain(ldomain); SID_NAME_USE use = SidTypeUnknown; // First call, to determine size of the strings (with '\0'). - if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, - (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { + if (!LookupAccountSid(NULL, pOwner, (LPWSTR)owner.data(), &lowner, + domain.data(), &ldomain, &use)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if (lowner > (DWORD)owner.size()) owner.resize(lowner); if (ldomain > (DWORD)domain.size()) domain.resize(ldomain); // Second call, try on resized buf-s - if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner, - (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) { + if (!LookupAccountSid(NULL, pOwner, owner.data(), &lowner, + domain.data(), &ldomain, &use)) { lowner = 0; } } else { @@ -696,9 +699,9 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst QFileSystemMetaData::MetaDataFlags what) { #if QT_CONFIG(fslibs) - if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { - resolveLibs(); - if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) { + if (qt_ntfs_permission_lookup > 0) { + initGlobalSid(); + { enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 }; QString fname = entry.nativeFilePath(); @@ -706,15 +709,15 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst PSID pGroup = 0; PACL pDacl; PSECURITY_DESCRIPTOR pSD; - DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT, - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, - &pOwner, &pGroup, &pDacl, 0, &pSD); + DWORD res = GetNamedSecurityInfo(reinterpret_cast<const wchar_t*>(fname.utf16()), SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &pOwner, &pGroup, &pDacl, 0, &pSD); if(res == ERROR_SUCCESS) { ACCESS_MASK access_mask; TRUSTEE_W trustee; if (what & QFileSystemMetaData::UserPermissions) { // user data.knownFlagsMask |= QFileSystemMetaData::UserPermissions; - if(ptrGetEffectiveRightsFromAclW(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) + if (GetEffectiveRightsFromAcl(pDacl, ¤tUserTrusteeW, &access_mask) != ERROR_SUCCESS) access_mask = (ACCESS_MASK)-1; if(access_mask & ReadMask) data.entryFlags |= QFileSystemMetaData::UserReadPermission; @@ -725,8 +728,8 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst } if (what & QFileSystemMetaData::OwnerPermissions) { // owner data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions; - ptrBuildTrusteeWithSidW(&trustee, pOwner); - if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) + BuildTrusteeWithSid(&trustee, pOwner); + if (GetEffectiveRightsFromAcl(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) access_mask = (ACCESS_MASK)-1; if(access_mask & ReadMask) data.entryFlags |= QFileSystemMetaData::OwnerReadPermission; @@ -737,8 +740,8 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst } if (what & QFileSystemMetaData::GroupPermissions) { // group data.knownFlagsMask |= QFileSystemMetaData::GroupPermissions; - ptrBuildTrusteeWithSidW(&trustee, pGroup); - if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) + BuildTrusteeWithSid(&trustee, pGroup); + if (GetEffectiveRightsFromAcl(pDacl, &trustee, &access_mask) != ERROR_SUCCESS) access_mask = (ACCESS_MASK)-1; if(access_mask & ReadMask) data.entryFlags |= QFileSystemMetaData::GroupReadPermission; @@ -749,7 +752,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst } if (what & QFileSystemMetaData::OtherPermissions) { // other (world) data.knownFlagsMask |= QFileSystemMetaData::OtherPermissions; - if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS) + if (GetEffectiveRightsFromAcl(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS) access_mask = (ACCESS_MASK)-1; // ### if(access_mask & ReadMask) data.entryFlags |= QFileSystemMetaData::OtherReadPermission; @@ -902,8 +905,10 @@ bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data, FILE_BASIC_INFO fileBasicInfo; if (GetFileInformationByHandleEx(fHandle, FileBasicInfo, &fileBasicInfo, sizeof(fileBasicInfo))) { data.fillFromFileAttribute(fileBasicInfo.FileAttributes); - data.creationTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart; - data.creationTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart; + data.birthTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart; + data.birthTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart; + data.changeTime_.dwHighDateTime = fileBasicInfo.ChangeTime.HighPart; + data.changeTime_.dwLowDateTime = fileBasicInfo.ChangeTime.LowPart; data.lastAccessTime_.dwHighDateTime = fileBasicInfo.LastAccessTime.HighPart; data.lastAccessTime_.dwLowDateTime = fileBasicInfo.LastAccessTime.LowPart; data.lastWriteTime_.dwHighDateTime = fileBasicInfo.LastWriteTime.HighPart; @@ -1160,19 +1165,19 @@ QString QFileSystemEngine::homePath() { QString ret; #if QT_CONFIG(fslibs) - resolveLibs(); - if (ptrGetUserProfileDirectoryW) { + initGlobalSid(); + { HANDLE hnd = ::GetCurrentProcess(); HANDLE token = 0; BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token); if (ok) { DWORD dwBufferSize = 0; // First call, to determine size of the strings (with '\0'). - ok = ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize); + ok = GetUserProfileDirectory(token, NULL, &dwBufferSize); if (!ok && dwBufferSize != 0) { // We got the required buffer size wchar_t *userDirectory = new wchar_t[dwBufferSize]; // Second call, now we can fill the allocated buffer. - ok = ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize); + ok = GetUserProfileDirectory(token, userDirectory, &dwBufferSize); if (ok) ret = QString::fromWCharArray(userDirectory); delete [] userDirectory; @@ -1318,6 +1323,17 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy } //static +bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) +{ + bool ret = ::MoveFileEx(reinterpret_cast<const wchar_t *>(source.nativeFilePath().utf16()), + reinterpret_cast<const wchar_t *>(target.nativeFilePath().utf16()), + MOVEFILE_REPLACE_EXISTING) != 0; + if (!ret) + error = QSystemError(::GetLastError(), QSystemError::NativeError); + return ret; +} + +//static bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error) { bool ret = ::DeleteFile((wchar_t*)entry.nativeFilePath().utf16()) != 0; @@ -1349,6 +1365,9 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per static inline QDateTime fileTimeToQDateTime(const FILETIME *time) { + if (time->dwHighDateTime == 0 && time->dwLowDateTime == 0) + return QDateTime(); + SYSTEMTIME sTime; FileTimeToSystemTime(time, &sTime); return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay), @@ -1356,9 +1375,13 @@ static inline QDateTime fileTimeToQDateTime(const FILETIME *time) Qt::UTC); } -QDateTime QFileSystemMetaData::creationTime() const +QDateTime QFileSystemMetaData::birthTime() const +{ + return fileTimeToQDateTime(&birthTime_); +} +QDateTime QFileSystemMetaData::metadataChangeTime() const { - return fileTimeToQDateTime(&creationTime_); + return fileTimeToQDateTime(&changeTime_); } QDateTime QFileSystemMetaData::modificationTime() const { |