7#include "qplatformdefs.h"
10#include "private/qabstractfileengine_p.h"
11#include "private/qfiledevice_p.h"
12#include "private/qfsfileengine_p.h"
13#include <private/qsystemlibrary_p.h>
21#if QT_CONFIG(regularexpression)
22#include "qregularexpression.h"
43#include <QtCore/private/qfunctions_win_p.h>
44#include <QtCore/private/wcharhelpers_win_p.h>
46#ifndef SPI_GETPLATFORMTYPE
47#define SPI_GETPLATFORMTYPE 257
51#define PATH_MAX FILENAME_MAX
54#ifndef _INTPTR_T_DEFINED
56typedef __int64 intptr_t;
59typedef _W64
int intptr_t;
61typedef INT_PTR intptr_t;
64#define _INTPTR_T_DEFINED
67#ifndef INVALID_FILE_ATTRIBUTES
68# define INVALID_FILE_ATTRIBUTES (DWORD (-1
))
71#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE)
84 } SymbolicLinkReparseBuffer;
86 USHORT SubstituteNameOffset;
87 USHORT SubstituteNameLength;
88 USHORT PrintNameOffset;
89 USHORT PrintNameLength;
91 } MountPointReparseBuffer;
94 } GenericReparseBuffer;
96} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
97# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
100#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
101# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384
103#ifndef IO_REPARSE_TAG_SYMLINK
104# define IO_REPARSE_TAG_SYMLINK (0xA000000CL
)
106#ifndef FSCTL_GET_REPARSE_POINT
107# define FSCTL_GET_REPARSE_POINT
108 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42
, METHOD_BUFFERED, FILE_ANY_ACCESS)
115static PSID currentUserSID =
nullptr;
116static PSID currentGroupSID =
nullptr;
117static PSID worldSID =
nullptr;
118static HANDLE currentUserImpersonatedToken =
nullptr;
122using namespace Qt::StringLiterals;
132GlobalSid::~GlobalSid()
134 free(currentUserSID);
135 currentUserSID =
nullptr;
137 free(currentGroupSID);
138 currentGroupSID =
nullptr;
146 if (currentUserImpersonatedToken) {
147 ::CloseHandle(currentUserImpersonatedToken);
148 currentUserImpersonatedToken =
nullptr;
153
154
155
156
157
159static T *getTokenInfo(HANDLE token, TOKEN_INFORMATION_CLASS infoClass)
162 GetTokenInformation(token, infoClass,
nullptr, 0, &retsize);
164 void *tokenBuffer = malloc(retsize);
165 if (::GetTokenInformation(token, infoClass, tokenBuffer, retsize, &retsize))
166 return reinterpret_cast<T *>(tokenBuffer);
174
175
176
177static void copySID(PSID &dstSid, PSID srcSid)
179 DWORD sidLen = GetLengthSid(srcSid);
180 dstSid =
reinterpret_cast<PSID>(malloc(sidLen));
182 CopySid(sidLen, dstSid, srcSid);
185GlobalSid::GlobalSid()
187 HANDLE hnd = ::GetCurrentProcess();
188 HANDLE token =
nullptr;
189 if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) {
191 if (
auto info = getTokenInfo<TOKEN_USER>(token, TokenUser)) {
192 copySID(currentUserSID, info->User.Sid);
197 if (
auto info = getTokenInfo<TOKEN_GROUPS>(token, TokenGroups)) {
198 copySID(currentGroupSID, info->Groups[0].Sid);
201 ::CloseHandle(token);
205 if (::OpenProcessToken(hnd,
206 TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ,
208 ::DuplicateToken(token, SecurityImpersonation, ¤tUserImpersonatedToken);
209 ::CloseHandle(token);
213 SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
214 AllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID);
217Q_GLOBAL_STATIC(GlobalSid, initGlobalSid)
220
221
222
223
224
225class QAuthzResourceManager
228 QAuthzResourceManager();
229 ~QAuthzResourceManager();
231 bool isValid()
const {
return resourceManager !=
nullptr; }
234 friend class QAuthzClientContext;
235 Q_DISABLE_COPY_MOVE(QAuthzResourceManager)
237 AUTHZ_RESOURCE_MANAGER_HANDLE resourceManager;
241
242
243
244
245
246class QAuthzClientContext
254 QAuthzClientContext(
const QAuthzResourceManager &rm, PSID pSID);
255 QAuthzClientContext(
const QAuthzResourceManager &rm, HANDLE tokenHandle, TokenTag);
257 ~QAuthzClientContext();
259 bool isValid()
const {
return context !=
nullptr; }
261 static constexpr ACCESS_MASK InvalidAccess = ~ACCESS_MASK(0);
263 ACCESS_MASK accessMask(PSECURITY_DESCRIPTOR pSD)
const;
266 Q_DISABLE_COPY_MOVE(QAuthzClientContext)
267 AUTHZ_CLIENT_CONTEXT_HANDLE context =
nullptr;
270QAuthzResourceManager::QAuthzResourceManager()
272 if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
nullptr,
nullptr,
nullptr,
nullptr,
274 resourceManager =
nullptr;
278QAuthzResourceManager::~QAuthzResourceManager()
281 AuthzFreeResourceManager(resourceManager);
285
286
287
288
289
290
291QAuthzClientContext::QAuthzClientContext(
const QAuthzResourceManager &rm, PSID pSID)
298 if (!AuthzInitializeContextFromSid(AUTHZ_SKIP_TOKEN_GROUPS, pSID, rm.resourceManager,
nullptr,
299 unusedId,
nullptr, &context)) {
305
306
307
308
309QAuthzClientContext::QAuthzClientContext(
const QAuthzResourceManager &rm, HANDLE tokenHandle,
317 if (!AuthzInitializeContextFromToken(0, tokenHandle, rm.resourceManager,
nullptr, unusedId,
318 nullptr, &context)) {
323QAuthzClientContext::~QAuthzClientContext()
326 AuthzFreeContext(context);
330
331
332
333
334
335
336ACCESS_MASK QAuthzClientContext::accessMask(PSECURITY_DESCRIPTOR pSD)
const
339 return InvalidAccess;
341 AUTHZ_ACCESS_REQUEST accessRequest = {};
342 AUTHZ_ACCESS_REPLY accessReply = {};
343 ACCESS_MASK accessMask = 0;
346 accessRequest.DesiredAccess = MAXIMUM_ALLOWED;
348 accessReply.ResultListLength = 1;
349 accessReply.GrantedAccessMask = &accessMask;
350 accessReply.Error = &error;
352 if (!AuthzAccessCheck(0, context, &accessRequest,
nullptr, pSD,
nullptr, 0, &accessReply,
355 return InvalidAccess;
361enum NonSpecificPermission {
362 ReadPermission = 0x4,
363 WritePermission = 0x2,
365 AllPermissions = ReadPermission | WritePermission | ExePermission
367Q_DECLARE_FLAGS(NonSpecificPermissions, NonSpecificPermission)
368Q_DECLARE_OPERATORS_FOR_FLAGS(NonSpecificPermissions)
370enum PermissionTag { OtherTag = 0, GroupTag = 4, UserTag = 8, OwnerTag = 12 };
372constexpr NonSpecificPermissions toNonSpecificPermissions(PermissionTag tag,
373 QFileDevice::Permissions permissions)
375 return NonSpecificPermissions::fromInt((permissions.toInt() >>
int(tag)) & 0x7);
379constexpr QFileDevice::Permissions toSpecificPermissions(PermissionTag tag,
380 NonSpecificPermissions permissions)
382 return QFileDevice::Permissions::fromInt(permissions.toInt() <<
int(tag));
388#if QT_DEPRECATED_SINCE(6
,6
)
389int qt_ntfs_permission_lookup = 0;
395QT_WARNING_DISABLE_DEPRECATED
399 return qt_ntfs_permission_lookup_v2.fetchAndAddRelaxed(1)
400QT_IF_DEPRECATED_SINCE(6, 6, , + qt_ntfs_permission_lookup)
406 return qt_ntfs_permission_lookup_v2.fetchAndSubRelaxed(1)
407QT_IF_DEPRECATED_SINCE(6, 6, , + qt_ntfs_permission_lookup)
413 return qt_ntfs_permission_lookup_v2.loadRelaxed()
414QT_IF_DEPRECATED_SINCE(6, 6, , + qt_ntfs_permission_lookup)
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450QNativeFilePermissions::QNativeFilePermissions(std::optional<QFileDevice::Permissions> perms,
461 const auto permissions = *perms;
463 PACL acl =
reinterpret_cast<PACL>(aclStorage);
465 if (!InitializeAcl(acl,
sizeof(aclStorage), ACL_REVISION))
470 ACCESS_MASK denyMask, allowMask;
473 auto makeMasks = [isDir](NonSpecificPermissions allowPermissions,
474 NonSpecificPermissions denyPermissions,
bool owner) {
475 constexpr ACCESS_MASK AllowRead = FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA;
476 constexpr ACCESS_MASK DenyRead = FILE_READ_DATA | FILE_READ_EA;
478 constexpr ACCESS_MASK AllowWrite =
479 FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA;
480 constexpr ACCESS_MASK DenyWrite = AllowWrite | FILE_DELETE_CHILD;
481 constexpr ACCESS_MASK DenyWriteOwner =
482 FILE_WRITE_DATA | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
484 constexpr ACCESS_MASK AllowExe = FILE_EXECUTE;
485 constexpr ACCESS_MASK DenyExe = AllowExe;
487 constexpr ACCESS_MASK StdRightsOther =
488 STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
489 constexpr ACCESS_MASK StdRightsOwner =
490 STANDARD_RIGHTS_ALL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE;
492 ACCESS_MASK allow = owner ? StdRightsOwner : StdRightsOther;
493 ACCESS_MASK deny = 0;
495 if (denyPermissions & ReadPermission)
498 if (denyPermissions & WritePermission)
499 deny |= owner ? DenyWriteOwner : DenyWrite;
501 if (denyPermissions & ExePermission)
504 if (allowPermissions & ReadPermission)
507 if (allowPermissions & WritePermission)
510 if (allowPermissions & ExePermission)
514 if (owner && allowPermissions == AllPermissions)
515 allow |= FILE_DELETE_CHILD;
518 && (allowPermissions & (WritePermission | ExePermission))
519 == (WritePermission | ExePermission)) {
520 allow |= FILE_DELETE_CHILD;
523 return Masks { deny, allow };
526 auto userPermissions = toNonSpecificPermissions(OwnerTag, permissions)
527 | toNonSpecificPermissions(UserTag, permissions);
528 auto groupPermissions = toNonSpecificPermissions(GroupTag, permissions);
529 auto otherPermissions = toNonSpecificPermissions(OtherTag, permissions);
531 auto userMasks = makeMasks(userPermissions,
532 ~userPermissions & (groupPermissions | otherPermissions),
true);
533 auto groupMasks = makeMasks(groupPermissions, ~groupPermissions & otherPermissions,
false);
534 auto otherMasks = makeMasks(otherPermissions, {},
false);
536 const DWORD aceFlags = isDir ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0;
537 const bool reorderGroupDeny = (groupMasks.denyMask & userMasks.allowMask) == 0;
539 const auto addDenyAce = [acl, aceFlags](
const Masks &masks, PSID pSID) {
541 return AddAccessDeniedAceEx(acl, ACL_REVISION, aceFlags, masks.denyMask, pSID);
545 const auto addAllowAce = [acl, aceFlags](
const Masks &masks, PSID pSID) {
547 return AddAccessAllowedAceEx(acl, ACL_REVISION, aceFlags, masks.allowMask, pSID);
551 if (!addDenyAce(userMasks, currentUserSID))
554 if (reorderGroupDeny) {
555 if (!addDenyAce(groupMasks, currentGroupSID))
559 if (!addAllowAce(userMasks, currentUserSID))
562 if (!reorderGroupDeny) {
563 if (!addDenyAce(groupMasks, currentGroupSID))
567 if (!addAllowAce(groupMasks, currentGroupSID))
570 if (!addAllowAce(otherMasks, worldSID))
573 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
576 if (!SetSecurityDescriptorOwner(&sd, currentUserSID, FALSE))
579 if (!SetSecurityDescriptorGroup(&sd, currentGroupSID, FALSE))
582 if (!SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
585 sa.nLength =
sizeof(sa);
586 sa.lpSecurityDescriptor = &sd;
587 sa.bInheritHandle = FALSE;
598
599
600
601
602
603
604
605SECURITY_ATTRIBUTES *QNativeFilePermissions::securityAttributes()
608 return isNull ?
nullptr : &sa;
611static inline bool toFileTime(
const QDateTime &date, FILETIME *fileTime)
614 if (date.timeSpec() == Qt::LocalTime) {
616 const QDate d = date.date();
617 const QTime t = date.time();
619 lTime.wYear = d.year();
620 lTime.wMonth = d.month();
621 lTime.wDay = d.day();
622 lTime.wHour = t.hour();
623 lTime.wMinute = t.minute();
624 lTime.wSecond = t.second();
625 lTime.wMilliseconds = t.msec();
626 lTime.wDayOfWeek = d.dayOfWeek() % 7;
628 if (!::TzSpecificLocalTimeToSystemTime(
nullptr, &lTime, &sTime))
631 QDateTime utcDate = date.toUTC();
632 const QDate d = utcDate.date();
633 const QTime t = utcDate.time();
635 sTime.wYear = d.year();
636 sTime.wMonth = d.month();
637 sTime.wDay = d.day();
638 sTime.wHour = t.hour();
639 sTime.wMinute = t.minute();
640 sTime.wSecond = t.second();
641 sTime.wMilliseconds = t.msec();
642 sTime.wDayOfWeek = d.dayOfWeek() % 7;
645 return ::SystemTimeToFileTime(&sTime, fileTime);
651 HANDLE handle = CreateFile((
wchar_t *)link.nativeFilePath().utf16(), FILE_READ_EA,
652 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
654 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
nullptr);
655 if (handle != INVALID_HANDLE_VALUE) {
657 REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)malloc(bufsize);
662 if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
663 int length = rdb->MountPointReparseBuffer.SubstituteNameLength /
sizeof(
wchar_t);
664 int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset /
sizeof(
wchar_t);
665 const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[offset];
666 result = QString::fromWCharArray(PathBuffer, length);
668 int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength /
sizeof(
wchar_t);
669 int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset /
sizeof(
wchar_t);
670 const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset];
671 result = QString::fromWCharArray(PathBuffer, length);
674 result = QFileSystemEntry::removeUncOrLongPathPrefix(result);
679#if QT_CONFIG(fslibs) && QT_CONFIG(regularexpression)
681 QRegularExpression matchVolumeRe(
"^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"_L1,
682 QRegularExpression::CaseInsensitiveOption);
683 auto matchVolume = matchVolumeRe.match(result);
684 if (matchVolume.hasMatch()) {
685 Q_ASSERT(matchVolume.capturedStart() == 0);
687 wchar_t buffer[MAX_PATH];
688 const QString volumeName =
"\\\\?\\"_L1 + matchVolume.captured();
689 if (GetVolumePathNamesForVolumeName(qt_castToWchar(volumeName), buffer, MAX_PATH, &len)
691 result.replace(0, matchVolume.capturedLength(), QString::fromWCharArray(buffer));
699static QString
readLink(
const QFileSystemEntry &link)
706 wchar_t szGotPath[MAX_PATH];
708 QComHelper comHelper;
711 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
714 if (SUCCEEDED(hres)) {
716 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
717 if (SUCCEEDED(hres)) {
718 hres = ppf->Load((LPOLESTR)link.nativeFilePath().utf16(), STGM_READ);
721 if (SUCCEEDED(hres)) {
722 if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
723 ret = QString::fromWCharArray(szGotPath);
740 const auto parts = QStringView{server}.split(u'\\', Qt::SkipEmptyParts);
741 if (parts.count() >= 3) {
743 if (QFileSystemEngine::uncListSharesOnServer(
"\\\\"_L1 + parts.at(2), &shares))
744 return parts.count() < 4
745 || shares.contains(parts.at(3).toString(), Qt::CaseInsensitive);
750static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
753 while (path.endsWith(u'\\'))
757 if (!path.endsWith(u':')) {
758 HANDLE hFind = ::FindFirstFile((
wchar_t*)path.utf16(), &findData);
759 if (hFind != INVALID_HANDLE_VALUE) {
857bool QFileSystemEngine::uncListSharesOnServer(
const QString &server, QStringList *list)
859 DWORD res = ERROR_NOT_SUPPORTED;
860 SHARE_INFO_1 *BufPtr, *p;
861 DWORD er = 0, tr = 0, resume = 0, i;
863 res = NetShareEnum((
wchar_t *)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr,
865 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) {
867 for (i = 1; i <= er; ++i) {
868 if (list && p->shi1_type == 0)
869 list->append(QString::fromWCharArray(p->shi1_netname));
873 NetApiBufferFree(BufPtr);
874 }
while (res == ERROR_MORE_DATA);
875 return res == ERROR_SUCCESS;
878void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
881 data.fileAttribute_ = 0;
882 data.birthTime_ = FILETIME();
883 data.changeTime_ = FILETIME();
884 data.lastAccessTime_ = FILETIME();
885 data.lastWriteTime_ = FILETIME();
889QFileSystemEntry QFileSystemEngine::getLinkTarget(
const QFileSystemEntry &link,
890 QFileSystemMetaData &data)
892 QFileSystemEntry ret = getRawLinkPath(link, data);
893 if (!ret.isEmpty() && ret.isRelative()) {
894 QString target = absoluteName(link).path() + u'/' + ret.filePath();
895 ret = QFileSystemEntry(QDir::cleanPath(target));
901QFileSystemEntry QFileSystemEngine::getRawLinkPath(
const QFileSystemEntry &link,
902 QFileSystemMetaData &data)
906 if (data.missingFlags(QFileSystemMetaData::LinkType))
907 QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType);
910 if (data.isLnkFile())
911 target = readLink(link);
912 else if (data.isLink())
913 target = readSymLink(link);
914 return QFileSystemEntry(target);
918QFileSystemEntry QFileSystemEngine::junctionTarget(
const QFileSystemEntry &link,
919 QFileSystemMetaData &data)
923 if (data.missingFlags(QFileSystemMetaData::JunctionType))
924 QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType);
927 if (data.isJunction())
928 target = readSymLink(link);
929 QFileSystemEntry ret(target);
930 if (!target.isEmpty() && ret.isRelative()) {
931 target.prepend(absoluteName(link).path() + u'/');
932 ret = QFileSystemEntry(QDir::cleanPath(target));
938QFileSystemEntry QFileSystemEngine::canonicalName(
const QFileSystemEntry &entry,
939 QFileSystemMetaData &data)
943 if (data.missingFlags(QFileSystemMetaData::ExistsAttribute))
944 QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
947 return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
949 return QFileSystemEntry();
953QString QFileSystemEngine::nativeAbsoluteFilePath(
const QString &path)
959 QVarLengthArray<
wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
960 wchar_t *fileName =
nullptr;
961 DWORD retLen = GetFullPathName((
wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
962 if (retLen > (DWORD)buf.size()) {
964 retLen = GetFullPathName((
wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
967 absPath = QString::fromWCharArray(buf.data(), retLen);
974 if (!path.isEmpty() && path.at(path.size() - 1) == u' ')
975 absPath.append(u' ');
980QFileSystemEntry QFileSystemEngine::absoluteName(
const QFileSystemEntry &entry)
986 if (!entry.isRelative()) {
987 if (entry.isAbsolute() && entry.isClean())
988 ret = entry.filePath();
990 ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath()));
992 ret = QDir::cleanPath(QDir::currentPath() + u'/' + entry.filePath());
999 if (ret.at(0) != u'/') {
1000 Q_ASSERT(ret.length() >= 2);
1001 Q_ASSERT(ret.at(0).isLetter());
1002 Q_ASSERT(ret.at(1) == u':');
1005 ret[0] = ret.at(0).toUpper();
1007 return QFileSystemEntry(ret, QFileSystemEntry::FromInternalPath());
1013 BY_HANDLE_FILE_INFORMATION info;
1014 if (GetFileInformationByHandle(handle, &info)) {
1016 id.volumeId = info.dwVolumeSerialNumber;
1017 id.fileId[0] = (quint64(info.nFileIndexHigh) << 32) | info.nFileIndexLow;
1026#if !defined(QT_BOOTSTRAPPED)
1027 FILE_ID_INFO infoEx;
1028 if (GetFileInformationByHandleEx(
1030 static_cast<FILE_INFO_BY_HANDLE_CLASS>(18),
1031 &infoEx,
sizeof(FILE_ID_INFO))) {
1033 id.volumeId = infoEx.VolumeSerialNumber;
1035 static_assert(
sizeof(infoEx.FileId) ==
sizeof(id.fileId));
1036 memcpy(id.fileId.data(), &infoEx.FileId,
sizeof(infoEx.FileId));
1040 return fileId(handle);
1042 return fileId(handle);
1050 char buffer[
sizeof "0123456789abcdef:0123456789abcdef0123456789abcdef"];
1051 std::snprintf(buffer,
sizeof(buffer),
"%llx:%016llx%016llx",
1052 qulonglong(volumeId), qulonglong(fileId[1]), qulonglong(fileId[0]));
1057QFileSystemNativeId QFileSystemEngine::nativeId(
const QFileSystemEntry &entry)
1061 QFileSystemNativeId result;
1062 const HANDLE handle = CreateFile((
wchar_t *)entry.nativeFilePath().utf16(), 0, FILE_SHARE_READ,
1063 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
1064 if (handle != INVALID_HANDLE_VALUE) {
1065 result = nativeId(handle);
1066 CloseHandle(handle);
1072QFileSystemNativeId QFileSystemEngine::nativeId(HANDLE fHandle)
1074 return fileIdWin8(HANDLE(fHandle));
1078bool QFileSystemEngine::setFileTime(HANDLE fHandle,
const QDateTime &newDate,
1079 QFile::FileTime time, QSystemError &error)
1082 FILETIME *pLastWrite =
nullptr;
1083 FILETIME *pLastAccess =
nullptr;
1084 FILETIME *pCreationTime =
nullptr;
1087 case QFile::FileModificationTime:
1088 pLastWrite = &fTime;
1091 case QFile::FileAccessTime:
1092 pLastAccess = &fTime;
1095 case QFile::FileBirthTime:
1096 pCreationTime = &fTime;
1100 error = QSystemError(ERROR_INVALID_PARAMETER, QSystemError::NativeError);
1104 if (!toFileTime(newDate, &fTime))
1107 if (!::SetFileTime(fHandle, pCreationTime, pLastAccess, pLastWrite)) {
1108 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1114QString QFileSystemEngine::owner(
const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
1117#if QT_CONFIG(fslibs)
1118 if (qAreNtfsPermissionChecksEnabled()) {
1122 PSECURITY_DESCRIPTOR pSD;
1123 if (GetNamedSecurityInfo(
1124 reinterpret_cast<
const wchar_t *>(entry.nativeFilePath().utf16()),
1126 own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION
1127 : OWNER_SECURITY_INFORMATION,
1128 own == QAbstractFileEngine::OwnerUser ? &pOwner :
nullptr,
1129 own == QAbstractFileEngine::OwnerGroup ? &pOwner :
nullptr,
nullptr,
1134 QVarLengthArray<
wchar_t, 64> owner(lowner);
1135 QVarLengthArray<
wchar_t, 64> domain(ldomain);
1136 SID_NAME_USE use = SidTypeUnknown;
1138 if (!LookupAccountSid(
nullptr, pOwner, (LPWSTR)owner.data(), &lowner, domain.data(),
1140 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1141 if (lowner > (DWORD)owner.size())
1142 owner.resize(lowner);
1143 if (ldomain > (DWORD)domain.size())
1144 domain.resize(ldomain);
1146 if (!LookupAccountSid(
nullptr, pOwner, owner.data(), &lowner, domain.data(),
1155 name = QString::fromWCharArray(owner.data());
1168bool QFileSystemEngine::fillPermissions(
const QFileSystemEntry &entry, QFileSystemMetaData &data,
1169 QFileSystemMetaData::MetaDataFlags what)
1171#if QT_CONFIG(fslibs)
1172 if (qAreNtfsPermissionChecksEnabled()) {
1175 QString fname = entry.nativeFilePath();
1179 PSECURITY_DESCRIPTOR pSD;
1184 DWORD res = GetNamedSecurityInfo(
1185 reinterpret_cast<
const wchar_t *>(fname.utf16()), SE_FILE_OBJECT,
1186 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1187 &pOwner, &pGroup, &pDacl,
nullptr, &pSD);
1188 if (res == ERROR_SUCCESS) {
1189 QAuthzResourceManager rm;
1191 auto addPermissions = [&data](ACCESS_MASK accessMask,
1192 QFileSystemMetaData::MetaDataFlag readFlags,
1193 QFileSystemMetaData::MetaDataFlag writeFlags,
1194 QFileSystemMetaData::MetaDataFlag executeFlags) {
1200 if (accessMask & (GENERIC_READ | FILE_READ_DATA))
1201 data.entryFlags |= readFlags;
1202 if (accessMask & (GENERIC_WRITE | FILE_WRITE_DATA))
1203 data.entryFlags |= writeFlags;
1204 if (accessMask & (GENERIC_EXECUTE | FILE_EXECUTE))
1205 data.entryFlags |= executeFlags;
1208 if (what & QFileSystemMetaData::UserPermissions && currentUserImpersonatedToken) {
1209 data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
1210 QAuthzClientContext context(rm, currentUserImpersonatedToken,
1211 QAuthzClientContext::TokenTag {});
1212 addPermissions(context.accessMask(pSD),
1213 QFileSystemMetaData::UserReadPermission,
1214 QFileSystemMetaData::UserWritePermission,
1215 QFileSystemMetaData::UserExecutePermission);
1218 if (what & QFileSystemMetaData::OwnerPermissions) {
1219 data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions;
1220 QAuthzClientContext context(rm, pOwner);
1221 addPermissions(context.accessMask(pSD),
1222 QFileSystemMetaData::OwnerReadPermission,
1223 QFileSystemMetaData::OwnerWritePermission,
1224 QFileSystemMetaData::OwnerExecutePermission);
1227 if (what & QFileSystemMetaData::GroupPermissions) {
1228 data.knownFlagsMask |= QFileSystemMetaData::GroupPermissions;
1229 QAuthzClientContext context(rm, pGroup);
1230 addPermissions(context.accessMask(pSD),
1231 QFileSystemMetaData::GroupReadPermission,
1232 QFileSystemMetaData::GroupWritePermission,
1233 QFileSystemMetaData::GroupExecutePermission);
1236 if (what & QFileSystemMetaData::OtherPermissions) {
1237 data.knownFlagsMask |= QFileSystemMetaData::OtherPermissions;
1238 QAuthzClientContext context(rm, worldSID);
1239 addPermissions(context.accessMask(pSD),
1240 QFileSystemMetaData::OtherReadPermission,
1241 QFileSystemMetaData::OtherWritePermission,
1242 QFileSystemMetaData::OtherExecutePermission);
1253 data.entryFlags |= QFileSystemMetaData::OwnerReadPermission
1254 | QFileSystemMetaData::GroupReadPermission
1255 | QFileSystemMetaData::OtherReadPermission;
1257 if (!(data.fileAttribute_ & FILE_ATTRIBUTE_READONLY)) {
1258 data.entryFlags |= QFileSystemMetaData::OwnerWritePermission
1259 | QFileSystemMetaData::GroupWritePermission
1260 | QFileSystemMetaData::OtherWritePermission;
1263 QString fname = entry.filePath();
1264 QString ext = fname.right(4).toLower();
1265 if (data.isDirectory() || ext ==
".exe"_L1 || ext ==
".com"_L1
1266 || ext ==
".bat"_L1 || ext ==
".pif"_L1 || ext ==
".cmd"_L1) {
1267 data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission
1268 | QFileSystemMetaData::GroupExecutePermission
1269 | QFileSystemMetaData::OtherExecutePermission
1270 | QFileSystemMetaData::UserExecutePermission;
1272 data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions
1273 | QFileSystemMetaData::GroupPermissions | QFileSystemMetaData::OtherPermissions
1274 | QFileSystemMetaData::UserExecutePermission;
1276 if (what & QFileSystemMetaData::UserReadPermission) {
1277 if (::_waccess((
wchar_t*)entry.nativeFilePath().utf16(), R_OK) == 0)
1278 data.entryFlags |= QFileSystemMetaData::UserReadPermission;
1279 data.knownFlagsMask |= QFileSystemMetaData::UserReadPermission;
1281 if (what & QFileSystemMetaData::UserWritePermission) {
1282 if (::_waccess((
wchar_t*)entry.nativeFilePath().utf16(), W_OK) == 0)
1283 data.entryFlags |= QFileSystemMetaData::UserWritePermission;
1284 data.knownFlagsMask |= QFileSystemMetaData::UserWritePermission;
1288 return data.hasFlags(what);
1293 bool entryExists =
false;
1294 DWORD fileAttrib = 0;
1295 if (fname.isDriveRoot()) {
1297 const UINT oldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1298 DWORD drivesBitmask = ::GetLogicalDrives();
1299 ::SetErrorMode(oldErrorMode);
1301 1 << (fname.filePath().at(0).toUpper().unicode() - u'A');
1302 if (drivesBitmask & drivebit) {
1303 fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM;
1307 const QString &path = fname.nativeFilePath();
1308 bool is_dir =
false;
1309 if (path.startsWith(
"\\\\?\\UNC"_L1)) {
1311 int s = path.indexOf(path.at(0),7);
1314 s = path.indexOf(path.at(0),s+1);
1317 if (s == path.size() - 1) {
1334 fileAttrib = FILE_ATTRIBUTE_DIRECTORY;
1339 data.fillFromFileAttribute(fileAttrib);
1345 bool filledData =
false;
1347 int errorCode = GetLastError();
1348 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1349 WIN32_FIND_DATA findData;
1350 if (getFindData(fname.nativeFilePath(), findData)
1352 data.fillFromFindData(findData,
true, fname.isDriveRoot());
1360bool QFileSystemEngine::fillMetaData(
int fd, QFileSystemMetaData &data,
1361 QFileSystemMetaData::MetaDataFlags what)
1363 auto fHandle =
reinterpret_cast<HANDLE>(_get_osfhandle(fd));
1364 if (fHandle != INVALID_HANDLE_VALUE) {
1365 return fillMetaData(fHandle, data, what);
1371bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
1372 QFileSystemMetaData::MetaDataFlags what)
1374 data.entryFlags &= ~what;
1375 clearWinStatData(data);
1376 BY_HANDLE_FILE_INFORMATION fileInfo;
1377 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1378 if (GetFileInformationByHandle(fHandle , &fileInfo)) {
1379 data.fillFromFindInfo(fileInfo);
1381 SetErrorMode(oldmode);
1382 return data.hasFlags(what);
1386bool QFileSystemEngine::fillMetaData(
const QFileSystemEntry &entry, QFileSystemMetaData &data,
1387 QFileSystemMetaData::MetaDataFlags what)
1390 what |= QFileSystemMetaData::WinLnkType | QFileSystemMetaData::WinStatFlags;
1391 data.entryFlags &= ~what;
1393 QFileSystemEntry fname;
1394 data.knownFlagsMask |= QFileSystemMetaData::WinLnkType;
1397 const QString origFilePath = entry.filePath();
1398 if (
bool exists; origFilePath.endsWith(
".lnk"_L1) && !isDirPath(origFilePath, &exists) && exists) {
1399 data.entryFlags |= QFileSystemMetaData::WinLnkType;
1400 fname = QFileSystemEntry(readLink(entry));
1405 if (fname.isEmpty()) {
1406 data.knownFlagsMask |= what;
1407 clearWinStatData(data);
1411 if (what & QFileSystemMetaData::WinStatFlags) {
1412 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1413 clearWinStatData(data);
1414 WIN32_FIND_DATA findData;
1417 bool ok = ::GetFileAttributesEx(
1418 reinterpret_cast<
const wchar_t *>(fname.nativeFilePath().utf16()),
1419 GetFileExInfoStandard,
reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *>(&findData));
1421 data.fillFromFindData(findData,
false, fname.isDriveRoot());
1423 const DWORD lastError = GetLastError();
1425 if (lastError == ERROR_LOGON_FAILURE || lastError == ERROR_BAD_NETPATH
1426 || (!tryFindFallback(fname, data) && !tryDriveUNCFallback(fname, data))) {
1428 SetErrorMode(oldmode);
1432 SetErrorMode(oldmode);
1435 if (what & QFileSystemMetaData::Permissions)
1436 fillPermissions(fname, data, what);
1437 if (what & QFileSystemMetaData::LinkType) {
1438 data.knownFlagsMask |= QFileSystemMetaData::LinkType;
1439 if (data.fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
1440 WIN32_FIND_DATA findData;
1441 if (getFindData(fname.nativeFilePath(), findData))
1442 data.fillFromFindData(findData,
true);
1445 data.knownFlagsMask |= what;
1446 return data.hasFlags(what);
1449static inline bool mkDir(
const QString &path, SECURITY_ATTRIBUTES *securityAttributes,
1450 DWORD *lastError =
nullptr)
1454 const QString longPath = QFSFileEnginePrivate::longFileName(path);
1455 const bool result = ::CreateDirectory((
wchar_t *)longPath.utf16(), securityAttributes);
1458 *lastError = GetLastError();
1462static inline bool rmDir(
const QString &path)
1464 return ::RemoveDirectory((
wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
1468bool QFileSystemEngine::isDirPath(
const QString &dirPath,
bool *existed)
1470 QString path = dirPath;
1471 if (path.length() == 2 && path.at(1) == u':')
1474 const QString longPath = QFSFileEnginePrivate::longFileName(path);
1475 DWORD fileAttrib = ::GetFileAttributes(
reinterpret_cast<
const wchar_t*>(longPath.utf16()));
1477 int errorCode = GetLastError();
1478 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1479 WIN32_FIND_DATA findData;
1480 if (getFindData(longPath, findData))
1481 fileAttrib = findData.dwFileAttributes;
1491 return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
1497 SECURITY_ATTRIBUTES *securityAttributes,
1498 bool shouldMkdirFirst =
true)
1500 const auto isUNCRoot = [](
const QString &nativeName) {
1501 return nativeName.startsWith(
"\\\\"_L1)
1502 && nativeName.count(QDir::separator()) <= 3;
1504 const auto isDriveName = [](
const QString &nativeName) {
1505 return nativeName.size() == 2 && nativeName.at(1) == u':';
1507 const auto isDir = [](
const QString &nativeName) {
1508 bool exists =
false;
1509 return QFileSystemEngine::isDirPath(nativeName, &exists) && exists;
1512 if (isUNCRoot(nativeName) || isDriveName(nativeName))
1515 if (shouldMkdirFirst) {
1516 if (mkDir(nativeName, securityAttributes))
1520 const int backSlash = nativeName.lastIndexOf(QDir::separator());
1524 const QString parentNativeName = nativeName.left(backSlash);
1525 if (!createDirectoryWithParents(parentNativeName, securityAttributes))
1529 if (mkDir(nativeName, securityAttributes))
1531 return isDir(nativeName);
1534bool QFileSystemEngine::mkpath(
const QFileSystemEntry &entry,
1535 std::optional<QFile::Permissions> permissions)
1537 QString dirName = entry.filePath();
1540 QNativeFilePermissions nativePermissions(permissions,
true);
1541 if (!nativePermissions.isOk())
1544 auto securityAttributes = nativePermissions.securityAttributes();
1545 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
1549 if (mkDir(dirName, securityAttributes, &lastError))
1552 if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED)
1553 return isDirPath(dirName,
nullptr);
1555 return createDirectoryWithParents(dirName, securityAttributes,
false);
1558bool QFileSystemEngine::mkdir(
const QFileSystemEntry &entry,
1559 std::optional<QFile::Permissions> permissions)
1561 QString dirName = entry.filePath();
1565 QNativeFilePermissions nativePermissions(permissions,
true);
1566 if (!nativePermissions.isOk())
1569 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
1570 return mkDir(dirName, nativePermissions.securityAttributes());
1573bool QFileSystemEngine::rmdir(
const QFileSystemEntry &entry)
1575 QString dirName = entry.filePath();
1578 return rmDir(dirName);
1581bool QFileSystemEngine::rmpath(
const QFileSystemEntry &entry)
1583 const QString dirName = QDir::toNativeSeparators(QDir::cleanPath(entry.filePath()));
1586 for (
int oldslash = 0, slash = dirName.size(); slash > 0; oldslash = slash) {
1587 const auto chunkRef = QStringView{dirName}.left(slash);
1588 if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
1589 && chunkRef.at(1) == u':') {
1592 const QString chunk = chunkRef.toString();
1594 if (!isDirPath(chunk,
nullptr))
1597 return oldslash != 0;
1598 slash = dirName.lastIndexOf(QDir::separator(), oldslash - 1);
1605QString QFileSystemEngine::rootPath()
1607 QString ret = qEnvironmentVariable(
"SystemDrive");
1615QString QFileSystemEngine::homePath()
1618#if QT_CONFIG(fslibs)
1621 HANDLE hnd = ::GetCurrentProcess();
1622 HANDLE token =
nullptr;
1623 BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token);
1625 DWORD dwBufferSize = 0;
1627 ok = GetUserProfileDirectory(token,
nullptr, &dwBufferSize);
1628 if (!ok && dwBufferSize != 0) {
1629 wchar_t *userDirectory =
new wchar_t[dwBufferSize];
1631 ok = GetUserProfileDirectory(token, userDirectory, &dwBufferSize);
1633 ret = QString::fromWCharArray(userDirectory);
1634 delete [] userDirectory;
1636 ::CloseHandle(token);
1640 if (ret.isEmpty() || !QFile::exists(ret)) {
1641 ret = qEnvironmentVariable(
"USERPROFILE");
1642 if (ret.isEmpty() || !QFile::exists(ret)) {
1643 ret = qEnvironmentVariable(
"HOMEDRIVE")
1644 + qEnvironmentVariable(
"HOMEPATH");
1645 if (ret.isEmpty() || !QFile::exists(ret)) {
1646 ret = qEnvironmentVariable(
"HOME");
1647 if (ret.isEmpty() || !QFile::exists(ret))
1652 return QDir::fromNativeSeparators(ret);
1655QString QFileSystemEngine::tempPath()
1658 wchar_t tempPath[MAX_PATH];
1659 using GetTempPathPrototype = DWORD (WINAPI *)(DWORD, LPWSTR);
1661 static GetTempPathPrototype getTempPathW = []() {
1662 const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
1663 if (
auto *func = QFunctionPointer(GetProcAddress(kernel32,
"GetTempPath2W")))
1664 return GetTempPathPrototype(func);
1667 const DWORD len = getTempPathW(MAX_PATH, tempPath);
1669 wchar_t longTempPath[MAX_PATH];
1670 const DWORD longLen = GetLongPathName(tempPath, longTempPath, MAX_PATH);
1671 ret = longLen && longLen < MAX_PATH ?
1672 QString::fromWCharArray(longTempPath, longLen) :
1673 QString::fromWCharArray(tempPath, len);
1675 if (!ret.isEmpty()) {
1676 while (ret.endsWith(u'\\'))
1678 ret = QDir::fromNativeSeparators(ret);
1680 if (ret.isEmpty()) {
1682 }
else if (ret.length() >= 2 && ret[1] == u':')
1683 ret[0] = ret.at(0).toUpper();
1687bool QFileSystemEngine::setCurrentPath(
const QFileSystemEntry &entry)
1689 QFileSystemMetaData meta;
1690 fillMetaData(entry, meta,
1691 QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType);
1692 if (!(meta.exists() && meta.isDirectory()))
1698 return ::SetCurrentDirectory(
reinterpret_cast<
const wchar_t *>(
1699 QDir::toNativeSeparators(entry.filePath()).utf16()))
1703QFileSystemEntry QFileSystemEngine::currentPath()
1705 QString ret(
PATH_MAX, Qt::Uninitialized);
1706 DWORD size = GetCurrentDirectoryW(
PATH_MAX,
reinterpret_cast<
wchar_t *>(ret.data()));
1710 size = GetCurrentDirectoryW(size,
reinterpret_cast<
wchar_t *>(ret.data()));
1715 if (size >= 2 && ret.at(1) == u':')
1716 ret[0] = ret.at(0).toUpper();
1718 return QFileSystemEntry(std::move(ret), QFileSystemEntry::FromNativePath());
1722bool QFileSystemEngine::createLink(
const QFileSystemEntry &source,
const QFileSystemEntry &target,
1723 QSystemError &error)
1726 QComHelper comHelper;
1727 IShellLink *psl =
nullptr;
1728 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
1729 reinterpret_cast<
void **>(&psl));
1731 if (SUCCEEDED(hres)) {
1732 const auto name = QDir::toNativeSeparators(source.filePath());
1733 const auto pathName = QDir::toNativeSeparators(source.path());
1734 if (SUCCEEDED(psl->SetPath(
reinterpret_cast<
const wchar_t *>(name.utf16())))
1735 && SUCCEEDED(psl->SetWorkingDirectory(
1736 reinterpret_cast<
const wchar_t *>(pathName.utf16())))) {
1737 IPersistFile *ppf =
nullptr;
1738 if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<
void **>(&ppf)))) {
1739 ret = SUCCEEDED(ppf->Save(
1740 reinterpret_cast<
const wchar_t *>(target.filePath().utf16()), TRUE));
1748 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1754bool QFileSystemEngine::copyFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target,
1755 QSystemError &error)
1757 bool ret = ::CopyFile((
wchar_t*)source.nativeFilePath().utf16(),
1758 (
wchar_t*)target.nativeFilePath().utf16(),
true) != 0;
1760 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1765bool QFileSystemEngine::renameFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target,
1766 QSystemError &error)
1771 bool ret = ::MoveFile((
wchar_t*)source.nativeFilePath().utf16(),
1772 (
wchar_t*)target.nativeFilePath().utf16()) != 0;
1774 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1779bool QFileSystemEngine::renameOverwriteFile(
const QFileSystemEntry &source,
1780 const QFileSystemEntry &target, QSystemError &error)
1785 bool ret = ::MoveFileEx(
reinterpret_cast<
const wchar_t *>(source.nativeFilePath().utf16()),
1786 reinterpret_cast<
const wchar_t *>(target.nativeFilePath().utf16()),
1787 MOVEFILE_REPLACE_EXISTING) != 0;
1789 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1794bool QFileSystemEngine::removeFile(
const QFileSystemEntry &entry, QSystemError &error)
1798 bool ret = ::DeleteFile((
wchar_t*)entry.nativeFilePath().utf16()) != 0;
1800 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1805bool QFileSystemEngine::supportsMoveFileToTrash()
1811bool QFileSystemEngine::supportsRmdirRecursively()
noexcept
1817bool QFileSystemEngine::rmdirRecursively(
const QFileSystemEntry &, QSystemError &error)
1819 error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
1824
1825
1826
1827
1828
1830bool QFileSystemEngine::moveFileToTrash(
const QFileSystemEntry &source,
1831 QFileSystemEntry &newLocation, QSystemError &error)
1834 const QString sourcePath = QDir::toNativeSeparators(absoluteName(source).filePath());
1836 QComHelper comHelper;
1838 IFileOperation *pfo =
nullptr;
1839 IShellItem *deleteItem =
nullptr;
1840 FileOperationProgressSink *sink =
nullptr;
1841 HRESULT hres = E_FAIL;
1843 auto coUninitialize = qScopeGuard([&](){
1847 deleteItem->Release();
1850 if (!SUCCEEDED(hres))
1851 error = QSystemError(hres, QSystemError::NativeError);
1854 hres = CoCreateInstance(CLSID_FileOperation,
nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
1857 pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
1858 | FOF_SILENT | FOF_NOERRORUI);
1859 hres = SHCreateItemFromParsingName(
reinterpret_cast<
const wchar_t*>(sourcePath.utf16()),
1860 nullptr, IID_PPV_ARGS(&deleteItem));
1863 sink =
new FileOperationProgressSink;
1864 hres = pfo->DeleteItem(deleteItem,
static_cast<IFileOperationProgressSink*>(sink));
1865 if (!SUCCEEDED(hres))
1867 hres = pfo->PerformOperations();
1868 if (!SUCCEEDED(hres))
1871 if (!SUCCEEDED(sink->deleteResult)) {
1872 error = QSystemError(sink->deleteResult, QSystemError::NativeError);
1875 newLocation = QFileSystemEntry(sink->targetPath);
1880bool QFileSystemEngine::setPermissions(
const QFileSystemEntry &entry,
1881 QFile::Permissions permissions, QSystemError &error)
1887 if (permissions & (QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther))
1890 & (QFile::WriteOwner | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther)) {
1898 ::_wchmod(
reinterpret_cast<
const wchar_t *>(entry.nativeFilePath().utf16()), mode) == 0;
1900 error = QSystemError(errno, QSystemError::StandardLibraryError);
1904bool QFileSystemEngine::isCaseSensitive(
const QFileSystemEntry &, QFileSystemMetaData &)
1912 if (time->dwHighDateTime == 0 && time->dwLowDateTime == 0)
1916 FileTimeToSystemTime(time, &sTime);
1917 return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
1918 QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
1922QDateTime QFileSystemMetaData::birthTime()
const
1924 return fileTimeToQDateTime(&birthTime_);
1926QDateTime QFileSystemMetaData::metadataChangeTime()
const
1928 return fileTimeToQDateTime(&changeTime_);
1930QDateTime QFileSystemMetaData::modificationTime()
const
1932 return fileTimeToQDateTime(&lastWriteTime_);
1934QDateTime QFileSystemMetaData::accessTime()
const
1936 return fileTimeToQDateTime(&lastAccessTime_);
virtual ~FileOperationProgressSink()
FileOperationProgressSink()
qEnableNtfsPermissionChecks()
qDisableNtfsPermissionChecks()
qAreNtfsPermissionChecksEnabled()
[raii]
#define Q_CHECK_FILE_NAME(name, result)
#define FSCTL_GET_REPARSE_POINT
static bool toFileTime(const QDateTime &date, FILETIME *fileTime)
static QString readSymLink(const QFileSystemEntry &link)
static bool tryFindFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data)
static QFileSystemNativeId fileId(HANDLE handle)
static bool rmDir(const QString &path)
#define INVALID_FILE_ATTRIBUTES
static QBasicAtomicInt qt_ntfs_permission_lookup_v2
static bool mkDir(const QString &path, SECURITY_ATTRIBUTES *securityAttributes, DWORD *lastError=nullptr)
static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data)
static QFileSystemNativeId fileIdWin8(HANDLE handle)
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
static QString readLink(const QFileSystemEntry &link)
static bool createDirectoryWithParents(const QString &nativeName, SECURITY_ATTRIBUTES *securityAttributes, bool shouldMkdirFirst=true)
static QDateTime fileTimeToQDateTime(const FILETIME *time)
static bool uncShareExists(const QString &server)
#define IO_REPARSE_TAG_SYMLINK
static bool getFindData(QString path, WIN32_FIND_DATA &findData)
bool isValid() const noexcept
USHORT SubstituteNameLength
USHORT SubstituteNameOffset