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)) {
1015 char buffer[
sizeof "01234567:0123456701234567"];
1016 std::snprintf(buffer,
sizeof(buffer),
"%lx:%08lx%08lx",
1017 info.dwVolumeSerialNumber,
1018 info.nFileIndexHigh,
1019 info.nFileIndexLow);
1022 return QByteArray();
1028#if !defined(QT_BOOTSTRAPPED)
1030 FILE_ID_INFO infoEx;
1031 if (GetFileInformationByHandleEx(
1033 static_cast<FILE_INFO_BY_HANDLE_CLASS>(18),
1034 &infoEx,
sizeof(FILE_ID_INFO))) {
1035 result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
1038 result += QByteArray(
reinterpret_cast<
const char *>(&infoEx.FileId),
1039 int(
sizeof(infoEx.FileId)))
1043 result = fileId(handle);
1047 return fileId(handle);
1052QByteArray QFileSystemEngine::id(
const QFileSystemEntry &entry)
1058 const HANDLE handle = CreateFile((
wchar_t *)entry.nativeFilePath().utf16(), 0, FILE_SHARE_READ,
1059 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
1060 if (handle != INVALID_HANDLE_VALUE) {
1061 result = id(handle);
1062 CloseHandle(handle);
1068QByteArray QFileSystemEngine::id(HANDLE fHandle)
1070 return fileIdWin8(HANDLE(fHandle));
1074bool QFileSystemEngine::setFileTime(HANDLE fHandle,
const QDateTime &newDate,
1075 QFile::FileTime time, QSystemError &error)
1078 FILETIME *pLastWrite =
nullptr;
1079 FILETIME *pLastAccess =
nullptr;
1080 FILETIME *pCreationTime =
nullptr;
1083 case QFile::FileModificationTime:
1084 pLastWrite = &fTime;
1087 case QFile::FileAccessTime:
1088 pLastAccess = &fTime;
1091 case QFile::FileBirthTime:
1092 pCreationTime = &fTime;
1096 error = QSystemError(ERROR_INVALID_PARAMETER, QSystemError::NativeError);
1100 if (!toFileTime(newDate, &fTime))
1103 if (!::SetFileTime(fHandle, pCreationTime, pLastAccess, pLastWrite)) {
1104 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1110QString QFileSystemEngine::owner(
const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
1113#if QT_CONFIG(fslibs)
1114 if (qAreNtfsPermissionChecksEnabled()) {
1118 PSECURITY_DESCRIPTOR pSD;
1119 if (GetNamedSecurityInfo(
1120 reinterpret_cast<
const wchar_t *>(entry.nativeFilePath().utf16()),
1122 own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION
1123 : OWNER_SECURITY_INFORMATION,
1124 own == QAbstractFileEngine::OwnerUser ? &pOwner :
nullptr,
1125 own == QAbstractFileEngine::OwnerGroup ? &pOwner :
nullptr,
nullptr,
1130 QVarLengthArray<
wchar_t, 64> owner(lowner);
1131 QVarLengthArray<
wchar_t, 64> domain(ldomain);
1132 SID_NAME_USE use = SidTypeUnknown;
1134 if (!LookupAccountSid(
nullptr, pOwner, (LPWSTR)owner.data(), &lowner, domain.data(),
1136 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1137 if (lowner > (DWORD)owner.size())
1138 owner.resize(lowner);
1139 if (ldomain > (DWORD)domain.size())
1140 domain.resize(ldomain);
1142 if (!LookupAccountSid(
nullptr, pOwner, owner.data(), &lowner, domain.data(),
1151 name = QString::fromWCharArray(owner.data());
1164bool QFileSystemEngine::fillPermissions(
const QFileSystemEntry &entry, QFileSystemMetaData &data,
1165 QFileSystemMetaData::MetaDataFlags what)
1167#if QT_CONFIG(fslibs)
1168 if (qAreNtfsPermissionChecksEnabled()) {
1171 QString fname = entry.nativeFilePath();
1175 PSECURITY_DESCRIPTOR pSD;
1180 DWORD res = GetNamedSecurityInfo(
1181 reinterpret_cast<
const wchar_t *>(fname.utf16()), SE_FILE_OBJECT,
1182 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1183 &pOwner, &pGroup, &pDacl,
nullptr, &pSD);
1184 if (res == ERROR_SUCCESS) {
1185 QAuthzResourceManager rm;
1187 auto addPermissions = [&data](ACCESS_MASK accessMask,
1188 QFileSystemMetaData::MetaDataFlag readFlags,
1189 QFileSystemMetaData::MetaDataFlag writeFlags,
1190 QFileSystemMetaData::MetaDataFlag executeFlags) {
1196 if (accessMask & (GENERIC_READ | FILE_READ_DATA))
1197 data.entryFlags |= readFlags;
1198 if (accessMask & (GENERIC_WRITE | FILE_WRITE_DATA))
1199 data.entryFlags |= writeFlags;
1200 if (accessMask & (GENERIC_EXECUTE | FILE_EXECUTE))
1201 data.entryFlags |= executeFlags;
1204 if (what & QFileSystemMetaData::UserPermissions && currentUserImpersonatedToken) {
1205 data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
1206 QAuthzClientContext context(rm, currentUserImpersonatedToken,
1207 QAuthzClientContext::TokenTag {});
1208 addPermissions(context.accessMask(pSD),
1209 QFileSystemMetaData::UserReadPermission,
1210 QFileSystemMetaData::UserWritePermission,
1211 QFileSystemMetaData::UserExecutePermission);
1214 if (what & QFileSystemMetaData::OwnerPermissions) {
1215 data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions;
1216 QAuthzClientContext context(rm, pOwner);
1217 addPermissions(context.accessMask(pSD),
1218 QFileSystemMetaData::OwnerReadPermission,
1219 QFileSystemMetaData::OwnerWritePermission,
1220 QFileSystemMetaData::OwnerExecutePermission);
1223 if (what & QFileSystemMetaData::GroupPermissions) {
1224 data.knownFlagsMask |= QFileSystemMetaData::GroupPermissions;
1225 QAuthzClientContext context(rm, pGroup);
1226 addPermissions(context.accessMask(pSD),
1227 QFileSystemMetaData::GroupReadPermission,
1228 QFileSystemMetaData::GroupWritePermission,
1229 QFileSystemMetaData::GroupExecutePermission);
1232 if (what & QFileSystemMetaData::OtherPermissions) {
1233 data.knownFlagsMask |= QFileSystemMetaData::OtherPermissions;
1234 QAuthzClientContext context(rm, worldSID);
1235 addPermissions(context.accessMask(pSD),
1236 QFileSystemMetaData::OtherReadPermission,
1237 QFileSystemMetaData::OtherWritePermission,
1238 QFileSystemMetaData::OtherExecutePermission);
1249 data.entryFlags |= QFileSystemMetaData::OwnerReadPermission
1250 | QFileSystemMetaData::GroupReadPermission
1251 | QFileSystemMetaData::OtherReadPermission;
1253 if (!(data.fileAttribute_ & FILE_ATTRIBUTE_READONLY)) {
1254 data.entryFlags |= QFileSystemMetaData::OwnerWritePermission
1255 | QFileSystemMetaData::GroupWritePermission
1256 | QFileSystemMetaData::OtherWritePermission;
1259 QString fname = entry.filePath();
1260 QString ext = fname.right(4).toLower();
1261 if (data.isDirectory() || ext ==
".exe"_L1 || ext ==
".com"_L1
1262 || ext ==
".bat"_L1 || ext ==
".pif"_L1 || ext ==
".cmd"_L1) {
1263 data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission
1264 | QFileSystemMetaData::GroupExecutePermission
1265 | QFileSystemMetaData::OtherExecutePermission
1266 | QFileSystemMetaData::UserExecutePermission;
1268 data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions
1269 | QFileSystemMetaData::GroupPermissions | QFileSystemMetaData::OtherPermissions
1270 | QFileSystemMetaData::UserExecutePermission;
1272 if (what & QFileSystemMetaData::UserReadPermission) {
1273 if (::_waccess((
wchar_t*)entry.nativeFilePath().utf16(), R_OK) == 0)
1274 data.entryFlags |= QFileSystemMetaData::UserReadPermission;
1275 data.knownFlagsMask |= QFileSystemMetaData::UserReadPermission;
1277 if (what & QFileSystemMetaData::UserWritePermission) {
1278 if (::_waccess((
wchar_t*)entry.nativeFilePath().utf16(), W_OK) == 0)
1279 data.entryFlags |= QFileSystemMetaData::UserWritePermission;
1280 data.knownFlagsMask |= QFileSystemMetaData::UserWritePermission;
1284 return data.hasFlags(what);
1289 bool entryExists =
false;
1290 DWORD fileAttrib = 0;
1291 if (fname.isDriveRoot()) {
1293 const UINT oldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1294 DWORD drivesBitmask = ::GetLogicalDrives();
1295 ::SetErrorMode(oldErrorMode);
1297 1 << (fname.filePath().at(0).toUpper().unicode() - u'A');
1298 if (drivesBitmask & drivebit) {
1299 fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM;
1303 const QString &path = fname.nativeFilePath();
1304 bool is_dir =
false;
1305 if (path.startsWith(
"\\\\?\\UNC"_L1)) {
1307 int s = path.indexOf(path.at(0),7);
1310 s = path.indexOf(path.at(0),s+1);
1313 if (s == path.size() - 1) {
1330 fileAttrib = FILE_ATTRIBUTE_DIRECTORY;
1335 data.fillFromFileAttribute(fileAttrib);
1341 bool filledData =
false;
1343 int errorCode = GetLastError();
1344 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1345 WIN32_FIND_DATA findData;
1346 if (getFindData(fname.nativeFilePath(), findData)
1348 data.fillFromFindData(findData,
true, fname.isDriveRoot());
1356bool QFileSystemEngine::fillMetaData(
int fd, QFileSystemMetaData &data,
1357 QFileSystemMetaData::MetaDataFlags what)
1359 auto fHandle =
reinterpret_cast<HANDLE>(_get_osfhandle(fd));
1360 if (fHandle != INVALID_HANDLE_VALUE) {
1361 return fillMetaData(fHandle, data, what);
1367bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
1368 QFileSystemMetaData::MetaDataFlags what)
1370 data.entryFlags &= ~what;
1371 clearWinStatData(data);
1372 BY_HANDLE_FILE_INFORMATION fileInfo;
1373 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1374 if (GetFileInformationByHandle(fHandle , &fileInfo)) {
1375 data.fillFromFindInfo(fileInfo);
1377 SetErrorMode(oldmode);
1378 return data.hasFlags(what);
1382bool QFileSystemEngine::fillMetaData(
const QFileSystemEntry &entry, QFileSystemMetaData &data,
1383 QFileSystemMetaData::MetaDataFlags what)
1386 what |= QFileSystemMetaData::WinLnkType | QFileSystemMetaData::WinStatFlags;
1387 data.entryFlags &= ~what;
1389 QFileSystemEntry fname;
1390 data.knownFlagsMask |= QFileSystemMetaData::WinLnkType;
1393 const QString origFilePath = entry.filePath();
1394 if (
bool exists; origFilePath.endsWith(
".lnk"_L1) && !isDirPath(origFilePath, &exists) && exists) {
1395 data.entryFlags |= QFileSystemMetaData::WinLnkType;
1396 fname = QFileSystemEntry(readLink(entry));
1401 if (fname.isEmpty()) {
1402 data.knownFlagsMask |= what;
1403 clearWinStatData(data);
1407 if (what & QFileSystemMetaData::WinStatFlags) {
1408 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1409 clearWinStatData(data);
1410 WIN32_FIND_DATA findData;
1413 bool ok = ::GetFileAttributesEx(
1414 reinterpret_cast<
const wchar_t *>(fname.nativeFilePath().utf16()),
1415 GetFileExInfoStandard,
reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *>(&findData));
1417 data.fillFromFindData(findData,
false, fname.isDriveRoot());
1419 const DWORD lastError = GetLastError();
1421 if (lastError == ERROR_LOGON_FAILURE || lastError == ERROR_BAD_NETPATH
1422 || (!tryFindFallback(fname, data) && !tryDriveUNCFallback(fname, data))) {
1424 SetErrorMode(oldmode);
1428 SetErrorMode(oldmode);
1431 if (what & QFileSystemMetaData::Permissions)
1432 fillPermissions(fname, data, what);
1433 if (what & QFileSystemMetaData::LinkType) {
1434 data.knownFlagsMask |= QFileSystemMetaData::LinkType;
1435 if (data.fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
1436 WIN32_FIND_DATA findData;
1437 if (getFindData(fname.nativeFilePath(), findData))
1438 data.fillFromFindData(findData,
true);
1441 data.knownFlagsMask |= what;
1442 return data.hasFlags(what);
1445static inline bool mkDir(
const QString &path, SECURITY_ATTRIBUTES *securityAttributes,
1446 DWORD *lastError =
nullptr)
1450 const QString longPath = QFSFileEnginePrivate::longFileName(path);
1451 const bool result = ::CreateDirectory((
wchar_t *)longPath.utf16(), securityAttributes);
1454 *lastError = GetLastError();
1458static inline bool rmDir(
const QString &path)
1460 return ::RemoveDirectory((
wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
1464bool QFileSystemEngine::isDirPath(
const QString &dirPath,
bool *existed)
1466 QString path = dirPath;
1467 if (path.length() == 2 && path.at(1) == u':')
1470 const QString longPath = QFSFileEnginePrivate::longFileName(path);
1471 DWORD fileAttrib = ::GetFileAttributes(
reinterpret_cast<
const wchar_t*>(longPath.utf16()));
1473 int errorCode = GetLastError();
1474 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1475 WIN32_FIND_DATA findData;
1476 if (getFindData(longPath, findData))
1477 fileAttrib = findData.dwFileAttributes;
1487 return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
1493 SECURITY_ATTRIBUTES *securityAttributes,
1494 bool shouldMkdirFirst =
true)
1496 const auto isUNCRoot = [](
const QString &nativeName) {
1497 return nativeName.startsWith(
"\\\\"_L1)
1498 && nativeName.count(QDir::separator()) <= 3;
1500 const auto isDriveName = [](
const QString &nativeName) {
1501 return nativeName.size() == 2 && nativeName.at(1) == u':';
1503 const auto isDir = [](
const QString &nativeName) {
1504 bool exists =
false;
1505 return QFileSystemEngine::isDirPath(nativeName, &exists) && exists;
1508 if (isUNCRoot(nativeName) || isDriveName(nativeName))
1511 if (shouldMkdirFirst) {
1512 if (mkDir(nativeName, securityAttributes))
1516 const int backSlash = nativeName.lastIndexOf(QDir::separator());
1520 const QString parentNativeName = nativeName.left(backSlash);
1521 if (!createDirectoryWithParents(parentNativeName, securityAttributes))
1525 if (mkDir(nativeName, securityAttributes))
1527 return isDir(nativeName);
1530bool QFileSystemEngine::mkpath(
const QFileSystemEntry &entry,
1531 std::optional<QFile::Permissions> permissions)
1533 QString dirName = entry.filePath();
1536 QNativeFilePermissions nativePermissions(permissions,
true);
1537 if (!nativePermissions.isOk())
1540 auto securityAttributes = nativePermissions.securityAttributes();
1541 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
1545 if (mkDir(dirName, securityAttributes, &lastError))
1548 if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED)
1549 return isDirPath(dirName,
nullptr);
1551 return createDirectoryWithParents(dirName, securityAttributes,
false);
1554bool QFileSystemEngine::mkdir(
const QFileSystemEntry &entry,
1555 std::optional<QFile::Permissions> permissions)
1557 QString dirName = entry.filePath();
1561 QNativeFilePermissions nativePermissions(permissions,
true);
1562 if (!nativePermissions.isOk())
1565 dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
1566 return mkDir(dirName, nativePermissions.securityAttributes());
1569bool QFileSystemEngine::rmdir(
const QFileSystemEntry &entry)
1571 QString dirName = entry.filePath();
1574 return rmDir(dirName);
1577bool QFileSystemEngine::rmpath(
const QFileSystemEntry &entry)
1579 const QString dirName = QDir::toNativeSeparators(QDir::cleanPath(entry.filePath()));
1582 for (
int oldslash = 0, slash = dirName.size(); slash > 0; oldslash = slash) {
1583 const auto chunkRef = QStringView{dirName}.left(slash);
1584 if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
1585 && chunkRef.at(1) == u':') {
1588 const QString chunk = chunkRef.toString();
1590 if (!isDirPath(chunk,
nullptr))
1593 return oldslash != 0;
1594 slash = dirName.lastIndexOf(QDir::separator(), oldslash - 1);
1601QString QFileSystemEngine::rootPath()
1603 QString ret = QString::fromLatin1(qgetenv(
"SystemDrive"));
1611QString QFileSystemEngine::homePath()
1614#if QT_CONFIG(fslibs)
1617 HANDLE hnd = ::GetCurrentProcess();
1618 HANDLE token =
nullptr;
1619 BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token);
1621 DWORD dwBufferSize = 0;
1623 ok = GetUserProfileDirectory(token,
nullptr, &dwBufferSize);
1624 if (!ok && dwBufferSize != 0) {
1625 wchar_t *userDirectory =
new wchar_t[dwBufferSize];
1627 ok = GetUserProfileDirectory(token, userDirectory, &dwBufferSize);
1629 ret = QString::fromWCharArray(userDirectory);
1630 delete [] userDirectory;
1632 ::CloseHandle(token);
1636 if (ret.isEmpty() || !QFile::exists(ret)) {
1637 ret = QString::fromLocal8Bit(qgetenv(
"USERPROFILE"));
1638 if (ret.isEmpty() || !QFile::exists(ret)) {
1639 ret = QString::fromLocal8Bit(qgetenv(
"HOMEDRIVE"))
1640 + QString::fromLocal8Bit(qgetenv(
"HOMEPATH"));
1641 if (ret.isEmpty() || !QFile::exists(ret)) {
1642 ret = QString::fromLocal8Bit(qgetenv(
"HOME"));
1643 if (ret.isEmpty() || !QFile::exists(ret))
1648 return QDir::fromNativeSeparators(ret);
1651QString QFileSystemEngine::tempPath()
1654 wchar_t tempPath[MAX_PATH];
1655 using GetTempPathPrototype = DWORD (WINAPI *)(DWORD, LPWSTR);
1657 static GetTempPathPrototype getTempPathW = []() {
1658 const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
1659 if (
auto *func = QFunctionPointer(GetProcAddress(kernel32,
"GetTempPath2W")))
1660 return GetTempPathPrototype(func);
1663 const DWORD len = getTempPathW(MAX_PATH, tempPath);
1665 wchar_t longTempPath[MAX_PATH];
1666 const DWORD longLen = GetLongPathName(tempPath, longTempPath, MAX_PATH);
1667 ret = longLen && longLen < MAX_PATH ?
1668 QString::fromWCharArray(longTempPath, longLen) :
1669 QString::fromWCharArray(tempPath, len);
1671 if (!ret.isEmpty()) {
1672 while (ret.endsWith(u'\\'))
1674 ret = QDir::fromNativeSeparators(ret);
1676 if (ret.isEmpty()) {
1678 }
else if (ret.length() >= 2 && ret[1] == u':')
1679 ret[0] = ret.at(0).toUpper();
1683bool QFileSystemEngine::setCurrentPath(
const QFileSystemEntry &entry)
1685 QFileSystemMetaData meta;
1686 fillMetaData(entry, meta,
1687 QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType);
1688 if (!(meta.exists() && meta.isDirectory()))
1694 return ::SetCurrentDirectory(
reinterpret_cast<
const wchar_t *>(
1695 QDir::toNativeSeparators(entry.filePath()).utf16()))
1699QFileSystemEntry QFileSystemEngine::currentPath()
1701 QString ret(
PATH_MAX, Qt::Uninitialized);
1702 DWORD size = GetCurrentDirectoryW(
PATH_MAX,
reinterpret_cast<
wchar_t *>(ret.data()));
1706 size = GetCurrentDirectoryW(size,
reinterpret_cast<
wchar_t *>(ret.data()));
1711 if (size >= 2 && ret.at(1) == u':')
1712 ret[0] = ret.at(0).toUpper();
1714 return QFileSystemEntry(std::move(ret), QFileSystemEntry::FromNativePath());
1718bool QFileSystemEngine::createLink(
const QFileSystemEntry &source,
const QFileSystemEntry &target,
1719 QSystemError &error)
1722 QComHelper comHelper;
1723 IShellLink *psl =
nullptr;
1724 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
1725 reinterpret_cast<
void **>(&psl));
1727 if (SUCCEEDED(hres)) {
1728 const auto name = QDir::toNativeSeparators(source.filePath());
1729 const auto pathName = QDir::toNativeSeparators(source.path());
1730 if (SUCCEEDED(psl->SetPath(
reinterpret_cast<
const wchar_t *>(name.utf16())))
1731 && SUCCEEDED(psl->SetWorkingDirectory(
1732 reinterpret_cast<
const wchar_t *>(pathName.utf16())))) {
1733 IPersistFile *ppf =
nullptr;
1734 if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<
void **>(&ppf)))) {
1735 ret = SUCCEEDED(ppf->Save(
1736 reinterpret_cast<
const wchar_t *>(target.filePath().utf16()), TRUE));
1744 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1750bool QFileSystemEngine::copyFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target,
1751 QSystemError &error)
1753 bool ret = ::CopyFile((
wchar_t*)source.nativeFilePath().utf16(),
1754 (
wchar_t*)target.nativeFilePath().utf16(),
true) != 0;
1756 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1761bool QFileSystemEngine::renameFile(
const QFileSystemEntry &source,
const QFileSystemEntry &target,
1762 QSystemError &error)
1767 bool ret = ::MoveFile((
wchar_t*)source.nativeFilePath().utf16(),
1768 (
wchar_t*)target.nativeFilePath().utf16()) != 0;
1770 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1775bool QFileSystemEngine::renameOverwriteFile(
const QFileSystemEntry &source,
1776 const QFileSystemEntry &target, QSystemError &error)
1781 bool ret = ::MoveFileEx(
reinterpret_cast<
const wchar_t *>(source.nativeFilePath().utf16()),
1782 reinterpret_cast<
const wchar_t *>(target.nativeFilePath().utf16()),
1783 MOVEFILE_REPLACE_EXISTING) != 0;
1785 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1790bool QFileSystemEngine::removeFile(
const QFileSystemEntry &entry, QSystemError &error)
1794 bool ret = ::DeleteFile((
wchar_t*)entry.nativeFilePath().utf16()) != 0;
1796 error = QSystemError(::GetLastError(), QSystemError::NativeError);
1801bool QFileSystemEngine::supportsMoveFileToTrash()
1807
1808
1809
1810
1811
1813bool QFileSystemEngine::moveFileToTrash(
const QFileSystemEntry &source,
1814 QFileSystemEntry &newLocation, QSystemError &error)
1817 const QString sourcePath = QDir::toNativeSeparators(absoluteName(source).filePath());
1819 QComHelper comHelper;
1821 IFileOperation *pfo =
nullptr;
1822 IShellItem *deleteItem =
nullptr;
1823 FileOperationProgressSink *sink =
nullptr;
1824 HRESULT hres = E_FAIL;
1826 auto coUninitialize = qScopeGuard([&](){
1830 deleteItem->Release();
1833 if (!SUCCEEDED(hres))
1834 error = QSystemError(hres, QSystemError::NativeError);
1837 hres = CoCreateInstance(CLSID_FileOperation,
nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
1840 pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
1841 | FOF_SILENT | FOF_NOERRORUI);
1842 hres = SHCreateItemFromParsingName(
reinterpret_cast<
const wchar_t*>(sourcePath.utf16()),
1843 nullptr, IID_PPV_ARGS(&deleteItem));
1846 sink =
new FileOperationProgressSink;
1847 hres = pfo->DeleteItem(deleteItem,
static_cast<IFileOperationProgressSink*>(sink));
1848 if (!SUCCEEDED(hres))
1850 hres = pfo->PerformOperations();
1851 if (!SUCCEEDED(hres))
1854 if (!SUCCEEDED(sink->deleteResult)) {
1855 error = QSystemError(sink->deleteResult, QSystemError::NativeError);
1858 newLocation = QFileSystemEntry(sink->targetPath);
1863bool QFileSystemEngine::setPermissions(
const QFileSystemEntry &entry,
1864 QFile::Permissions permissions, QSystemError &error)
1870 if (permissions & (QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther))
1873 & (QFile::WriteOwner | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther)) {
1881 ::_wchmod(
reinterpret_cast<
const wchar_t *>(entry.nativeFilePath().utf16()), mode) == 0;
1883 error = QSystemError(errno, QSystemError::StandardLibraryError);
1887bool QFileSystemEngine::isCaseSensitive(
const QFileSystemEntry &, QFileSystemMetaData &)
1895 if (time->dwHighDateTime == 0 && time->dwLowDateTime == 0)
1899 FileTimeToSystemTime(time, &sTime);
1900 return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
1901 QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
1905QDateTime QFileSystemMetaData::birthTime()
const
1907 return fileTimeToQDateTime(&birthTime_);
1909QDateTime QFileSystemMetaData::metadataChangeTime()
const
1911 return fileTimeToQDateTime(&changeTime_);
1913QDateTime QFileSystemMetaData::modificationTime()
const
1915 return fileTimeToQDateTime(&lastWriteTime_);
1917QDateTime QFileSystemMetaData::accessTime()
const
1919 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 bool rmDir(const QString &path)
static QByteArray fileId(HANDLE handle)
#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)
QByteArray 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)
USHORT SubstituteNameLength
USHORT SubstituteNameOffset