Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qplatformdefs.h"
41#include "private/qabstractfileengine_p.h"
42#include "private/qfsfileengine_p.h"
43#include "qfilesystemengine_p.h"
44#include <qdebug.h>
45
46#include "qfile.h"
47#include "qdir.h"
48#include "qvarlengtharray.h"
49#include "qdatetime.h"
50#include "qt_windows.h"
51
52#include <sys/types.h>
53#include <direct.h>
54#include <winioctl.h>
55#include <objbase.h>
56#ifndef Q_OS_WINRT
57# include <shlobj.h>
58# include <accctrl.h>
59#endif
60#include <initguid.h>
61#include <ctype.h>
62#include <limits.h>
63#include <stdio.h>
64#ifndef Q_OS_WINRT
65# define SECURITY_WIN32
66# include <security.h>
67#endif
68
69#ifndef PATH_MAX
70#define PATH_MAX FILENAME_MAX
71#endif
72
73QT_BEGIN_NAMESPACE
74
75static inline bool isUncPath(const QString &path)
76{
77 // Starts with \\, but not \\.
78 return (path.startsWith(QLatin1String("\\\\"))
79 && path.size() > 2 && path.at(2) != QLatin1Char('.'));
80}
81
82/*!
83 \internal
84*/
85QString QFSFileEnginePrivate::longFileName(const QString &path)
86{
87 if (path.startsWith(QLatin1String("\\\\.\\")))
88 return path;
89
90 QString absPath = QFileSystemEngine::nativeAbsoluteFilePath(path);
91#if !defined(Q_OS_WINRT)
92 QString prefix = QLatin1String("\\\\?\\");
93 if (isUncPath(absPath)) {
94 prefix.append(QLatin1String("UNC\\")); // "\\\\?\\UNC\\"
95 absPath.remove(0, 2);
96 }
97 return prefix + absPath;
98#else
99 return absPath;
100#endif
101}
102
103/*
104 \internal
105*/
106bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
107{
108 Q_Q(QFSFileEngine);
109
110 // All files are opened in share mode (both read and write).
111 DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
112
113 int accessRights = 0;
114 if (openMode & QIODevice::ReadOnly)
115 accessRights |= GENERIC_READ;
116 if (openMode & QIODevice::WriteOnly)
117 accessRights |= GENERIC_WRITE;
118
119 // WriteOnly can create files, ReadOnly cannot.
120 DWORD creationDisp = (openMode & QIODevice::NewOnly)
121 ? CREATE_NEW
122 : openModeCanCreate(openMode)
123 ? OPEN_ALWAYS
124 : OPEN_EXISTING;
125 // Create the file handle.
126#ifndef Q_OS_WINRT
127 SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
128 fileHandle = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
129 accessRights,
130 shareMode,
131 &securityAtts,
132 creationDisp,
133 FILE_ATTRIBUTE_NORMAL,
134 NULL);
135#else // !Q_OS_WINRT
136 fileHandle = CreateFile2((const wchar_t*)fileEntry.nativeFilePath().utf16(),
137 accessRights,
138 shareMode,
139 creationDisp,
140 NULL);
141#endif // Q_OS_WINRT
142
143 // Bail out on error.
144 if (fileHandle == INVALID_HANDLE_VALUE) {
145 q->setError(QFile::OpenError, qt_error_string());
146 return false;
147 }
148
149 // Truncate the file after successfully opening it if Truncate is passed.
150 if (openMode & QIODevice::Truncate)
151 q->setSize(0);
152
153 return true;
154}
155
156/*
157 \internal
158*/
159bool QFSFileEnginePrivate::nativeClose()
160{
161 Q_Q(QFSFileEngine);
162 if (fh || fd != -1) {
163 // stdlib / stdio mode.
164 return closeFdFh();
165 }
166
167 // Windows native mode.
168 bool ok = true;
169
170 if (cachedFd != -1) {
171 if (::_close(cachedFd) && !::CloseHandle(fileHandle)) {
172 q->setError(QFile::UnspecifiedError, qt_error_string());
173 ok = false;
174 }
175
176 // System handle is closed with associated file descriptor.
177 fileHandle = INVALID_HANDLE_VALUE;
178 cachedFd = -1;
179
180 return ok;
181 }
182
183 if ((fileHandle == INVALID_HANDLE_VALUE || !::CloseHandle(fileHandle))) {
184 q->setError(QFile::UnspecifiedError, qt_error_string());
185 ok = false;
186 }
187 fileHandle = INVALID_HANDLE_VALUE;
188 return ok;
189}
190
191/*
192 \internal
193*/
194bool QFSFileEnginePrivate::nativeFlush()
195{
196 if (fh) {
197 // Buffered stdlib mode.
198 return flushFh();
199 }
200 if (fd != -1) {
201 // Unbuffered stdio mode; always succeeds (no buffer).
202 return true;
203 }
204
205 // Windows native mode; flushing is unnecessary.
206 return true;
207}
208
209/*
210 \internal
211 \since 5.1
212*/
213bool QFSFileEnginePrivate::nativeSyncToDisk()
214{
215 if (fh || fd != -1) {
216 // stdlib / stdio mode. No API available.
217 return false;
218 }
219 return FlushFileBuffers(fileHandle);
220}
221
222/*
223 \internal
224*/
225qint64 QFSFileEnginePrivate::nativeSize() const
226{
227 Q_Q(const QFSFileEngine);
228 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q);
229
230 // ### Don't flush; for buffered files, we should get away with ftell.
231 thatQ->flush();
232
233 // Always retrive the current information
234 metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
235 bool filled = false;
236 if (fileHandle != INVALID_HANDLE_VALUE && openMode != QIODevice::NotOpen )
237 filled = QFileSystemEngine::fillMetaData(fileHandle, metaData,
238 QFileSystemMetaData::SizeAttribute);
239 else
240 filled = doStat(QFileSystemMetaData::SizeAttribute);
241
242 if (!filled) {
243 thatQ->setError(QFile::UnspecifiedError, QSystemError::stdString());
244 return 0;
245 }
246 return metaData.size();
247}
248
249/*
250 \internal
251*/
252qint64 QFSFileEnginePrivate::nativePos() const
253{
254 Q_Q(const QFSFileEngine);
255 QFSFileEngine *thatQ = const_cast<QFSFileEngine *>(q);
256
257 if (fh || fd != -1) {
258 // stdlib / stido mode.
259 return posFdFh();
260 }
261
262 // Windows native mode.
263 if (fileHandle == INVALID_HANDLE_VALUE)
264 return 0;
265
266 LARGE_INTEGER currentFilePos;
267 LARGE_INTEGER offset;
268 offset.QuadPart = 0;
269 if (!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_CURRENT)) {
270 thatQ->setError(QFile::UnspecifiedError, qt_error_string());
271 return 0;
272 }
273
274 return qint64(currentFilePos.QuadPart);
275}
276
277/*
278 \internal
279*/
280bool QFSFileEnginePrivate::nativeSeek(qint64 pos)
281{
282 Q_Q(QFSFileEngine);
283
284 if (fh || fd != -1) {
285 // stdlib / stdio mode.
286 return seekFdFh(pos);
287 }
288
289 LARGE_INTEGER currentFilePos;
290 LARGE_INTEGER offset;
291 offset.QuadPart = pos;
292 if (!::SetFilePointerEx(fileHandle, offset, &currentFilePos, FILE_BEGIN)) {
293 q->setError(QFile::UnspecifiedError, qt_error_string());
294 return false;
295 }
296
297 return true;
298}
299
300/*
301 \internal
302*/
303qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
304{
305 Q_Q(QFSFileEngine);
306
307 if (fh || fd != -1) {
308 // stdio / stdlib mode.
309 if (fh && nativeIsSequential() && feof(fh)) {
310 q->setError(QFile::ReadError, QSystemError::stdString());
311 return -1;
312 }
313
314 return readFdFh(data, maxlen);
315 }
316
317 // Windows native mode.
318 if (fileHandle == INVALID_HANDLE_VALUE)
319 return -1;
320
321 qint64 bytesToRead = maxlen;
322
323 // Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
324 // the chunks are too large, so we limit the block size to 32MB.
325 static const qint64 maxBlockSize = 32 * 1024 * 1024;
326
327 qint64 totalRead = 0;
328 do {
329 DWORD blockSize = DWORD(qMin(bytesToRead, maxBlockSize));
330 DWORD bytesRead;
331 if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) {
332 if (totalRead == 0) {
333 // Note: only return failure if the first ReadFile fails.
334 q->setError(QFile::ReadError, qt_error_string());
335 return -1;
336 }
337 break;
338 }
339 if (bytesRead == 0)
340 break;
341 totalRead += bytesRead;
342 bytesToRead -= bytesRead;
343 } while (totalRead < maxlen);
344 return totalRead;
345}
346
347/*
348 \internal
349*/
350qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen)
351{
352 Q_Q(QFSFileEngine);
353
354 if (fh || fd != -1) {
355 // stdio / stdlib mode.
356 return readLineFdFh(data, maxlen);
357 }
358
359 // Windows native mode.
360 if (fileHandle == INVALID_HANDLE_VALUE)
361 return -1;
362
363 // ### No equivalent in Win32?
364 return q->QAbstractFileEngine::readLine(data, maxlen);
365}
366
367/*
368 \internal
369*/
370qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
371{
372 Q_Q(QFSFileEngine);
373
374 if (fh || fd != -1) {
375 // stdio / stdlib mode.
376 return writeFdFh(data, len);
377 }
378
379 // Windows native mode.
380 if (fileHandle == INVALID_HANDLE_VALUE)
381 return -1;
382
383 qint64 bytesToWrite = len;
384
385 // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
386 // the chunks are too large, so we limit the block size to 32MB.
387 qint64 totalWritten = 0;
388 do {
389 const DWORD currentBlockSize = DWORD(qMin(bytesToWrite, qint64(32 * 1024 * 1024)));
390 DWORD bytesWritten;
391 if (!WriteFile(fileHandle, data + totalWritten, currentBlockSize, &bytesWritten, NULL)) {
392 if (totalWritten == 0) {
393 // Note: Only return error if the first WriteFile failed.
394 q->setError(QFile::WriteError, qt_error_string());
395 return -1;
396 }
397 break;
398 }
399 if (bytesWritten == 0)
400 break;
401 totalWritten += bytesWritten;
402 bytesToWrite -= bytesWritten;
403 } while (totalWritten < len);
404 return qint64(totalWritten);
405}
406
407/*
408 \internal
409*/
410int QFSFileEnginePrivate::nativeHandle() const
411{
412 if (fh || fd != -1)
413 return fh ? QT_FILENO(fh) : fd;
414 if (cachedFd != -1)
415 return cachedFd;
416
417 int flags = 0;
418 if (openMode & QIODevice::Append)
419 flags |= _O_APPEND;
420 if (!(openMode & QIODevice::WriteOnly))
421 flags |= _O_RDONLY;
422 cachedFd = _open_osfhandle((intptr_t) fileHandle, flags);
423 return cachedFd;
424}
425
426/*
427 \internal
428*/
429bool QFSFileEnginePrivate::nativeIsSequential() const
430{
431#if !defined(Q_OS_WINRT)
432 HANDLE handle = fileHandle;
433 if (fh || fd != -1)
434 handle = (HANDLE)_get_osfhandle(fh ? QT_FILENO(fh) : fd);
435 if (handle == INVALID_HANDLE_VALUE)
436 return false;
437
438 DWORD fileType = GetFileType(handle);
439 return (fileType == FILE_TYPE_CHAR)
440 || (fileType == FILE_TYPE_PIPE);
441#else
442 return false;
443#endif
444}
445
446bool QFSFileEngine::remove()
447{
448 Q_D(QFSFileEngine);
449 QSystemError error;
450 bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
451 if (!ret)
452 setError(QFile::RemoveError, error.toString());
453 return ret;
454}
455
456bool QFSFileEngine::copy(const QString &copyName)
457{
458 Q_D(QFSFileEngine);
459 QSystemError error;
460 bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
461 if (!ret)
462 setError(QFile::CopyError, error.toString());
463 return ret;
464}
465
466bool QFSFileEngine::rename(const QString &newName)
467{
468 Q_D(QFSFileEngine);
469 QSystemError error;
470 bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
471 if (!ret)
472 setError(QFile::RenameError, error.toString());
473 return ret;
474}
475
476bool QFSFileEngine::renameOverwrite(const QString &newName)
477{
478 Q_D(QFSFileEngine);
479 QSystemError error;
480 bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
481 if (!ret)
482 setError(QFile::RenameError, error.toString());
483 return ret;
484}
485
486bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
487{
488 return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
489}
490
491bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
492{
493 return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
494}
495
496bool QFSFileEngine::caseSensitive() const
497{
498 return false;
499}
500
501bool QFSFileEngine::setCurrentPath(const QString &path)
502{
503 return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
504}
505
506QString QFSFileEngine::currentPath(const QString &fileName)
507{
508#if !defined(Q_OS_WINRT)
509 QString ret;
510 //if filename is a drive: then get the pwd of that drive
511 if (fileName.length() >= 2 &&
512 fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) {
513 int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1;
514 if (_getdrive() != drv) {
515 wchar_t buf[PATH_MAX];
516 ::_wgetdcwd(drv, buf, PATH_MAX);
517 ret = QString::fromWCharArray(buf);
518 }
519 }
520 if (ret.isEmpty()) {
521 //just the pwd
522 ret = QFileSystemEngine::currentPath().filePath();
523 }
524 if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
525 ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
526 return ret;
527#else // !Q_OS_WINRT
528 Q_UNUSED(fileName);
529 return QFileSystemEngine::currentPath().filePath();
530#endif // Q_OS_WINRT
531}
532
533QString QFSFileEngine::homePath()
534{
535 return QFileSystemEngine::homePath();
536}
537
538QString QFSFileEngine::rootPath()
539{
540 return QFileSystemEngine::rootPath();
541}
542
543QString QFSFileEngine::tempPath()
544{
545 return QFileSystemEngine::tempPath();
546}
547
548#if !defined(Q_OS_WINRT)
549// cf QStorageInfo::isReady
550static inline bool isDriveReady(const wchar_t *path)
551{
552 DWORD fileSystemFlags;
553 const UINT driveType = GetDriveType(path);
554 return (driveType != DRIVE_REMOVABLE && driveType != DRIVE_CDROM)
555 || GetVolumeInformation(path, nullptr, 0, nullptr, nullptr,
556 &fileSystemFlags, nullptr, 0) == TRUE;
557}
558#endif // !Q_OS_WINRT
559
560QFileInfoList QFSFileEngine::drives()
561{
562 QFileInfoList ret;
563#if !defined(Q_OS_WINRT)
564 const UINT oldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
565 quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff;
566 wchar_t driveName[] = L"A:\\";
567
568 while (driveBits) {
569 if ((driveBits & 1) && isDriveReady(driveName))
570 ret.append(QFileInfo(QString::fromWCharArray(driveName)));
571 driveName[0]++;
572 driveBits = driveBits >> 1;
573 }
574 ::SetErrorMode(oldErrorMode);
575 return ret;
576#else // !Q_OS_WINRT
577 ret.append(QFileInfo(QLatin1String("/")));
578 return ret;
579#endif // Q_OS_WINRT
580}
581
582bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
583{
584 if (!tried_stat || !metaData.hasFlags(flags)) {
585 tried_stat = true;
586
587 int localFd = fd;
588 if (fh && fileEntry.isEmpty())
589 localFd = QT_FILENO(fh);
590 if (localFd != -1)
591 QFileSystemEngine::fillMetaData(localFd, metaData, flags);
592 if (metaData.missingFlags(flags) && !fileEntry.isEmpty())
593 QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
594 }
595
596 return metaData.exists();
597}
598
599
600bool QFSFileEngine::link(const QString &newName)
601{
602#if !defined(Q_OS_WINRT)
603 bool ret = false;
604
605 QString linkName = newName;
606 //### assume that they add .lnk
607
608 IShellLink *psl;
609 bool neededCoInit = false;
610
611 HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
612 reinterpret_cast<void **>(&psl));
613
614 if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
615 neededCoInit = true;
616 CoInitialize(nullptr);
617 hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
618 reinterpret_cast<void **>(&psl));
619 }
620
621 if (SUCCEEDED(hres)) {
622 const QString nativeAbsoluteName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\'));
623 hres = psl->SetPath(reinterpret_cast<const wchar_t *>(nativeAbsoluteName.utf16()));
624 if (SUCCEEDED(hres)) {
625 const QString nativeAbsolutePathName = fileName(AbsolutePathName).replace(QLatin1Char('/'), QLatin1Char('\\'));
626 hres = psl->SetWorkingDirectory(reinterpret_cast<const wchar_t *>(nativeAbsolutePathName.utf16()));
627 if (SUCCEEDED(hres)) {
628 IPersistFile *ppf;
629 hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void **>(&ppf));
630 if (SUCCEEDED(hres)) {
631 hres = ppf->Save(reinterpret_cast<const wchar_t *>(linkName.utf16()), TRUE);
632 if (SUCCEEDED(hres))
633 ret = true;
634 ppf->Release();
635 }
636 }
637 }
638 psl->Release();
639 }
640 if (!ret)
641 setError(QFile::RenameError, qt_error_string());
642
643 if (neededCoInit)
644 CoUninitialize();
645
646 return ret;
647#else // !Q_OS_WINRT
648 Q_UNUSED(newName);
649 Q_UNIMPLEMENTED();
650 return false;
651#endif // Q_OS_WINRT
652}
653
654/*!
655 \reimp
656*/
657QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const
658{
659 Q_D(const QFSFileEngine);
660
661 if (type & Refresh)
662 d->metaData.clear();
663
664 QAbstractFileEngine::FileFlags ret = 0;
665
666 if (type & FlagsMask)
667 ret |= LocalDiskFlag;
668
669 bool exists;
670 {
671 QFileSystemMetaData::MetaDataFlags queryFlags = 0;
672
673 queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type))
674 & QFileSystemMetaData::Permissions;
675
676 // AliasType and BundleType are 0x0
677 if (type & TypesMask)
678 queryFlags |= QFileSystemMetaData::AliasType
679 | QFileSystemMetaData::LinkType
680 | QFileSystemMetaData::FileType
681 | QFileSystemMetaData::DirectoryType
682 | QFileSystemMetaData::BundleType;
683
684 if (type & FlagsMask)
685 queryFlags |= QFileSystemMetaData::HiddenAttribute
686 | QFileSystemMetaData::ExistsAttribute;
687
688 queryFlags |= QFileSystemMetaData::LinkType;
689
690 exists = d->doStat(queryFlags);
691 }
692
693 if (exists && (type & PermsMask))
694 ret |= FileFlags(uint(d->metaData.permissions()));
695
696 if (type & TypesMask) {
697 if ((type & LinkType) && d->metaData.isLegacyLink())
698 ret |= LinkType;
699 if (d->metaData.isDirectory()) {
700 ret |= DirectoryType;
701 } else {
702 ret |= FileType;
703 }
704 }
705 if (type & FlagsMask) {
706 if (d->metaData.exists()) {
707 // if we succeeded in querying, then the file exists: a file on
708 // Windows cannot be deleted if we have an open handle to it
709 ret |= ExistsFlag;
710 if (d->fileEntry.isRoot())
711 ret |= RootFlag;
712 else if (d->metaData.isHidden())
713 ret |= HiddenFlag;
714 }
715 }
716 return ret;
717}
718
719QByteArray QFSFileEngine::id() const
720{
721 Q_D(const QFSFileEngine);
722 HANDLE h = d->fileHandle;
723 if (h == INVALID_HANDLE_VALUE) {
724 int localFd = d->fd;
725 if (d->fh && d->fileEntry.isEmpty())
726 localFd = QT_FILENO(d->fh);
727 if (localFd != -1)
728 h = HANDLE(_get_osfhandle(localFd));
729 }
730 if (h != INVALID_HANDLE_VALUE)
731 return QFileSystemEngine::id(h);
732
733 // file is not open, try by path
734 return QFileSystemEngine::id(d->fileEntry);
735}
736
737QString QFSFileEngine::fileName(FileName file) const
738{
739 Q_D(const QFSFileEngine);
740 if (file == BaseName) {
741 return d->fileEntry.fileName();
742 } else if (file == PathName) {
743 return d->fileEntry.path();
744 } else if (file == AbsoluteName || file == AbsolutePathName) {
745 QString ret;
746
747 if (!isRelativePath()) {
748 if (d->fileEntry.filePath().startsWith(QLatin1Char('/')) || // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt
749 d->fileEntry.filePath().size() == 2 || // It's a drive letter that needs to get a working dir appended
750 (d->fileEntry.filePath().size() > 2 && d->fileEntry.filePath().at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt
751 d->fileEntry.filePath().contains(QLatin1String("/../")) || d->fileEntry.filePath().contains(QLatin1String("/./")) ||
752 d->fileEntry.filePath().endsWith(QLatin1String("/..")) || d->fileEntry.filePath().endsWith(QLatin1String("/.")))
753 {
754 ret = QDir::fromNativeSeparators(QFileSystemEngine::nativeAbsoluteFilePath(d->fileEntry.filePath()));
755 } else {
756 ret = d->fileEntry.filePath();
757 }
758 } else {
759 ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->fileEntry.filePath());
760 }
761
762 // The path should be absolute at this point.
763 // From the docs :
764 // Absolute paths begin with the directory separator "/"
765 // (optionally preceded by a drive specification under Windows).
766 if (ret.at(0) != QLatin1Char('/')) {
767 Q_ASSERT(ret.length() >= 2);
768 Q_ASSERT(ret.at(0).isLetter());
769 Q_ASSERT(ret.at(1) == QLatin1Char(':'));
770
771 // Force uppercase drive letters.
772 ret[0] = ret.at(0).toUpper();
773 }
774
775 if (file == AbsolutePathName) {
776 int slash = ret.lastIndexOf(QLatin1Char('/'));
777 if (slash < 0)
778 return ret;
779 if (ret.at(0) != QLatin1Char('/') && slash == 2)
780 return ret.left(3); // include the slash
781 return ret.left(slash > 0 ? slash : 1);
782 }
783 return ret;
784 } else if (file == CanonicalName || file == CanonicalPathName) {
785 if (!(fileFlags(ExistsFlag) & ExistsFlag))
786 return QString();
787 QFileSystemEntry entry(QFileSystemEngine::canonicalName(QFileSystemEntry(fileName(AbsoluteName)), d->metaData));
788
789 if (file == CanonicalPathName)
790 return entry.path();
791 return entry.filePath();
792 } else if (file == LinkName) {
793 return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();
794 } else if (file == BundleName) {
795 return QString();
796 }
797 return d->fileEntry.filePath();
798}
799
800bool QFSFileEngine::isRelativePath() const
801{
802 Q_D(const QFSFileEngine);
803 // drive, e.g. "a:", or UNC root, e.q. "//"
804 return d->fileEntry.isRelative();
805}
806
807uint QFSFileEngine::ownerId(FileOwner /*own*/) const
808{
809 static const uint nobodyID = (uint) -2;
810 return nobodyID;
811}
812
813QString QFSFileEngine::owner(FileOwner own) const
814{
815 Q_D(const QFSFileEngine);
816 return QFileSystemEngine::owner(d->fileEntry, own);
817}
818
819bool QFSFileEngine::setPermissions(uint perms)
820{
821 Q_D(QFSFileEngine);
822 QSystemError error;
823 bool ret = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error);
824 if (!ret)
825 setError(QFile::PermissionsError, error.toString());
826 return ret;
827}
828
829bool QFSFileEngine::setSize(qint64 size)
830{
831 Q_D(QFSFileEngine);
832
833 if (d->fileHandle != INVALID_HANDLE_VALUE || d->fd != -1 || d->fh) {
834 // resize open file
835 HANDLE fh = d->fileHandle;
836 if (fh == INVALID_HANDLE_VALUE) {
837 if (d->fh)
838 fh = (HANDLE)_get_osfhandle(QT_FILENO(d->fh));
839 else
840 fh = (HANDLE)_get_osfhandle(d->fd);
841 }
842 if (fh == INVALID_HANDLE_VALUE)
843 return false;
844 qint64 currentPos = pos();
845
846 if (seek(size) && SetEndOfFile(fh)) {
847 seek(qMin(currentPos, size));
848 return true;
849 }
850
851 seek(currentPos);
852 return false;
853 }
854
855 if (!d->fileEntry.isEmpty()) {
856 // resize file on disk
857 QFile file(d->fileEntry.filePath());
858 if (file.open(QFile::ReadWrite)) {
859 bool ret = file.resize(size);
860 if (!ret)
861 setError(QFile::ResizeError, file.errorString());
862 return ret;
863 }
864 }
865 return false;
866}
867
868bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
869{
870 Q_D(QFSFileEngine);
871
872 if (d->openMode == QFile::NotOpen) {
873 setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
874 return false;
875 }
876
877 if (!newDate.isValid() || time == QAbstractFileEngine::MetadataChangeTime) {
878 setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
879 return false;
880 }
881
882 HANDLE handle = d->fileHandle;
883 if (handle == INVALID_HANDLE_VALUE) {
884 if (d->fh)
885 handle = reinterpret_cast<HANDLE>(::_get_osfhandle(QT_FILENO(d->fh)));
886 else if (d->fd != -1)
887 handle = reinterpret_cast<HANDLE>(::_get_osfhandle(d->fd));
888 }
889
890 if (handle == INVALID_HANDLE_VALUE) {
891 setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
892 return false;
893 }
894
895 QSystemError error;
896 if (!QFileSystemEngine::setFileTime(handle, newDate, time, error)) {
897 setError(QFile::PermissionsError, error.toString());
898 return false;
899 }
900
901 d->metaData.clearFlags(QFileSystemMetaData::Times);
902 return true;
903}
904
905uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
906 QFile::MemoryMapFlags flags)
907{
908 Q_Q(QFSFileEngine);
909 Q_UNUSED(flags);
910 if (openMode == QFile::NotOpen) {
911 q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
912 return 0;
913 }
914 if (offset == 0 && size == 0) {
915 q->setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
916 return 0;
917 }
918
919 // check/setup args to map
920 DWORD access = 0;
921 if (flags & QFileDevice::MapPrivateOption) {
922#ifdef FILE_MAP_COPY
923 access = FILE_MAP_COPY;
924#else
925 q->setError(QFile::UnspecifiedError, "MapPrivateOption unsupported");
926 return 0;
927#endif
928 } else if (openMode & QIODevice::WriteOnly) {
929 access = FILE_MAP_WRITE;
930 } else if (openMode & QIODevice::ReadOnly) {
931 access = FILE_MAP_READ;
932 }
933
934 if (mapHandle == NULL) {
935 // get handle to the file
936 HANDLE handle = fileHandle;
937
938 if (handle == INVALID_HANDLE_VALUE && fh)
939 handle = (HANDLE)::_get_osfhandle(QT_FILENO(fh));
940
941#ifdef Q_USE_DEPRECATED_MAP_API
942 nativeClose();
943 // handle automatically closed by kernel with mapHandle (below).
944 handle = ::CreateFileForMapping((const wchar_t*)fileEntry.nativeFilePath().utf16(),
945 GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0),
946 0,
947 NULL,
948 OPEN_EXISTING,
949 FILE_ATTRIBUTE_NORMAL,
950 NULL);
951 // Since this is a special case, we check if the return value was NULL and if so
952 // we change it to INVALID_HANDLE_VALUE to follow the logic inside this function.
953 if(0 == handle)
954 handle = INVALID_HANDLE_VALUE;
955#endif
956
957 if (handle == INVALID_HANDLE_VALUE) {
958 q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
959 return 0;
960 }
961
962 // first create the file mapping handle
963 DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY;
964#ifndef Q_OS_WINRT
965 mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0);
966#else
967 mapHandle = ::CreateFileMappingFromApp(handle, 0, protection, 0, 0);
968#endif
969 if (mapHandle == NULL) {
970 q->setError(QFile::PermissionsError, qt_error_string());
971#ifdef Q_USE_DEPRECATED_MAP_API
972 ::CloseHandle(handle);
973#endif
974 return 0;
975 }
976 }
977
978 DWORD offsetHi = offset >> 32;
979 DWORD offsetLo = offset & Q_UINT64_C(0xffffffff);
980 SYSTEM_INFO sysinfo;
981#ifndef Q_OS_WINRT
982 ::GetSystemInfo(&sysinfo);
983#else
984 ::GetNativeSystemInfo(&sysinfo);
985#endif
986 DWORD mask = sysinfo.dwAllocationGranularity - 1;
987 DWORD extra = offset & mask;
988 if (extra)
989 offsetLo &= ~mask;
990
991 // attempt to create the map
992#ifndef Q_OS_WINRT
993 LPVOID mapAddress = ::MapViewOfFile(mapHandle, access,
994 offsetHi, offsetLo, size + extra);
995#else
996 LPVOID mapAddress = ::MapViewOfFileFromApp(mapHandle, access,
997 (ULONG64(offsetHi) << 32) + offsetLo, size + extra);
998#endif
999 if (mapAddress) {
1000 uchar *address = extra + static_cast<uchar*>(mapAddress);
1001 maps[address] = extra;
1002 return address;
1003 }
1004
1005 switch(GetLastError()) {
1006 case ERROR_ACCESS_DENIED:
1007 q->setError(QFile::PermissionsError, qt_error_string());
1008 break;
1009 case ERROR_INVALID_PARAMETER:
1010 // size are out of bounds
1011 default:
1012 q->setError(QFile::UnspecifiedError, qt_error_string());
1013 }
1014
1015 ::CloseHandle(mapHandle);
1016 mapHandle = NULL;
1017 return 0;
1018}
1019
1020bool QFSFileEnginePrivate::unmap(uchar *ptr)
1021{
1022 Q_Q(QFSFileEngine);
1023 if (!maps.contains(ptr)) {
1024 q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
1025 return false;
1026 }
1027 uchar *start = ptr - maps[ptr];
1028 if (!UnmapViewOfFile(start)) {
1029 q->setError(QFile::PermissionsError, qt_error_string());
1030 return false;
1031 }
1032
1033 maps.remove(ptr);
1034 if (maps.isEmpty()) {
1035 ::CloseHandle(mapHandle);
1036 mapHandle = NULL;
1037 }
1038
1039 return true;
1040}
1041
1042/*!
1043 \reimp
1044*/
1045bool QFSFileEngine::cloneTo(QAbstractFileEngine *target)
1046{
1047 // There's some Windows Server 2016 API, but we won't
1048 // bother with it.
1049 Q_UNUSED(target);
1050 return false;
1051}
1052
1053QT_END_NAMESPACE
1054

Warning: That file was not part of the compilation database. It may have many parsing errors.