summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfsfileengine_win.cpp
blob: c436d4cd26b8b855e33ecdbbf0473166718be76e (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
// Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qplatformdefs.h"#include"private/qabstractfileengine_p.h"#include"private/qfiledevice_p.h"#include"private/qfsfileengine_p.h"#include"qfilesystemengine_p.h"#include <qdebug.h>#include"qfile.h"#include"qdir.h"#include"qvarlengtharray.h"#include"qdatetime.h"#include"qt_windows.h"#include <sys/types.h>#include <direct.h>#include <winioctl.h>#include <objbase.h>#include <shlobj.h>#include <accctrl.h>#include <initguid.h>#include <ctype.h>#include <limits.h>#include <stdio.h>#define SECURITY_WIN32#include <security.h>#include <memory>#ifndef PATH_MAX#define PATH_MAX FILENAME_MAX#endif QT_BEGIN_NAMESPACE using namespaceQt::StringLiterals;staticinlineboolisUncPath(const QString &path){// Starts with \\, but not \\.return(path.startsWith("\\\\"_L1)&& path.size() >2&& path.at(2) != u'.');}/*! \internal*/ QString QFSFileEnginePrivate::longFileName(const QString &path){if(path.startsWith("\\\\.\\"_L1))return path; QString absPath =QFileSystemEngine::nativeAbsoluteFilePath(path); QString prefix ="\\\\?\\"_L1;if(isUncPath(absPath)) { prefix.append("UNC\\"_L1);// "\\\\?\\UNC\\" absPath.remove(0,2);}return prefix + absPath;}/* \internal*/boolQFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode,std::optional<QFile::Permissions> permissions){Q_Q(QFSFileEngine);// All files are opened in share mode (both read and write). DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;int accessRights =0;if(openMode &QIODevice::ReadOnly) accessRights |= GENERIC_READ;if(openMode &QIODevice::WriteOnly) accessRights |= GENERIC_WRITE;// WriteOnly can create files, ReadOnly cannot. DWORD creationDisp = (openMode &QIODevice::NewOnly)? CREATE_NEW :openModeCanCreate(openMode)? OPEN_ALWAYS : OPEN_EXISTING;// Create the file handle. QNativeFilePermissions nativePermissions(permissions,false);if(!nativePermissions.isOk())return false; fileHandle =CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(), accessRights, shareMode, nativePermissions.securityAttributes(), creationDisp, FILE_ATTRIBUTE_NORMAL, NULL);// Bail out on error.if(fileHandle == INVALID_HANDLE_VALUE) { q->setError(QFile::OpenError,qt_error_string());return false;}// Truncate the file after successfully opening it if Truncate is passed.if(openMode &QIODevice::Truncate) q->setSize(0);return true;}/* \internal*/boolQFSFileEnginePrivate::nativeClose(){Q_Q(QFSFileEngine);if(fh || fd != -1) {// stdlib / stdio mode.returncloseFdFh();}// Windows native mode.bool ok =true;if(cachedFd != -1) {if(::_close(cachedFd) && !::CloseHandle(fileHandle)) { q->setError(QFile::UnspecifiedError,qt_error_string()); ok =false;}// System handle is closed with associated file descriptor. fileHandle = INVALID_HANDLE_VALUE; cachedFd = -1;return ok;}if((fileHandle == INVALID_HANDLE_VALUE || !::CloseHandle(fileHandle))) { q->setError(QFile::UnspecifiedError,qt_error_string()); ok =false;} fileHandle = INVALID_HANDLE_VALUE;return ok;}/* \internal*/boolQFSFileEnginePrivate::nativeFlush(){if(fh) {// Buffered stdlib mode.returnflushFh();}if(fd != -1) {// Unbuffered stdio mode; always succeeds (no buffer).return true;}// Windows native mode; flushing is unnecessary.return true;}/* \internal \since 5.1*/boolQFSFileEnginePrivate::nativeSyncToDisk(){if(fh || fd != -1) {// stdlib / stdio mode. No API available.return false;}returnFlushFileBuffers(fileHandle);}/* \internal*/ qint64 QFSFileEnginePrivate::nativeSize()const{Q_Q(const QFSFileEngine); QFSFileEngine *thatQ =const_cast<QFSFileEngine *>(q);// ### Don't flush; for buffered files, we should get away with ftell. thatQ->flush();// Always retrieve the current information metaData.clearFlags(QFileSystemMetaData::SizeAttribute);bool filled =false;if(fileHandle != INVALID_HANDLE_VALUE && openMode !=QIODevice::NotOpen ) filled =QFileSystemEngine::fillMetaData(fileHandle, metaData,QFileSystemMetaData::SizeAttribute);else filled =doStat(QFileSystemMetaData::SizeAttribute);if(!filled) { thatQ->setError(QFile::UnspecifiedError,QSystemError::stdString());return0;}return metaData.size();}/* \internal*/ qint64 QFSFileEnginePrivate::nativePos()const{Q_Q(const QFSFileEngine); QFSFileEngine *thatQ =const_cast<QFSFileEngine *>(q);if(fh || fd != -1) {// stdlib / stido mode.returnposFdFh();}// Windows native mode.if(fileHandle == INVALID_HANDLE_VALUE)return0; LARGE_INTEGER currentFilePos; LARGE_INTEGER offset; offset.QuadPart =0;if(!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_CURRENT)) { thatQ->setError(QFile::UnspecifiedError,qt_error_string());return0;}returnqint64(currentFilePos.QuadPart);}/* \internal*/boolQFSFileEnginePrivate::nativeSeek(qint64 pos){Q_Q(QFSFileEngine);if(fh || fd != -1) {// stdlib / stdio mode.returnseekFdFh(pos);} LARGE_INTEGER currentFilePos; LARGE_INTEGER offset; offset.QuadPart = pos;if(!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_BEGIN)) { q->setError(QFile::UnspecifiedError,qt_error_string());return false;}return true;}/* \internal*/ qint64 QFSFileEnginePrivate::nativeRead(char*data, qint64 maxlen){Q_Q(QFSFileEngine);if(fh || fd != -1) {// stdio / stdlib mode.if(fh &&nativeIsSequential() &&feof(fh)) { q->setError(QFile::ReadError,QSystemError::stdString());return-1;}returnreadFdFh(data, maxlen);}// Windows native mode.if(fileHandle == INVALID_HANDLE_VALUE)return-1; qint64 bytesToRead = maxlen;// Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when// the chunks are too large, so we limit the block size to 32MB.static const qint64 maxBlockSize =32*1024*1024; qint64 totalRead =0;do{ DWORD blockSize =DWORD(qMin(bytesToRead, maxBlockSize)); DWORD bytesRead;if(!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) {if(totalRead ==0) {// Note: only return failure if the first ReadFile fails. q->setError(QFile::ReadError,qt_error_string());return-1;}break;}if(bytesRead ==0)break; totalRead += bytesRead; bytesToRead -= bytesRead;}while(totalRead < maxlen);return totalRead;}/* \internal*/ qint64 QFSFileEnginePrivate::nativeReadLine(char*data, qint64 maxlen){Q_Q(QFSFileEngine);if(fh || fd != -1) {// stdio / stdlib mode.returnreadLineFdFh(data, maxlen);}// Windows native mode.if(fileHandle == INVALID_HANDLE_VALUE)return-1;// ### No equivalent in Win32?return q->QAbstractFileEngine::readLine(data, maxlen);}/* \internal*/ qint64 QFSFileEnginePrivate::nativeWrite(const char*data, qint64 len){Q_Q(QFSFileEngine);if(fh || fd != -1) {// stdio / stdlib mode.returnwriteFdFh(data, len);}// Windows native mode.if(fileHandle == INVALID_HANDLE_VALUE)return-1; qint64 bytesToWrite = len;// Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when// the chunks are too large, so we limit the block size to 32MB. qint64 totalWritten =0;do{const DWORD currentBlockSize =DWORD(qMin(bytesToWrite,qint64(32*1024*1024))); DWORD bytesWritten;if(!WriteFile(fileHandle, data + totalWritten, currentBlockSize, &bytesWritten, NULL)) {if(totalWritten ==0) {// Note: Only return error if the first WriteFile failed. q->setError(QFile::WriteError,qt_error_string());return-1;}break;}if(bytesWritten ==0)break; totalWritten += bytesWritten; bytesToWrite -= bytesWritten;}while(totalWritten < len);returnqint64(totalWritten);}/* \internal*/intQFSFileEnginePrivate::nativeHandle()const{if(fh || fd != -1)return fh ?QT_FILENO(fh) : fd;if(cachedFd != -1)return cachedFd;int flags =0;if(openMode &QIODevice::Append) flags |= _O_APPEND;if(!(openMode &QIODevice::WriteOnly)) flags |= _O_RDONLY; cachedFd =_open_osfhandle((intptr_t) fileHandle, flags);return cachedFd;}/* \internal*/boolQFSFileEnginePrivate::nativeIsSequential()const{ HANDLE handle = fileHandle;if(fh || fd != -1) handle = (HANDLE)_get_osfhandle(fh ?QT_FILENO(fh) : fd);if(handle == INVALID_HANDLE_VALUE)return false; DWORD fileType =GetFileType(handle);return(fileType == FILE_TYPE_CHAR)|| (fileType == FILE_TYPE_PIPE);}boolQFSFileEnginePrivate::nativeRenameOverwrite(const QFileSystemEntry &newEntry){if(fileHandle == INVALID_HANDLE_VALUE)return false;const QString newFilePath = newEntry.nativeFilePath();const size_t nameByteLength = newFilePath.length() *sizeof(wchar_t);if(nameByteLength +sizeof(wchar_t) >std::numeric_limits<DWORD>::max())return false;constexprsize_t RenameInfoSize =sizeof(FILE_RENAME_INFO);const size_t renameDataSize = RenameInfoSize + nameByteLength +sizeof(wchar_t); QVarLengthArray<char>v(qsizetype(renameDataSize),0);auto*renameInfo =q20::construct_at(reinterpret_cast<FILE_RENAME_INFO *>(v.data()));auto renameInfoRAII =qScopeGuard([&] {std::destroy_at(renameInfo); }); renameInfo->ReplaceIfExists = TRUE; renameInfo->RootDirectory =nullptr; renameInfo->FileNameLength =DWORD(nameByteLength);memcpy(renameInfo->FileName, newFilePath.data(), nameByteLength);bool res =SetFileInformationByHandle(fileHandle, FileRenameInfo, renameInfo,DWORD(renameDataSize));if(!res) { DWORD error =GetLastError();q_func()->setError(QFile::RenameError,qt_error_string(int(error)));}return res;} QString QFSFileEngine::currentPath(const QString &fileName){ QString ret;//if filename is a drive: then get the pwd of that driveif(fileName.length() >=2&& fileName.at(0).isLetter() && fileName.at(1) == u':') {int drv = fileName.toUpper().at(0).toLatin1() -'A'+1;if(_getdrive() != drv) {wchar_t buf[PATH_MAX];::_wgetdcwd(drv, buf, PATH_MAX); ret =QString::fromWCharArray(buf);}}if(ret.isEmpty()) {//just the pwd ret =QFileSystemEngine::currentPath().filePath();}if(ret.length() >=2&& ret[1] == u':') ret[0] = ret.at(0).toUpper();// Force uppercase drive letters.return ret;}// cf QStorageInfo::isReadystaticinlineboolisDriveReady(const wchar_t*path){ DWORD fileSystemFlags;const UINT driveType =GetDriveType(path);return(driveType != DRIVE_REMOVABLE && driveType != DRIVE_CDROM)||GetVolumeInformation(path,nullptr,0,nullptr,nullptr,&fileSystemFlags,nullptr,0) == TRUE;} QFileInfoList QFSFileEngine::drives(){ QFileInfoList ret;const UINT oldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); quint32 driveBits = (quint32)GetLogicalDrives() &0x3ffffff;wchar_t driveName[] = L"A:\\";while(driveBits) {if((driveBits &1) &&isDriveReady(driveName)) ret.append(QFileInfo(QString::fromWCharArray(driveName))); driveName[0]++; driveBits = driveBits >>1;}::SetErrorMode(oldErrorMode);return ret;}boolQFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags)const{if(!tried_stat || !metaData.hasFlags(flags)) { tried_stat =true;int localFd = fd;if(fh && fileEntry.isEmpty()) localFd =QT_FILENO(fh);if(localFd != -1)QFileSystemEngine::fillMetaData(localFd, metaData, flags);if(metaData.missingFlags(flags) && !fileEntry.isEmpty())QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));}return metaData.exists();}// ### assume that they add .lnk to newNameboolQFSFileEngine::link(const QString &newName){ QSystemError error;bool ret =QFileSystemEngine::createLink(QFileSystemEntry(fileName(AbsoluteName)),QFileSystemEntry(newName), error);if(!ret)setError(QFile::RenameError, error.toString());return ret;}/*! \reimp*/QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type)const{Q_D(const QFSFileEngine);if(type & Refresh) d->metaData.clear();QAbstractFileEngine::FileFlags ret;if(type & FlagsMask) ret |= LocalDiskFlag;bool exists;{QFileSystemMetaData::MetaDataFlags queryFlags; queryFlags |=QFileSystemMetaData::MetaDataFlags::fromInt(type.toInt())&QFileSystemMetaData::Permissions;// AliasType and BundleType are 0x0if(type & TypesMask) queryFlags |=QFileSystemMetaData::AliasType |QFileSystemMetaData::LinkType |QFileSystemMetaData::FileType |QFileSystemMetaData::DirectoryType |QFileSystemMetaData::BundleType;if(type & FlagsMask) queryFlags |=QFileSystemMetaData::HiddenAttribute |QFileSystemMetaData::ExistsAttribute; queryFlags |=QFileSystemMetaData::LinkType; exists = d->doStat(queryFlags);}if(exists && (type & PermsMask)) ret |=FileFlags::fromInt(d->metaData.permissions().toInt());if(type & TypesMask) {if((type & LinkType) && d->metaData.isLegacyLink()) ret |= LinkType;if(d->metaData.isDirectory()) { ret |= DirectoryType;}else{ ret |= FileType;}}if(type & FlagsMask) {if(d->metaData.exists()) {// if we succeeded in querying, then the file exists: a file on// Windows cannot be deleted if we have an open handle to it ret |= ExistsFlag;if(d->fileEntry.isRoot()) ret |= RootFlag;else if(d->metaData.isHidden()) ret |= HiddenFlag;}}return ret;} QByteArray QFSFileEngine::id()const{Q_D(const QFSFileEngine); HANDLE h = d->fileHandle;if(h == INVALID_HANDLE_VALUE) {int localFd = d->fd;if(d->fh && d->fileEntry.isEmpty()) localFd =QT_FILENO(d->fh);if(localFd != -1) h =HANDLE(_get_osfhandle(localFd));}if(h != INVALID_HANDLE_VALUE)returnQFileSystemEngine::id(h);// file is not open, try by pathreturnQFileSystemEngine::id(d->fileEntry);} QString QFSFileEngine::fileName(FileName file)const{Q_D(const QFSFileEngine);switch(file) {case BaseName:return d->fileEntry.fileName();case PathName:return d->fileEntry.path();case AbsoluteName:case AbsolutePathName: { QString ret = d->fileEntry.filePath();if(isRelativePath()) { ret =QDir::cleanPath(QDir::currentPath() + u'/'+ ret);}else if(ret.startsWith(u'/')// absolute path to the current drive, so \a.txt -> Z:\a.txt|| ret.size() ==2// or a drive letter that needs to get a working dir appended// or a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt|| (ret.size() >2&& ret.at(2) != u'/')|| ret.contains(QStringView(u"/../"))|| ret.contains(QStringView(u"/./"))|| ret.endsWith(QStringView(u"/.."))|| ret.endsWith(QStringView(u"/."))) { ret =QDir::fromNativeSeparators(QFileSystemEngine::nativeAbsoluteFilePath(ret));}// The path should be absolute at this point.// From the docs :// Absolute paths begin with the directory separator "/"// (optionally preceded by a drive specification under Windows).if(ret.at(0) != u'/') {Q_ASSERT(ret.length() >=2);Q_ASSERT(ret.at(0).isLetter());Q_ASSERT(ret.at(1) == u':');// Force uppercase drive letters. ret[0] = ret.at(0).toUpper();}if(file == AbsolutePathName) {int slash = ret.lastIndexOf(u'/');if(slash <0)return ret;if(ret.at(0) != u'/'&& slash ==2)return ret.left(3);// include the slashreturn ret.left(slash >0? slash :1);}return ret;}case CanonicalName:case CanonicalPathName: {if(!(fileFlags(ExistsFlag) & ExistsFlag))returnQString();const QFileSystemEntry entry =QFileSystemEngine::canonicalName(QFileSystemEntry(fileName(AbsoluteName)), d->metaData);if(file == CanonicalPathName)return entry.path();return entry.filePath();}case AbsoluteLinkTarget:returnQFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();case RawLinkPath:returnQFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData).filePath();case BundleName:returnQString();case JunctionName:returnQFileSystemEngine::getJunctionTarget(d->fileEntry, d->metaData).filePath();case DefaultName:break;case NFileNames:Q_ASSERT(false);break;}return d->fileEntry.filePath();}boolQFSFileEngine::isRelativePath()const{Q_D(const QFSFileEngine);// drive, e.g. "a:", or UNC root, e.q. "//"return d->fileEntry.isRelative();} uint QFSFileEngine::ownerId(FileOwner /*own*/)const{static const uint nobodyID = (uint) -2;return nobodyID;} QString QFSFileEngine::owner(FileOwner own)const{Q_D(const QFSFileEngine);returnQFileSystemEngine::owner(d->fileEntry, own);}boolQFSFileEngine::setPermissions(uint perms){Q_D(QFSFileEngine); QSystemError error;// clear cached state (if any) d->metaData.clearFlags(QFileSystemMetaData::Permissions);bool ret =QFileSystemEngine::setPermissions(d->fileEntry,QFile::Permissions(perms), error);if(!ret)setError(QFile::PermissionsError, error.toString());return ret;}boolQFSFileEngine::setSize(qint64 size){Q_D(QFSFileEngine);if(d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1|| d->fh) {// resize open file HANDLE fh = d->fileHandle;if(fh == INVALID_HANDLE_VALUE) {if(d->fh) fh = (HANDLE)_get_osfhandle(QT_FILENO(d->fh));else fh = (HANDLE)_get_osfhandle(d->fd);}if(fh == INVALID_HANDLE_VALUE)return false; qint64 currentPos =pos();if(seek(size) &&SetEndOfFile(fh)) {seek(qMin(currentPos, size));return true;}seek(currentPos);return false;}if(!d->fileEntry.isEmpty()) {// resize file on disk QFile file(d->fileEntry.filePath());if(file.open(QFile::ReadWrite)) {bool ret = file.resize(size);if(!ret)setError(QFile::ResizeError, file.errorString());return ret;}}return false;}boolQFSFileEngine::setFileTime(const QDateTime &newDate,QFile::FileTime time){Q_D(QFSFileEngine);if(d->openMode ==QFile::NotOpen) {setError(QFile::PermissionsError,qt_error_string(ERROR_ACCESS_DENIED));return false;}if(!newDate.isValid() || time ==QFile::FileMetadataChangeTime) {setError(QFile::UnspecifiedError,qt_error_string(ERROR_INVALID_PARAMETER));return false;} HANDLE handle = d->fileHandle;if(handle == INVALID_HANDLE_VALUE) {if(d->fh) handle =reinterpret_cast<HANDLE>(::_get_osfhandle(QT_FILENO(d->fh)));else if(d->fd != -1) handle =reinterpret_cast<HANDLE>(::_get_osfhandle(d->fd));}if(handle == INVALID_HANDLE_VALUE) {setError(QFile::PermissionsError,qt_error_string(ERROR_ACCESS_DENIED));return false;} QSystemError error;if(!QFileSystemEngine::setFileTime(handle, newDate, time, error)) {setError(QFile::PermissionsError, error.toString());return false;} d->metaData.clearFlags(QFileSystemMetaData::Times);return true;} uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,QFile::MemoryMapFlags flags){Q_Q(QFSFileEngine);Q_UNUSED(flags);if(openMode ==QFile::NotOpen) { q->setError(QFile::PermissionsError,qt_error_string(ERROR_ACCESS_DENIED));return0;}if(offset ==0&& size ==0) { q->setError(QFile::UnspecifiedError,qt_error_string(ERROR_INVALID_PARAMETER));return0;}// check/setup args to map DWORD access =0;if(flags &QFileDevice::MapPrivateOption) {#ifdef FILE_MAP_COPY access = FILE_MAP_COPY;#else q->setError(QFile::UnspecifiedError,"MapPrivateOption unsupported");return0;#endif}else if(openMode &QIODevice::WriteOnly) { access = FILE_MAP_WRITE;}else if(openMode &QIODevice::ReadOnly) { access = FILE_MAP_READ;}if(mapHandle == NULL) {// get handle to the file HANDLE handle = fileHandle;if(handle == INVALID_HANDLE_VALUE && fh) handle = (HANDLE)::_get_osfhandle(QT_FILENO(fh));#ifdef Q_USE_DEPRECATED_MAP_APInativeClose();// handle automatically closed by kernel with mapHandle (below). handle = ::CreateFileForMapping((const wchar_t*)fileEntry.nativeFilePath().utf16(), GENERIC_READ | (openMode &QIODevice::WriteOnly ? GENERIC_WRITE :0),0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// Since this is a special case, we check if the return value was NULL and if so// we change it to INVALID_HANDLE_VALUE to follow the logic inside this function.if(!handle) handle = INVALID_HANDLE_VALUE;#endifif(handle == INVALID_HANDLE_VALUE) { q->setError(QFile::PermissionsError,qt_error_string(ERROR_ACCESS_DENIED));return0;}// first create the file mapping handle DWORD protection = (openMode &QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY; mapHandle = ::CreateFileMapping(handle,0, protection,0,0,0);if(mapHandle == NULL) { q->setError(QFile::PermissionsError,qt_error_string());#ifdef Q_USE_DEPRECATED_MAP_API::CloseHandle(handle);#endifreturn0;}} DWORD offsetHi = offset >>32; DWORD offsetLo = offset &Q_UINT64_C(0xffffffff); SYSTEM_INFO sysinfo;::GetSystemInfo(&sysinfo); DWORD mask = sysinfo.dwAllocationGranularity -1; DWORD extra = offset & mask;if(extra) offsetLo &= ~mask;// attempt to create the map LPVOID mapAddress = ::MapViewOfFile(mapHandle, access, offsetHi, offsetLo, size + extra);if(mapAddress) { uchar *address = extra +static_cast<uchar*>(mapAddress); maps[address] = extra;return address;}switch(GetLastError()) {case ERROR_ACCESS_DENIED: q->setError(QFile::PermissionsError,qt_error_string());break;case ERROR_INVALID_PARAMETER:// size are out of boundsdefault: q->setError(QFile::UnspecifiedError,qt_error_string());}::CloseHandle(mapHandle); mapHandle = NULL;return0;}boolQFSFileEnginePrivate::unmap(uchar *ptr){Q_Q(QFSFileEngine);constauto it =std::as_const(maps).find(ptr);if(it == maps.cend()) { q->setError(QFile::PermissionsError,qt_error_string(ERROR_ACCESS_DENIED));return false;} uchar *start = ptr - *it;if(!UnmapViewOfFile(start)) { q->setError(QFile::PermissionsError,qt_error_string());return false;} maps.erase(it);if(maps.isEmpty()) {::CloseHandle(mapHandle); mapHandle = NULL;}return true;}/*! \reimp*/QAbstractFileEngine::TriStateResult QFSFileEngine::cloneTo(QAbstractFileEngine *target){// There's some Windows Server 2016 API, but we won't// bother with it.Q_UNUSED(target);returnTriStateResult::NotSupported;} QT_END_NAMESPACE 
close