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)
446QNativeFilePermissions::QNativeFilePermissions(std::optional<QFileDevice::Permissions> perms,
457 const auto permissions = *perms;
459 PACL acl =
reinterpret_cast<PACL
>(aclStorage);
461 if (!InitializeAcl(acl,
sizeof(aclStorage), ACL_REVISION))
466 ACCESS_MASK denyMask, allowMask;
469 auto makeMasks = [isDir](NonSpecificPermissions allowPermissions,
470 NonSpecificPermissions denyPermissions,
bool owner) {
471 constexpr ACCESS_MASK AllowRead = FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA;
472 constexpr ACCESS_MASK DenyRead = FILE_READ_DATA | FILE_READ_EA;
474 constexpr ACCESS_MASK AllowWrite =
475 FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA;
476 constexpr ACCESS_MASK DenyWrite = AllowWrite | FILE_DELETE_CHILD;
477 constexpr ACCESS_MASK DenyWriteOwner =
478 FILE_WRITE_DATA | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
480 constexpr ACCESS_MASK AllowExe = FILE_EXECUTE;
481 constexpr ACCESS_MASK DenyExe = AllowExe;
483 constexpr ACCESS_MASK StdRightsOther =
484 STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
485 constexpr ACCESS_MASK StdRightsOwner =
486 STANDARD_RIGHTS_ALL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE;
488 ACCESS_MASK allow = owner ? StdRightsOwner : StdRightsOther;
489 ACCESS_MASK deny = 0;
491 if (denyPermissions & ReadPermission)
494 if (denyPermissions & WritePermission)
495 deny |= owner ? DenyWriteOwner : DenyWrite;
497 if (denyPermissions & ExePermission)
500 if (allowPermissions & ReadPermission)
503 if (allowPermissions & WritePermission)
506 if (allowPermissions & ExePermission)
510 if (owner && allowPermissions == AllPermissions)
511 allow |= FILE_DELETE_CHILD;
514 && (allowPermissions & (WritePermission | ExePermission))
515 == (WritePermission | ExePermission)) {
516 allow |= FILE_DELETE_CHILD;
519 return Masks { deny, allow };
522 auto userPermissions = toNonSpecificPermissions(OwnerTag, permissions)
523 | toNonSpecificPermissions(UserTag, permissions);
524 auto groupPermissions = toNonSpecificPermissions(GroupTag, permissions);
525 auto otherPermissions = toNonSpecificPermissions(OtherTag, permissions);
527 auto userMasks = makeMasks(userPermissions,
528 ~userPermissions & (groupPermissions | otherPermissions),
true);
529 auto groupMasks = makeMasks(groupPermissions, ~groupPermissions & otherPermissions,
false);
530 auto otherMasks = makeMasks(otherPermissions, {},
false);
532 const DWORD aceFlags = isDir ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0;
533 const bool reorderGroupDeny = (groupMasks.denyMask & userMasks.allowMask) == 0;
535 const auto addDenyAce = [acl, aceFlags](
const Masks &masks, PSID pSID) {
537 return AddAccessDeniedAceEx(acl, ACL_REVISION, aceFlags, masks.denyMask, pSID);
541 const auto addAllowAce = [acl, aceFlags](
const Masks &masks, PSID pSID) {
543 return AddAccessAllowedAceEx(acl, ACL_REVISION, aceFlags, masks.allowMask, pSID);
547 if (!addDenyAce(userMasks, currentUserSID))
550 if (reorderGroupDeny) {
551 if (!addDenyAce(groupMasks, currentGroupSID))
555 if (!addAllowAce(userMasks, currentUserSID))
558 if (!reorderGroupDeny) {
559 if (!addDenyAce(groupMasks, currentGroupSID))
563 if (!addAllowAce(groupMasks, currentGroupSID))
566 if (!addAllowAce(otherMasks, worldSID))
569 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
572 if (!SetSecurityDescriptorOwner(&sd, currentUserSID, FALSE))
575 if (!SetSecurityDescriptorGroup(&sd, currentGroupSID, FALSE))
578 if (!SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
581 sa.nLength =
sizeof(sa);
582 sa.lpSecurityDescriptor = &sd;
583 sa.bInheritHandle = FALSE;
601SECURITY_ATTRIBUTES *QNativeFilePermissions::securityAttributes()
615 lTime.wYear =
d.
year();
616 lTime.wMonth =
d.month();
617 lTime.wDay =
d.day();
618 lTime.wHour =
t.hour();
619 lTime.wMinute =
t.minute();
620 lTime.wSecond =
t.second();
621 lTime.wMilliseconds =
t.msec();
622 lTime.wDayOfWeek =
d.dayOfWeek() % 7;
624 if (!::TzSpecificLocalTimeToSystemTime(
nullptr, &lTime, &sTime))
628 const QDate d = utcDate.date();
629 const QTime t = utcDate.time();
631 sTime.wYear =
d.year();
632 sTime.wMonth =
d.month();
633 sTime.wDay =
d.day();
634 sTime.wHour =
t.
hour();
635 sTime.wMinute =
t.minute();
636 sTime.wSecond =
t.second();
637 sTime.wMilliseconds =
t.msec();
638 sTime.wDayOfWeek =
d.dayOfWeek() % 7;
641 return ::SystemTimeToFileTime(&sTime, fileTime);
648 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
650 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
nullptr);
651 if (
handle != INVALID_HANDLE_VALUE) {
658 if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
659 int length = rdb->MountPointReparseBuffer.SubstituteNameLength /
sizeof(wchar_t);
660 int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset /
sizeof(wchar_t);
661 const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[
offset];
664 int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength /
sizeof(wchar_t);
665 int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset /
sizeof(wchar_t);
666 const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[
offset];
670 result = QFileSystemEntry::removeUncOrLongPathPrefix(
result);
675#if QT_CONFIG(fslibs) && QT_CONFIG(regularexpression)
679 auto matchVolume = matchVolumeRe.match(
result);
680 if (matchVolume.hasMatch()) {
681 Q_ASSERT(matchVolume.capturedStart() == 0);
684 const QString volumeName =
"\\\\?\\"_L1 + matchVolume.captured();
685 if (GetVolumePathNamesForVolumeName(
reinterpret_cast<LPCWSTR
>(volumeName.utf16()),
705 QComHelper comHelper;
708 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
711 if (SUCCEEDED(hres)) {
713 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
714 if (SUCCEEDED(hres)) {
715 hres = ppf->Load((LPOLESTR)link.
nativeFilePath().utf16(), STGM_READ);
718 if (SUCCEEDED(hres)) {
719 if (psl->GetPath(szGotPath,
MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
738 if (parts.count() >= 3) {
740 if (QFileSystemEngine::uncListSharesOnServer(
"\\\\"_L1 + parts.at(2), &shares))
741 return parts.count() < 4
750 while (
path.endsWith(u
'\\'))
754 if (!
path.endsWith(u
':')) {
755 HANDLE hFind = ::FindFirstFile((
wchar_t*)
path.utf16(), &findData);
756 if (hFind != INVALID_HANDLE_VALUE) {
773 ULONG STDMETHODCALLTYPE
AddRef()
override {
return ++
ref; }
787 *ppvObject =
nullptr;
789 if (iid == __uuidof(IUnknown)) {
790 *ppvObject =
static_cast<IUnknown*
>(
this);
791 }
else if (iid == __uuidof(IFileOperationProgressSink)) {
792 *ppvObject =
static_cast<IFileOperationProgressSink*
>(
this);
800 return E_NOINTERFACE;
807 IShellItem *)
override
812 IShellItem *)
override
817 IShellItem *)
override
822 return (dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE) ? S_OK : E_FAIL;
826 IShellItem *psiNewlyCreated)
override
828 deleteResult = hrDelete;
829 if (psiNewlyCreated) {
830 wchar_t *pszName =
nullptr;
831 psiNewlyCreated->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
834 CoTaskMemFree(pszName);
841 IShellItem *)
override
856 DWORD
res = ERROR_NOT_SUPPORTED;
857 SHARE_INFO_1 *BufPtr, *
p;
860 res = NetShareEnum((
wchar_t *)
server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &
tr,
862 if (
res == ERROR_SUCCESS ||
res == ERROR_MORE_DATA) {
864 for (
i = 1;
i <= er; ++
i) {
865 if (
list &&
p->shi1_type == 0)
870 NetApiBufferFree(BufPtr);
871 }
while (
res == ERROR_MORE_DATA);
872 return res == ERROR_SUCCESS;
878 data.fileAttribute_ = 0;
879 data.birthTime_ = FILETIME();
880 data.changeTime_ = FILETIME();
881 data.lastAccessTime_ = FILETIME();
882 data.lastWriteTime_ = FILETIME();
890 if (!
ret.isEmpty() &&
ret.isRelative()) {
907 if (
data.isLnkFile())
909 else if (
data.isLink())
924 if (
data.isJunction())
927 if (!
target.isEmpty() &&
ret.isRelative()) {
928 target.prepend(absoluteName(link).
path() + u
'/');
958 DWORD retLen = GetFullPathName((
wchar_t*)
path.utf16(),
buf.size(),
buf.data(), &
fileName);
959 if (retLen > (DWORD)
buf.size()) {
971 if (!
path.isEmpty() &&
path.at(
path.size() - 1) == u
' ')
972 absPath.append(u
' ');
983 if (!
entry.isRelative()) {
996 if (
ret.at(0) != u
'/') {
1002 ret[0] =
ret.at(0).toUpper();
1010 BY_HANDLE_FILE_INFORMATION
info;
1011 if (GetFileInformationByHandle(
handle, &
info)) {
1012 char buffer[
sizeof "01234567:0123456701234567"];
1014 info.dwVolumeSerialNumber,
1015 info.nFileIndexHigh,
1016 info.nFileIndexLow);
1025#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))) {
1036 int(
sizeof(infoEx.FileId)))
1055 const HANDLE handle = CreateFile((
wchar_t *)
entry.nativeFilePath().utf16(), 0, FILE_SHARE_READ,
1056 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
1057 if (
handle != INVALID_HANDLE_VALUE) {
1075 FILETIME *pLastWrite =
nullptr;
1076 FILETIME *pLastAccess =
nullptr;
1077 FILETIME *pCreationTime =
nullptr;
1081 pLastWrite = &fTime;
1085 pLastAccess = &fTime;
1089 pCreationTime = &fTime;
1100 if (!::SetFileTime(fHandle, pCreationTime, pLastAccess, pLastWrite)) {
1110#if QT_CONFIG(fslibs)
1115 PSECURITY_DESCRIPTOR pSD;
1116 if (GetNamedSecurityInfo(
1117 reinterpret_cast<const wchar_t *
>(
entry.nativeFilePath().utf16()),
1120 : OWNER_SECURITY_INFORMATION,
1127 QVarLengthArray<wchar_t, 64> owner(lowner);
1128 QVarLengthArray<wchar_t, 64> domain(ldomain);
1129 SID_NAME_USE use = SidTypeUnknown;
1131 if (!LookupAccountSid(
nullptr, pOwner, (LPWSTR)owner.data(), &lowner, domain.data(),
1133 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1134 if (lowner > (DWORD)owner.size())
1135 owner.resize(lowner);
1136 if (ldomain > (DWORD)domain.size())
1137 domain.resize(ldomain);
1139 if (!LookupAccountSid(
nullptr, pOwner, owner.data(), &lowner, domain.data(),
1162 QFileSystemMetaData::MetaDataFlags what)
1164#if QT_CONFIG(fslibs)
1172 PSECURITY_DESCRIPTOR pSD;
1177 DWORD
res = GetNamedSecurityInfo(
1178 reinterpret_cast<const wchar_t *
>(fname.utf16()), SE_FILE_OBJECT,
1179 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1180 &pOwner, &pGroup, &pDacl,
nullptr, &pSD);
1181 if (
res == ERROR_SUCCESS) {
1182 QAuthzResourceManager rm;
1184 auto addPermissions = [&
data](ACCESS_MASK accessMask,
1193 if (accessMask & (GENERIC_READ | FILE_READ_DATA))
1194 data.entryFlags |= readFlags;
1195 if (accessMask & (GENERIC_WRITE | FILE_WRITE_DATA))
1197 if (accessMask & (GENERIC_EXECUTE | FILE_EXECUTE))
1198 data.entryFlags |= executeFlags;
1203 QAuthzClientContext
context(rm, currentUserImpersonatedToken,
1204 QAuthzClientContext::TokenTag {});
1205 addPermissions(
context.accessMask(pSD),
1213 QAuthzClientContext
context(rm, pOwner);
1214 addPermissions(
context.accessMask(pSD),
1222 QAuthzClientContext
context(rm, pGroup);
1223 addPermissions(
context.accessMask(pSD),
1231 QAuthzClientContext
context(rm, worldSID);
1232 addPermissions(
context.accessMask(pSD),
1250 if (!(
data.fileAttribute_ & FILE_ATTRIBUTE_READONLY)) {
1258 if (
data.isDirectory() || ext ==
".exe"_L1 || ext ==
".com"_L1
1259 || ext ==
".bat"_L1 || ext ==
".pif"_L1 || ext ==
".cmd"_L1) {
1270 if (::_waccess((
wchar_t*)
entry.nativeFilePath().utf16(), R_OK) == 0)
1275 if (::_waccess((
wchar_t*)
entry.nativeFilePath().utf16(), W_OK) == 0)
1281 return data.hasFlags(what);
1286 bool entryExists =
false;
1287 DWORD fileAttrib = 0;
1288 if (fname.isDriveRoot()) {
1290 const UINT oldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1291 DWORD drivesBitmask = ::GetLogicalDrives();
1292 ::SetErrorMode(oldErrorMode);
1294 1 << (fname.filePath().at(0).toUpper().unicode() - u
'A');
1295 if (drivesBitmask & drivebit) {
1296 fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM;
1301 bool is_dir =
false;
1302 if (
path.startsWith(
"\\\\?\\UNC"_L1)) {
1310 if (
s ==
path.size() - 1) {
1327 fileAttrib = FILE_ATTRIBUTE_DIRECTORY;
1332 data.fillFromFileAttribute(fileAttrib);
1338 bool filledData =
false;
1340 int errorCode = GetLastError();
1341 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1342 WIN32_FIND_DATA findData;
1345 data.fillFromFindData(findData,
true, fname.isDriveRoot());
1354 QFileSystemMetaData::MetaDataFlags what)
1356 auto fHandle =
reinterpret_cast<HANDLE>(_get_osfhandle(
fd));
1357 if (fHandle != INVALID_HANDLE_VALUE) {
1358 return fillMetaData(fHandle,
data, what);
1365 QFileSystemMetaData::MetaDataFlags what)
1367 data.entryFlags &= ~what;
1368 clearWinStatData(
data);
1369 BY_HANDLE_FILE_INFORMATION fileInfo;
1370 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1371 if (GetFileInformationByHandle(fHandle , &fileInfo)) {
1372 data.fillFromFindInfo(fileInfo);
1374 SetErrorMode(oldmode);
1375 return data.hasFlags(what);
1380 QFileSystemMetaData::MetaDataFlags what)
1384 data.entryFlags &= ~what;
1391 if (origFilePath.endsWith(
".lnk"_L1) && !isDirPath(origFilePath,
nullptr)) {
1398 if (fname.isEmpty()) {
1399 data.knownFlagsMask |= what;
1400 clearWinStatData(
data);
1404 if (what & QFileSystemMetaData::WinStatFlags) {
1405 UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1406 clearWinStatData(
data);
1407 WIN32_FIND_DATA findData;
1410 bool ok = ::GetFileAttributesEx(
1411 reinterpret_cast<const wchar_t *
>(fname.nativeFilePath().utf16()),
1412 GetFileExInfoStandard,
reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *
>(&findData));
1414 data.fillFromFindData(findData,
false, fname.isDriveRoot());
1416 const DWORD lastError = GetLastError();
1418 if (lastError == ERROR_LOGON_FAILURE || lastError == ERROR_BAD_NETPATH
1421 SetErrorMode(oldmode);
1425 SetErrorMode(oldmode);
1429 fillPermissions(fname,
data, what);
1432 if (
data.fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
1433 WIN32_FIND_DATA findData;
1434 if (
getFindData(fname.nativeFilePath(), findData))
1435 data.fillFromFindData(findData,
true);
1438 data.knownFlagsMask |= what;
1439 return data.hasFlags(what);
1443 DWORD *lastError =
nullptr)
1447 const QString longPath = QFSFileEnginePrivate::longFileName(
path);
1448 const bool result = ::CreateDirectory((
wchar_t *)longPath.utf16(), securityAttributes);
1451 *lastError = GetLastError();
1457 return ::RemoveDirectory((
wchar_t*)QFSFileEnginePrivate::longFileName(
path).utf16());
1461bool QFileSystemEngine::isDirPath(
const QString &dirPath,
bool *existed)
1464 if (
path.length() == 2 &&
path.at(1) == u
':')
1467 const QString longPath = QFSFileEnginePrivate::longFileName(
path);
1468 DWORD fileAttrib = ::GetFileAttributes(
reinterpret_cast<const wchar_t*
>(longPath.utf16()));
1470 int errorCode = GetLastError();
1471 if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
1472 WIN32_FIND_DATA findData;
1474 fileAttrib = findData.dwFileAttributes;
1484 return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
1490 SECURITY_ATTRIBUTES *securityAttributes,
1491 bool shouldMkdirFirst =
true)
1493 const auto isUNCRoot = [](
const QString &nativeName) {
1494 return nativeName.startsWith(
"\\\\"_L1)
1497 const auto isDriveName = [](
const QString &nativeName) {
1498 return nativeName.size() == 2 && nativeName.at(1) == u
':';
1500 const auto isDir = [](
const QString &nativeName) {
1501 bool exists =
false;
1502 return QFileSystemEngine::isDirPath(nativeName, &exists) && exists;
1505 if (isUNCRoot(nativeName) || isDriveName(nativeName))
1508 if (shouldMkdirFirst) {
1509 if (
mkDir(nativeName, securityAttributes))
1517 const QString parentNativeName = nativeName.
left(backSlash);
1522 if (
mkDir(nativeName, securityAttributes))
1524 return isDir(nativeName);
1529 std::optional<QFile::Permissions> permissions)
1537 if (!nativePermissions.isOk())
1540 auto securityAttributes = nativePermissions.securityAttributes();
1544 if (
mkDir(dirName, securityAttributes, &lastError))
1549 if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED)
1550 return isDirPath(dirName,
nullptr);
1561 if (removeEmptyParents) {
1563 for (
int oldslash = 0, slash=dirName.
length(); slash > 0; oldslash = slash) {
1565 if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
1566 && chunkRef.at(1) == u
':') {
1569 const QString chunk = chunkRef.toString();
1570 if (!isDirPath(chunk,
nullptr))
1573 return oldslash != 0;
1595#if QT_CONFIG(fslibs)
1598 HANDLE hnd = ::GetCurrentProcess();
1600 BOOL
ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &
token);
1602 DWORD dwBufferSize = 0;
1604 ok = GetUserProfileDirectory(
token,
nullptr, &dwBufferSize);
1605 if (!
ok && dwBufferSize != 0) {
1606 wchar_t *userDirectory =
new wchar_t[dwBufferSize];
1608 ok = GetUserProfileDirectory(
token, userDirectory, &dwBufferSize);
1611 delete [] userDirectory;
1613 ::CloseHandle(
token);
1636 const DWORD
len = GetTempPath(
MAX_PATH, tempPath);
1639 const DWORD longLen = GetLongPathName(tempPath, longTempPath,
MAX_PATH);
1644 if (!
ret.isEmpty()) {
1645 while (
ret.endsWith(u
'\\'))
1649 if (
ret.isEmpty()) {
1651 }
else if (
ret.length() >= 2 &&
ret[1] == u
':')
1652 ret[0] =
ret.at(0).toUpper();
1659 fillMetaData(
entry, meta,
1667 return ::SetCurrentDirectory(
reinterpret_cast<const wchar_t *
>(
1675 DWORD
size = GetCurrentDirectoryW(
PATH_MAX,
reinterpret_cast<wchar_t *
>(
ret.data()));
1679 size = GetCurrentDirectoryW(
size,
reinterpret_cast<wchar_t *
>(
ret.data()));
1684 if (
size >= 2 &&
ret.at(1) == u
':')
1685 ret[0] =
ret.at(0).toUpper();
1695 QComHelper comHelper;
1696 IShellLink *psl =
nullptr;
1697 HRESULT hres = CoCreateInstance(CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
1698 reinterpret_cast<void **
>(&psl));
1700 if (SUCCEEDED(hres)) {
1703 if (SUCCEEDED(psl->SetPath(
reinterpret_cast<const wchar_t *
>(
name.utf16())))
1704 && SUCCEEDED(psl->SetWorkingDirectory(
1705 reinterpret_cast<const wchar_t *
>(pathName.utf16())))) {
1706 IPersistFile *ppf =
nullptr;
1707 if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<void **
>(&ppf)))) {
1708 ret = SUCCEEDED(ppf->Save(
1709 reinterpret_cast<const wchar_t *
>(
target.filePath().utf16()), TRUE));
1726 bool ret = ::CopyFile((
wchar_t*)
source.nativeFilePath().utf16(),
1727 (
wchar_t*)
target.nativeFilePath().utf16(),
true) != 0;
1740 bool ret = ::MoveFile((
wchar_t*)
source.nativeFilePath().utf16(),
1741 (
wchar_t*)
target.nativeFilePath().utf16()) != 0;
1754 bool ret = ::MoveFileEx(
reinterpret_cast<const wchar_t *
>(
source.nativeFilePath().utf16()),
1755 reinterpret_cast<const wchar_t *
>(
target.nativeFilePath().utf16()),
1756 MOVEFILE_REPLACE_EXISTING) != 0;
1767 bool ret = ::DeleteFile((
wchar_t*)
entry.nativeFilePath().utf16()) != 0;
1786 QComHelper comHelper;
1788 IFileOperation *pfo =
nullptr;
1789 IShellItem *deleteItem =
nullptr;
1797 deleteItem->Release();
1800 if (!SUCCEEDED(hres))
1804 hres = CoCreateInstance(CLSID_FileOperation,
nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
1807 pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
1808 | FOF_SILENT | FOF_NOERRORUI);
1809 hres = SHCreateItemFromParsingName(
reinterpret_cast<const wchar_t*
>(sourcePath.
utf16()),
1810 nullptr, IID_PPV_ARGS(&deleteItem));
1814 hres = pfo->DeleteItem(deleteItem,
static_cast<IFileOperationProgressSink*
>(
sink));
1815 if (!SUCCEEDED(hres))
1817 hres = pfo->PerformOperations();
1818 if (!SUCCEEDED(hres))
1821 if (!SUCCEEDED(
sink->deleteResult)) {
1850 ::_wchmod(
reinterpret_cast<const wchar_t *
>(
entry.nativeFilePath().utf16()),
mode) == 0;
1858 if (
time->dwHighDateTime == 0 &&
time->dwLowDateTime == 0)
1862 FileTimeToSystemTime(
time, &sTime);
1864 QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
HRESULT STDMETHODCALLTYPE PreRenameItem(DWORD, IShellItem *, LPCWSTR) 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 PostDeleteItem(DWORD, IShellItem *, HRESULT hrDelete, IShellItem *psiNewlyCreated) 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.
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
\inmodule QtCore\reentrant
\inmodule QtCore \reentrant
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
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 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 setFileTime(const QFileSystemEntry &entry, const QDateTime &newDate, QFile::FileTime whatTime, QSystemError &error)
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
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
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString left(qsizetype n) const &
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString & replace(qsizetype i, qsizetype len, QChar after)
void chop(qsizetype n)
Removes n characters from the end of the string.
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...
QString right(qsizetype n) const &
QString toLower() const &
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
qsizetype length() const noexcept
Returns the number of characters in this string.
\inmodule QtCore \reentrant
int hour() const
Returns the hour part (0 to 23) of the time.
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]
qEnableNtfsPermissionChecks()
qDisableNtfsPermissionChecks()
#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
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define Q_CHECK_FILE_NAME(name, result)
static bool createDirectoryWithParents(const QByteArray &nativeName, mode_t mode, bool shouldMkdirFirst=true)
#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 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 QBasicAtomicInt qt_ntfs_permission_lookup_v2
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)
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
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLenum GLsizei const GLchar * buf
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])
USHORT SubstituteNameLength
struct _REPARSE_DATA_BUFFER::@19::@21 SymbolicLinkReparseBuffer
USHORT SubstituteNameOffset
struct _REPARSE_DATA_BUFFER::@19::@22 MountPointReparseBuffer
struct _REPARSE_DATA_BUFFER::@19::@23 GenericReparseBuffer