6#include "qplatformdefs.h"
9#include "private/qabstractfileengine_p.h"
10#include "private/qfiledevice_p.h"
11#include "private/qfsfileengine_p.h"
12#include <private/qsystemlibrary_p.h>
20#if QT_CONFIG(regularexpression)
40#include <QtCore/private/qfunctions_win_p.h>
42#ifndef SPI_GETPLATFORMTYPE
43#define SPI_GETPLATFORMTYPE 257
47#define PATH_MAX FILENAME_MAX
50#ifndef _INTPTR_T_DEFINED
60#define _INTPTR_T_DEFINED
63#ifndef INVALID_FILE_ATTRIBUTES
64# define INVALID_FILE_ATTRIBUTES (DWORD (-1))
67#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE)
93# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
96#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
97# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384
99#ifndef IO_REPARSE_TAG_SYMLINK
100# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
102#ifndef FSCTL_GET_REPARSE_POINT
103# define FSCTL_GET_REPARSE_POINT \
104 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
111static PSID currentUserSID =
nullptr;
112static PSID currentGroupSID =
nullptr;
113static PSID worldSID =
nullptr;
114static HANDLE currentUserImpersonatedToken =
nullptr;
128GlobalSid::~GlobalSid()
130 free(currentUserSID);
131 currentUserSID =
nullptr;
133 free(currentGroupSID);
134 currentGroupSID =
nullptr;
142 if (currentUserImpersonatedToken) {
143 ::CloseHandle(currentUserImpersonatedToken);
144 currentUserImpersonatedToken =
nullptr;
155static T *getTokenInfo(
HANDLE token, TOKEN_INFORMATION_CLASS infoClass)
158 GetTokenInformation(
token, infoClass,
nullptr, 0, &retsize);
160 void *tokenBuffer = malloc(retsize);
161 if (::GetTokenInformation(
token, infoClass, tokenBuffer, retsize, &retsize))
162 return reinterpret_cast<T *
>(tokenBuffer);
173static void copySID(PSID &dstSid, PSID srcSid)
175 DWORD sidLen = GetLengthSid(srcSid);
176 dstSid =
reinterpret_cast<PSID
>(malloc(sidLen));
178 CopySid(sidLen, dstSid, srcSid);
181GlobalSid::GlobalSid()
183 HANDLE hnd = ::GetCurrentProcess();
185 if (::OpenProcessToken(hnd, TOKEN_QUERY, &
token)) {
187 if (
auto info = getTokenInfo<TOKEN_USER>(
token, TokenUser)) {
188 copySID(currentUserSID,
info->User.Sid);
193 if (
auto info = getTokenInfo<TOKEN_GROUPS>(
token, TokenGroups)) {
194 copySID(currentGroupSID,
info->Groups[0].Sid);
197 ::CloseHandle(
token);
201 if (::OpenProcessToken(hnd,
202 TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ,
204 ::DuplicateToken(
token, SecurityImpersonation, ¤tUserImpersonatedToken);
205 ::CloseHandle(
token);
209 SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
210 AllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID);
221class QAuthzResourceManager
224 QAuthzResourceManager();
225 ~QAuthzResourceManager();
227 bool isValid()
const {
return resourceManager !=
nullptr; }
230 friend class QAuthzClientContext;
231 Q_DISABLE_COPY_MOVE(QAuthzResourceManager)
233 AUTHZ_RESOURCE_MANAGER_HANDLE resourceManager;
242class QAuthzClientContext
250 QAuthzClientContext(
const QAuthzResourceManager &rm, PSID pSID);
251 QAuthzClientContext(
const QAuthzResourceManager &rm,
HANDLE tokenHandle, TokenTag);
253 ~QAuthzClientContext();
255 bool isValid()
const {
return context !=
nullptr; }
257 static constexpr ACCESS_MASK InvalidAccess = ~ACCESS_MASK(0);
259 ACCESS_MASK accessMask(PSECURITY_DESCRIPTOR pSD)
const;
262 Q_DISABLE_COPY_MOVE(QAuthzClientContext)
263 AUTHZ_CLIENT_CONTEXT_HANDLE
context =
nullptr;
266QAuthzResourceManager::QAuthzResourceManager()
268 if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
nullptr,
nullptr,
nullptr,
nullptr,
270 resourceManager =
nullptr;
274QAuthzResourceManager::~QAuthzResourceManager()
277 AuthzFreeResourceManager(resourceManager);
287QAuthzClientContext::QAuthzClientContext(
const QAuthzResourceManager &rm, PSID pSID)
294 if (!AuthzInitializeContextFromSid(AUTHZ_SKIP_TOKEN_GROUPS, pSID, rm.resourceManager,
nullptr,
295 unusedId,
nullptr, &
context)) {
305QAuthzClientContext::QAuthzClientContext(
const QAuthzResourceManager &rm,
HANDLE tokenHandle,
313 if (!AuthzInitializeContextFromToken(0, tokenHandle, rm.resourceManager,
nullptr, unusedId,
319QAuthzClientContext::~QAuthzClientContext()
332ACCESS_MASK QAuthzClientContext::accessMask(PSECURITY_DESCRIPTOR pSD)
const
335 return InvalidAccess;
337 AUTHZ_ACCESS_REQUEST accessRequest = {};
338 AUTHZ_ACCESS_REPLY accessReply = {};
339 ACCESS_MASK accessMask = 0;
342 accessRequest.DesiredAccess = MAXIMUM_ALLOWED;
344 accessReply.ResultListLength = 1;
345 accessReply.GrantedAccessMask = &accessMask;
346 accessReply.Error = &
error;
348 if (!AuthzAccessCheck(0,
context, &accessRequest,
nullptr, pSD,
nullptr, 0, &accessReply,
351 return InvalidAccess;
357enum NonSpecificPermission {
358 ReadPermission = 0x4,
359 WritePermission = 0x2,
361 AllPermissions = ReadPermission | WritePermission | ExePermission
366enum PermissionTag { OtherTag = 0, GroupTag = 4, UserTag = 8, OwnerTag = 12 };
368constexpr NonSpecificPermissions toNonSpecificPermissions(PermissionTag
tag,
369 QFileDevice::Permissions permissions)
371 return NonSpecificPermissions::fromInt((permissions.toInt() >>
int(
tag)) & 0x7);
375constexpr QFileDevice::Permissions toSpecificPermissions(PermissionTag
tag,
376 NonSpecificPermissions permissions)
378 return QFileDevice::Permissions::fromInt(permissions.toInt() <<
int(
tag));
384#if QT_DEPRECATED_SINCE(6,6)
464QNativeFilePermissions::QNativeFilePermissions(std::optional<QFileDevice::Permissions> perms,
475 const auto permissions = *perms;
477 PACL acl =
reinterpret_cast<PACL
>(aclStorage);
479 if (!InitializeAcl(acl,
sizeof(aclStorage), ACL_REVISION))
484 ACCESS_MASK denyMask, allowMask;
487 auto makeMasks = [isDir](NonSpecificPermissions allowPermissions,
488 NonSpecificPermissions denyPermissions,
bool owner) {
489 constexpr ACCESS_MASK AllowRead = FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA;
490 constexpr ACCESS_MASK DenyRead = FILE_READ_DATA | FILE_READ_EA;
492 constexpr ACCESS_MASK AllowWrite =
493 FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA;
494 constexpr ACCESS_MASK DenyWrite = AllowWrite | FILE_DELETE_CHILD;
495 constexpr ACCESS_MASK DenyWriteOwner =
496 FILE_WRITE_DATA | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
498 constexpr ACCESS_MASK AllowExe = FILE_EXECUTE;
499 constexpr ACCESS_MASK DenyExe = AllowExe;
501 constexpr ACCESS_MASK StdRightsOther =
502 STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
503 constexpr ACCESS_MASK StdRightsOwner =
504 STANDARD_RIGHTS_ALL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE;
506 ACCESS_MASK allow = owner ? StdRightsOwner : StdRightsOther;
507 ACCESS_MASK deny = 0;
509 if (denyPermissions & ReadPermission)
512 if (denyPermissions & WritePermission)
513 deny |= owner ? DenyWriteOwner : DenyWrite;
515 if (denyPermissions & ExePermission)
518 if (allowPermissions & ReadPermission)
521 if (allowPermissions & WritePermission)
524 if (allowPermissions & ExePermission)
528 if (owner && allowPermissions == AllPermissions)
529 allow |= FILE_DELETE_CHILD;
532 && (allowPermissions & (WritePermission | ExePermission))
533 == (WritePermission | ExePermission)) {
534 allow |= FILE_DELETE_CHILD;
537 return Masks { deny, allow };
540 auto userPermissions = toNonSpecificPermissions(OwnerTag, permissions)
541 | toNonSpecificPermissions(UserTag, permissions);
542 auto groupPermissions = toNonSpecificPermissions(GroupTag, permissions);
543 auto otherPermissions = toNonSpecificPermissions(OtherTag, permissions);
545 auto userMasks = makeMasks(userPermissions,
546 ~userPermissions & (groupPermissions | otherPermissions),
true);
547 auto groupMasks = makeMasks(groupPermissions, ~groupPermissions & otherPermissions,
false);
548 auto otherMasks = makeMasks(otherPermissions, {},
false);
550 const DWORD aceFlags = isDir ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0;
551 const bool reorderGroupDeny = (groupMasks.denyMask & userMasks.allowMask) == 0;
553 const auto addDenyAce = [acl, aceFlags](
const Masks &masks, PSID pSID) {
555 return AddAccessDeniedAceEx(acl, ACL_REVISION, aceFlags, masks.denyMask, pSID);
559 const auto addAllowAce = [acl, aceFlags](
const Masks &masks, PSID pSID) {
561 return AddAccessAllowedAceEx(acl, ACL_REVISION, aceFlags, masks.allowMask, pSID);
565 if (!addDenyAce(userMasks, currentUserSID))
568 if (reorderGroupDeny) {
569 if (!addDenyAce(groupMasks, currentGroupSID))
573 if (!addAllowAce(userMasks, currentUserSID))
576 if (!reorderGroupDeny) {
577 if (!addDenyAce(groupMasks, currentGroupSID))
581 if (!addAllowAce(groupMasks, currentGroupSID))
584 if (!addAllowAce(otherMasks, worldSID))
587 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
590 if (!SetSecurityDescriptorOwner(&sd, currentUserSID, FALSE))
593 if (!SetSecurityDescriptorGroup(&sd, currentGroupSID, FALSE))
596 if (!SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
599 sa.nLength =
sizeof(sa);
600 sa.lpSecurityDescriptor = &sd;
601 sa.bInheritHandle = FALSE;
619SECURITY_ATTRIBUTES *QNativeFilePermissions::securityAttributes()
633 lTime.wYear =
d.year();
634 lTime.wMonth =
d.month();
635 lTime.wDay =
d.day();
636 lTime.wHour =
t.hour();
637 lTime.wMinute =
t.minute();
638 lTime.wSecond =
t.second();
639 lTime.wMilliseconds =
t.msec();
640 lTime.wDayOfWeek =
d.dayOfWeek() % 7;
642 if (!::TzSpecificLocalTimeToSystemTime(
nullptr, &lTime, &sTime))
649 sTime.wYear =
d.year();
650 sTime.wMonth =
d.month();
651 sTime.wDay =
d.day();
652 sTime.wHour =
t.hour();
653 sTime.wMinute =
t.minute();
654 sTime.wSecond =
t.second();
655 sTime.wMilliseconds =
t.msec();
656 sTime.wDayOfWeek =
d.dayOfWeek() % 7;
659 return ::SystemTimeToFileTime(&sTime, fileTime);
666 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
668 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
nullptr);
669 if (
handle != INVALID_HANDLE_VALUE) {
676 if (rdb->
ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
688 result = QFileSystemEntry::removeUncOrLongPathPrefix(
result);
693#if QT_CONFIG(fslibs) && QT_CONFIG(regularexpression)
698 if (matchVolume.hasMatch()) {
699 Q_ASSERT(matchVolume.capturedStart() == 0);
702 const QString volumeName =
"\\\\?\\"_L1 + matchVolume.captured();
703 if (GetVolumePathNamesForVolumeName(
reinterpret_cast<LPCWSTR
>(volumeName.
utf16()),
723 QComHelper comHelper;
726 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
729 if (SUCCEEDED(hres)) {
731 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
732 if (SUCCEEDED(hres)) {
733 hres = ppf->Load((LPOLESTR)link.
nativeFilePath().utf16(), STGM_READ);
736 if (SUCCEEDED(hres)) {
737 if (psl->GetPath(szGotPath,
MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
756 if (parts.count() >= 3) {
758 if (QFileSystemEngine::uncListSharesOnServer(
"\\\\"_L1 + parts.at(2), &shares))
759 return parts.count() < 4
768 while (
path.endsWith(u
'\\'))
772 if (!
path.endsWith(u
':')) {
773 HANDLE hFind = ::FindFirstFile((
wchar_t*)
path.utf16(), &findData);
774 if (hFind != INVALID_HANDLE_VALUE) {
791 ULONG STDMETHODCALLTYPE
AddRef()
override {
return ++
ref; }
805 *ppvObject =
nullptr;
807 if (iid == __uuidof(IUnknown)) {
808 *ppvObject =
static_cast<IUnknown*
>(
this);
809 }
else if (iid == __uuidof(IFileOperationProgressSink)) {
810 *ppvObject =
static_cast<IFileOperationProgressSink*
>(
this);
818 return E_NOINTERFACE;
825 IShellItem *)
override
830 IShellItem *)
override
835 IShellItem *)
override
840 return (dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE) ? S_OK : E_FAIL;
844 IShellItem *psiNewlyCreated)
override
846 if (psiNewlyCreated) {
847 wchar_t *pszName =
nullptr;
848 psiNewlyCreated->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
851 CoTaskMemFree(pszName);
858 IShellItem *)
override
872 DWORD
res = ERROR_NOT_SUPPORTED;
873 SHARE_INFO_1 *BufPtr, *
p;
876 res = NetShareEnum((
wchar_t *)
server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &
tr,
878 if (
res == ERROR_SUCCESS ||
res == ERROR_MORE_DATA) {
880 for (
i = 1;
i <= er; ++
i) {
881 if (
list &&
p->shi1_type == 0)
886 NetApiBufferFree(BufPtr);
887 }
while (
res == ERROR_MORE_DATA);
888 return res == ERROR_SUCCESS;
894 data.fileAttribute_ = 0;
895 data.birthTime_ = FILETIME();
896 data.changeTime_ = FILETIME();
897 data.lastAccessTime_ = FILETIME();
898 data.lastWriteTime_ = FILETIME();
906 if (!
ret.isEmpty() &&
ret.isRelative()) {
923 if (
data.isLnkFile())
925 else if (
data.isLink())
940 if (
data.isJunction())
943 if (!
target.isEmpty() &&
ret.isRelative()) {
974 DWORD retLen = GetFullPathName((
wchar_t*)
path.utf16(),
buf.size(),
buf.data(), &
fileName);
975 if (retLen > (DWORD)
buf.size()) {
987 if (!
path.isEmpty() &&
path.at(
path.size() - 1) == u
' ')
999 if (!
entry.isRelative()) {
1012 if (
ret.at(0) != u
'/') {
1018 ret[0] =
ret.at(0).toUpper();
1026 BY_HANDLE_FILE_INFORMATION
info;
1027 if (GetFileInformationByHandle(
handle, &
info)) {
1028 char buffer[
sizeof "01234567:0123456701234567"];
1030 info.dwVolumeSerialNumber,
1031 info.nFileIndexHigh,
1032 info.nFileIndexLow);
1041#if !defined(QT_BOOTSTRAPPED)
1043 FILE_ID_INFO infoEx;
1044 if (GetFileInformationByHandleEx(
1046 static_cast<FILE_INFO_BY_HANDLE_CLASS
>(18),
1047 &infoEx,
sizeof(FILE_ID_INFO))) {
1052 int(
sizeof(infoEx.FileId)))
1071 const HANDLE handle = CreateFile((
wchar_t *)
entry.nativeFilePath().utf16(), 0, FILE_SHARE_READ,
1072 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
1073 if (
handle != INVALID_HANDLE_VALUE) {
1091 FILETIME *pLastWrite =
nullptr;
1092 FILETIME *pLastAccess =
nullptr;
1093 FILETIME *pCreationTime =
nullptr;
1097 pLastWrite = &fTime;
1101 pLastAccess = &fTime;
1105 pCreationTime = &fTime;
1116 if (!::SetFileTime(fHandle, pCreationTime, pLastAccess, pLastWrite)) {
1126#if QT_CONFIG(fslibs)
1131 PSECURITY_DESCRIPTOR pSD;
1132 if (GetNamedSecurityInfo(
1133 reinterpret_cast<const wchar_t *
>(
entry.nativeFilePath().utf16()),
1136 : OWNER_SECURITY_INFORMATION,
1145 SID_NAME_USE use = SidTypeUnknown;
1147 if (!LookupAccountSid(
nullptr, pOwner, (LPWSTR)owner.data(), &lowner, domain.data(),
1149 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1150 if (lowner > (DWORD)owner.size())
1151 owner.resize(lowner);
1152 if (ldomain > (DWORD)domain.size())
1153 domain.resize(ldomain);
1155 if (!LookupAccountSid(
nullptr, pOwner, owner.data(), &lowner, domain.data(),
1178 QFileSystemMetaData::MetaDataFlags what)
1180#if QT_CONFIG(fslibs)
1188 PSECURITY_DESCRIPTOR pSD;
1193 DWORD
res = GetNamedSecurityInfo(
1194 reinterpret_cast<const wchar_t *
>(fname.
utf16()), SE_FILE_OBJECT,
1195 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1196 &pOwner, &pGroup, &pDacl,
nullptr, &pSD);
1197 if (
res == ERROR_SUCCESS) {
1198 QAuthzResourceManager rm;
1200 auto addPermissions = [&
data](ACCESS_MASK accessMask,
1209 if (accessMask & (GENERIC_READ | FILE_READ_DATA))
1210 data.entryFlags |= readFlags;
1211 if (accessMask & (GENERIC_WRITE | FILE_WRITE_DATA))
1213 if (accessMask & (GENERIC_EXECUTE | FILE_EXECUTE))
1214 data.entryFlags |= executeFlags;
1219 QAuthzClientContext
context(rm, currentUserImpersonatedToken,
1220 QAuthzClientContext::TokenTag {});
1221 addPermissions(
context.accessMask(pSD),
1229 QAuthzClientContext
context(rm, pOwner);
1230 addPermissions(
context.accessMask(pSD),
1238 QAuthzClientContext
context(rm, pGroup);
1239 addPermissions(
context.accessMask(pSD),
1247 QAuthzClientContext
context(rm, worldSID);
1248 addPermissions(
context.accessMask(pSD),
1266 if (!(
data.fileAttribute_ & FILE_ATTRIBUTE_READONLY)) {
1274 if (
data.isDirectory() ||
ext ==
".exe"_L1 ||
ext ==
".com"_L1
1275 ||
ext ==
".bat"_L1 ||
ext ==
".pif"_L1 ||
ext ==
".cmd"_L1) {
1286 if (::_waccess((
wchar_t*)
entry.nativeFilePath().utf16(), R_OK) == 0)
1291 if (::_waccess((
wchar_t*)
entry.nativeFilePath().utf16(), W_OK) == 0)
1297 return data.hasFlags(what);
1302 bool entryExists =
false;
1303 DWORD fileAttrib = 0;
1304 if (fname.isDriveRoot()) {
1306 const UINT oldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1307 DWORD drivesBitmask = ::GetLogicalDrives();
1308 ::SetErrorMode(oldErrorMode);
1311 if (drivesBitmask & drivebit) {
1312 fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM;
1317 bool is_dir =
false;
1318 if (
path.startsWith(
"\\\\?\\UNC"_L1)) {
1326 if (
s ==
path.size() - 1) {
1343 fileAttrib = FILE_ATTRIBUTE_DIRECTORY;
1348 data.fillFromFileAttribute(fileAttrib);
1354 bool filledData =
false;
1356 int errorCode = GetLastError();
1357 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1358 WIN32_FIND_DATA findData;
1361 data.fillFromFindData(findData,
true, fname.isDriveRoot());
1370 QFileSystemMetaData::MetaDataFlags what)
1372 auto fHandle =
reinterpret_cast<HANDLE>(_get_osfhandle(
fd));
1373 if (fHandle != INVALID_HANDLE_VALUE) {
1381 QFileSystemMetaData::MetaDataFlags what)
1383 data.entryFlags &= ~what;
1384 clearWinStatData(
data);
1385 BY_HANDLE_FILE_INFORMATION fileInfo;
1386 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1387 if (GetFileInformationByHandle(fHandle , &fileInfo)) {
1388 data.fillFromFindInfo(fileInfo);
1390 SetErrorMode(oldmode);
1391 return data.hasFlags(what);
1396 QFileSystemMetaData::MetaDataFlags what)
1400 data.entryFlags &= ~what;
1407 if (origFilePath.
endsWith(
".lnk"_L1) && !isDirPath(origFilePath,
nullptr)) {
1415 data.knownFlagsMask |= what;
1416 clearWinStatData(
data);
1420 if (what & QFileSystemMetaData::WinStatFlags) {
1421 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1422 clearWinStatData(
data);
1423 WIN32_FIND_DATA findData;
1426 bool ok = ::GetFileAttributesEx(
1427 reinterpret_cast<const wchar_t *
>(fname.
nativeFilePath().utf16()),
1428 GetFileExInfoStandard,
reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *
>(&findData));
1430 data.fillFromFindData(findData,
false, fname.isDriveRoot());
1432 const DWORD lastError = GetLastError();
1434 if (lastError == ERROR_LOGON_FAILURE || lastError == ERROR_BAD_NETPATH
1437 SetErrorMode(oldmode);
1441 SetErrorMode(oldmode);
1445 fillPermissions(fname,
data, what);
1448 if (
data.fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
1449 WIN32_FIND_DATA findData;
1451 data.fillFromFindData(findData,
true);
1454 data.knownFlagsMask |= what;
1455 return data.hasFlags(what);
1459 DWORD *lastError =
nullptr)
1463 const QString longPath = QFSFileEnginePrivate::longFileName(
path);
1464 const bool result = ::CreateDirectory((
wchar_t *)longPath.
utf16(), securityAttributes);
1467 *lastError = GetLastError();
1473 return ::RemoveDirectory((
wchar_t*)QFSFileEnginePrivate::longFileName(
path).utf16());
1477bool QFileSystemEngine::isDirPath(
const QString &dirPath,
bool *existed)
1480 if (
path.length() == 2 &&
path.at(1) == u
':')
1483 const QString longPath = QFSFileEnginePrivate::longFileName(
path);
1484 DWORD fileAttrib = ::GetFileAttributes(
reinterpret_cast<const wchar_t*
>(longPath.
utf16()));
1486 int errorCode = GetLastError();
1487 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1488 WIN32_FIND_DATA findData;
1490 fileAttrib = findData.dwFileAttributes;
1500 return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
1506 SECURITY_ATTRIBUTES *securityAttributes,
1507 bool shouldMkdirFirst =
true)
1509 const auto isUNCRoot = [](
const QString &nativeName) {
1513 const auto isDriveName = [](
const QString &nativeName) {
1514 return nativeName.
size() == 2 && nativeName.
at(1) == u
':';
1516 const auto isDir = [](
const QString &nativeName) {
1517 bool exists =
false;
1518 return QFileSystemEngine::isDirPath(nativeName, &exists) && exists;
1521 if (isUNCRoot(nativeName) || isDriveName(nativeName))
1524 if (shouldMkdirFirst) {
1525 if (
mkDir(nativeName, securityAttributes))
1533 const QString parentNativeName = nativeName.
left(backSlash);
1538 if (
mkDir(nativeName, securityAttributes))
1540 return isDir(nativeName);
1545 std::optional<QFile::Permissions> permissions)
1553 if (!nativePermissions.isOk())
1556 auto securityAttributes = nativePermissions.securityAttributes();
1560 if (
mkDir(dirName, securityAttributes, &lastError))
1565 if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED)
1566 return isDirPath(dirName,
nullptr);
1577 if (removeEmptyParents) {
1579 for (
int oldslash = 0, slash=dirName.
length(); slash > 0; oldslash = slash) {
1581 if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
1582 && chunkRef.at(1) == u
':') {
1585 const QString chunk = chunkRef.toString();
1586 if (!isDirPath(chunk,
nullptr))
1589 return oldslash != 0;
1611#if QT_CONFIG(fslibs)
1614 HANDLE hnd = ::GetCurrentProcess();
1616 BOOL
ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &
token);
1618 DWORD dwBufferSize = 0;
1620 ok = GetUserProfileDirectory(
token,
nullptr, &dwBufferSize);
1621 if (!
ok && dwBufferSize != 0) {
1622 wchar_t *userDirectory =
new wchar_t[dwBufferSize];
1624 ok = GetUserProfileDirectory(
token, userDirectory, &dwBufferSize);
1627 delete [] userDirectory;
1629 ::CloseHandle(
token);
1660 if (!
ret.isEmpty()) {
1661 while (
ret.endsWith(u
'\\'))
1665 if (
ret.isEmpty()) {
1667 }
else if (
ret.length() >= 2 &&
ret[1] == u
':')
1668 ret[0] =
ret.at(0).toUpper();
1683 return ::SetCurrentDirectory(
reinterpret_cast<const wchar_t *
>(
1691 DWORD
size = GetCurrentDirectoryW(
PATH_MAX,
reinterpret_cast<wchar_t *
>(
ret.data()));
1695 size = GetCurrentDirectoryW(
size,
reinterpret_cast<wchar_t *
>(
ret.data()));
1700 if (
size >= 2 &&
ret.at(1) == u
':')
1701 ret[0] =
ret.at(0).toUpper();
1711 QComHelper comHelper;
1712 IShellLink *psl =
nullptr;
1713 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
1714 reinterpret_cast<void **
>(&psl));
1716 if (SUCCEEDED(hres)) {
1719 if (SUCCEEDED(psl->SetPath(
reinterpret_cast<const wchar_t *
>(
name.utf16())))
1720 && SUCCEEDED(psl->SetWorkingDirectory(
1721 reinterpret_cast<const wchar_t *
>(pathName.utf16())))) {
1722 IPersistFile *ppf =
nullptr;
1723 if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<void **
>(&ppf)))) {
1724 ret = SUCCEEDED(ppf->Save(
1725 reinterpret_cast<const wchar_t *
>(
target.filePath().utf16()), TRUE));
1742 bool ret = ::CopyFile((
wchar_t*)
source.nativeFilePath().utf16(),
1743 (
wchar_t*)
target.nativeFilePath().utf16(),
true) != 0;
1756 bool ret = ::MoveFile((
wchar_t*)
source.nativeFilePath().utf16(),
1757 (
wchar_t*)
target.nativeFilePath().utf16()) != 0;
1770 bool ret = ::MoveFileEx(
reinterpret_cast<const wchar_t *
>(
source.nativeFilePath().utf16()),
1771 reinterpret_cast<const wchar_t *
>(
target.nativeFilePath().utf16()),
1772 MOVEFILE_REPLACE_EXISTING) != 0;
1783 bool ret = ::DeleteFile((
wchar_t*)
entry.nativeFilePath().utf16()) != 0;
1802 QComHelper comHelper;
1804 IFileOperation *pfo =
nullptr;
1805 IShellItem *deleteItem =
nullptr;
1813 deleteItem->Release();
1816 if (!SUCCEEDED(hres))
1820 hres = CoCreateInstance(CLSID_FileOperation,
nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
1823 pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
1824 | FOF_SILENT | FOF_NOERRORUI);
1825 hres = SHCreateItemFromParsingName(
reinterpret_cast<const wchar_t*
>(sourcePath.
utf16()),
1826 nullptr, IID_PPV_ARGS(&deleteItem));
1830 hres = pfo->DeleteItem(deleteItem,
static_cast<IFileOperationProgressSink*
>(
sink));
1831 if (!SUCCEEDED(hres))
1833 hres = pfo->PerformOperations();
1834 if (!SUCCEEDED(hres))
1862 ::_wchmod(
reinterpret_cast<const wchar_t *
>(
entry.nativeFilePath().utf16()),
mode) == 0;
1870 if (
time->dwHighDateTime == 0 &&
time->dwLowDateTime == 0)
1874 FileTimeToSystemTime(
time, &sTime);
1876 QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
HRESULT STDMETHODCALLTYPE PreRenameItem(DWORD, IShellItem *, LPCWSTR) override
HRESULT STDMETHODCALLTYPE PostDeleteItem(DWORD, IShellItem *, HRESULT, IShellItem *psiNewlyCreated) override
virtual ~FileOperationProgressSink()
HRESULT STDMETHODCALLTYPE PreCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR) override
HRESULT STDMETHODCALLTYPE PostNewItem(DWORD, IShellItem *, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem *) override
HRESULT STDMETHODCALLTYPE UpdateProgress(UINT, UINT) override
HRESULT STDMETHODCALLTYPE PostCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT, IShellItem *) override
HRESULT STDMETHODCALLTYPE ResetTimer() override
HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT) override
HRESULT STDMETHODCALLTYPE PostMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT, IShellItem *) override
HRESULT STDMETHODCALLTYPE PauseTimer() override
HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD dwFlags, IShellItem *) override
HRESULT STDMETHODCALLTYPE PostRenameItem(DWORD, IShellItem *, LPCWSTR, HRESULT, IShellItem *) override
HRESULT STDMETHODCALLTYPE StartOperations() override
HRESULT STDMETHODCALLTYPE ResumeTimer() override
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override
HRESULT STDMETHODCALLTYPE PreNewItem(DWORD, IShellItem *, LPCWSTR) override
ULONG STDMETHODCALLTYPE AddRef() override
HRESULT STDMETHODCALLTYPE PreMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR) override
FileOperationProgressSink()
ULONG STDMETHODCALLTYPE Release() override
\inmodule QtCore \reentrant
FileOwner
\value OwnerUser The user who owns the file.
FileTime
These are used by the fileTime() function.
T fetchAndSubRelaxed(T valueToAdd) noexcept
T fetchAndAddRelaxed(T valueToAdd) noexcept
T loadRelaxed() const noexcept
qsizetype indexOf(char c, qsizetype from=0) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
QByteArray toHex(char separator='\0') const
Returns a hex encoded copy of the byte array.
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
QChar toUpper() const noexcept
Returns the uppercase equivalent if the character is lowercase or titlecase; otherwise returns the ch...
\inmodule QtCore\reentrant
QTime time() const
Returns the time part of the datetime.
QDate date() const
Returns the date part of the datetime.
\inmodule QtCore \reentrant
static QString fromNativeSeparators(const QString &pathName)
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
static QString toNativeSeparators(const QString &pathName)
static QString currentPath()
Returns the absolute path of the application's current directory.
static bool setFileTime(const QFileSystemEntry &entry, const QDateTime &newDate, QAbstractFileEngine::FileTime whatTime, QSystemError &error)
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
static QByteArray id(const QFileSystemEntry &entry)
static bool setCurrentPath(const QFileSystemEntry &entry)
static bool moveFileToTrash(const QFileSystemEntry &source, QFileSystemEntry &newLocation, QSystemError &error)
static QFileSystemEntry getRawLinkPath(const QFileSystemEntry &link, QFileSystemMetaData &data)
static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
static bool renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what)
static QString rootPath()
static bool createDirectory(const QFileSystemEntry &entry, bool createParents, std::optional< QFile::Permissions > permissions=std::nullopt)
static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
static bool setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data=nullptr)
static QString homePath()
static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry)
static QString tempPath()
static bool removeFile(const QFileSystemEntry &entry, QSystemError &error)
static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
static QFileSystemEntry currentPath()
Q_AUTOTEST_EXPORT NativePath nativeFilePath() const
Q_AUTOTEST_EXPORT bool isEmpty() const
Q_AUTOTEST_EXPORT QString path() const
Q_AUTOTEST_EXPORT QString filePath() const
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void append(parameter_type t)
\inmodule QtCore \reentrant
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString right(qsizetype n) const
Returns a substring that contains the n rightmost characters of the string.
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
qsizetype size() const
Returns the number of characters in this string.
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
QString toLower() const &
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
QString & append(QChar c)
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
qsizetype length() const
Returns the number of characters in this string.
\inmodule QtCore \reentrant
static void writeFlags(QTextStream &stream, const Provider &provider)
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
qAreNtfsPermissionChecksEnabled()
[raii]
Q_CORE_EXPORT int qt_ntfs_permission_lookup
[0]
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
#define QT_WARNING_DISABLE_DEPRECATED
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall DBusPendingCall return DBusPendingCall return dbus_int32_t return DBusServer * server
DBusConnection const char DBusError * error
#define Q_CHECK_FILE_NAME(name, result)
static bool createDirectoryWithParents(const QByteArray &nativeName, mode_t mode, bool shouldMkdirFirst=true)
#define FSCTL_GET_REPARSE_POINT
QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED bool qEnableNtfsPermissionChecks() noexcept
static bool toFileTime(const QDateTime &date, FILETIME *fileTime)
static QString readSymLink(const QFileSystemEntry &link)
static bool tryFindFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data)
bool qDisableNtfsPermissionChecks() noexcept
static bool rmDir(const QString &path)
static QByteArray fileId(HANDLE handle)
#define INVALID_FILE_ATTRIBUTES
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 QBasicAtomicInt qt_ntfs_permission_lookup_v2
static QDateTime fileTimeToQDateTime(const FILETIME *time)
static bool uncShareExists(const QString &server)
bool qAreNtfsPermissionChecksEnabled() noexcept
[raii]
#define IO_REPARSE_TAG_SYMLINK
static bool getFindData(QString path, WIN32_FIND_DATA &findData)
struct _REPARSE_DATA_BUFFER REPARSE_DATA_BUFFER
struct _REPARSE_DATA_BUFFER * PREPARSE_DATA_BUFFER
#define Q_DECLARE_FLAGS(Flags, Enum)
#define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
constexpr const T & qMax(const T &a, const T &b)
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLsizei GLsizei GLchar * source
GLsizei const GLchar *const * path
GLsizei GLenum GLboolean sink
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
#define QT_IF_DEPRECATED_SINCE(major, minor, whenTrue, whenFalse)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CHECK_PTR(a=new int[80])
QFileInfo info(fileName)
[8]
USHORT SubstituteNameLength
USHORT SubstituteNameOffset
struct _REPARSE_DATA_BUFFER::@22::@26 GenericReparseBuffer
struct _REPARSE_DATA_BUFFER::@22::@24 SymbolicLinkReparseBuffer
struct _REPARSE_DATA_BUFFER::@22::@25 MountPointReparseBuffer