Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qfsfileengine.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// Copyright (C) 2016 Intel Corporation.
3
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
// Qt-Security score:critical reason:data-parser
5
6
#
include
"qfsfileengine_p.h"
7
#
include
"qfsfileengine_iterator_p.h"
8
#
include
"qfilesystemengine_p.h"
9
#
include
"qdatetime.h"
10
#
include
"qset.h"
11
#
include
<
QtCore
/
qdebug
.
h
>
12
13
#
ifndef
QT_NO_FSFILEENGINE
14
15
#
include
<
errno
.
h
>
16
#
if
defined
(
Q_OS_UNIX
)
17
#
include
"private/qcore_unix_p.h"
18
#
endif
19
#
include
<
stdio
.
h
>
20
#
include
<
stdlib
.
h
>
21
#
if
defined
(
Q_OS_DARWIN
)
22
#
include
<
private
/
qcore_mac_p
.
h
>
23
#
endif
24
25
QT_BEGIN_NAMESPACE
26
27
using
namespace
Qt::StringLiterals;
28
29
#
ifdef
Q_OS_WIN
30
#
ifndef
S_ISREG
31
#
define
S_ISREG
(
x
)
(
(
(
x
)
&
S_IFMT
)
==
S_IFREG
)
32
#
endif
33
#
ifndef
S_ISCHR
34
#
define
S_ISCHR
(
x
)
(
(
(
x
)
&
S_IFMT
)
==
S_IFCHR
)
35
#
endif
36
#
ifndef
S_ISFIFO
37
#
define
S_ISFIFO
(
x
)
false
38
#
endif
39
#
ifndef
S_ISSOCK
40
#
define
S_ISSOCK
(
x
)
false
41
#
endif
42
#
ifndef
INVALID_FILE_ATTRIBUTES
43
#
define
INVALID_FILE_ATTRIBUTES
(
DWORD
(
-
1
)
)
44
#
endif
45
#
endif
46
47
#
ifdef
Q_OS_WIN
48
// on Windows, read() and write() use int and unsigned int
49
typedef
int
SignedIOType;
50
typedef
unsigned
int
UnsignedIOType;
51
#
else
52
typedef
ssize_t
SignedIOType
;
53
typedef
size_t
UnsignedIOType
;
54
static_assert
(
sizeof
(
SignedIOType
) ==
sizeof
(
UnsignedIOType
),
55
"Unsupported: read/write return a type with different size as the len parameter"
);
56
#
endif
57
58
/*! \class QFSFileEngine
59
\inmodule QtCore
60
\brief The QFSFileEngine class implements Qt's default file engine.
61
\since 4.1
62
\internal
63
64
This class is part of the file engine framework in Qt. If you only want to
65
access files or directories, use QFile, QFileInfo or QDir instead.
66
67
QFSFileEngine is the default file engine for accessing regular files. It
68
is provided for convenience; by subclassing this class, you can alter its
69
behavior slightly, without having to write a complete QAbstractFileEngine
70
subclass. To install your custom file engine, you must also subclass
71
QAbstractFileEngineHandler and create an instance of your handler.
72
73
It can also be useful to create a QFSFileEngine object directly if you
74
need to use the local file system inside QAbstractFileEngine::create(), in
75
order to avoid recursion (as higher-level classes tend to call
76
QAbstractFileEngine::create()).
77
*/
78
79
//**************** QFSFileEnginePrivate
80
QFSFileEnginePrivate::QFSFileEnginePrivate(QAbstractFileEngine *q)
81
: QAbstractFileEnginePrivate(q)
82
{
83
init();
84
}
85
86
/*!
87
\internal
88
*/
89
void
QFSFileEnginePrivate::init()
90
{
91
is_sequential = 0;
92
tried_stat = 0;
93
need_lstat = 1;
94
is_link = 0;
95
openMode = QIODevice::NotOpen;
96
fd = -1;
97
fh =
nullptr
;
98
lastIOCommand = IOFlushCommand;
99
lastFlushFailed =
false
;
100
closeFileHandle =
false
;
101
#
ifdef
Q_OS_WIN
102
fileAttrib = INVALID_FILE_ATTRIBUTES;
103
fileHandle = INVALID_HANDLE_VALUE;
104
mapHandle = NULL;
105
cachedFd = -1;
106
#
endif
107
}
108
109
/*!
110
Constructs a QFSFileEngine for the file name \a file.
111
*/
112
QFSFileEngine::QFSFileEngine(
const
QString &file)
113
: QAbstractFileEngine(*
new
QFSFileEnginePrivate(
this
))
114
{
115
Q_D(QFSFileEngine);
116
d->fileEntry = QFileSystemEntry(file);
117
}
118
119
/*!
120
Constructs a QFSFileEngine.
121
*/
122
QFSFileEngine::QFSFileEngine() : QAbstractFileEngine(*
new
QFSFileEnginePrivate(
this
))
123
{
124
}
125
126
/*!
127
\internal
128
*/
129
QFSFileEngine::QFSFileEngine(QFSFileEnginePrivate &dd)
130
: QAbstractFileEngine(dd)
131
{
132
}
133
134
/*!
135
\internal
136
*/
137
ProcessOpenModeResult
processOpenModeFlags
(QIODevice::OpenMode openMode)
138
{
139
ProcessOpenModeResult result;
140
result.ok =
false
;
141
if
((openMode & QFile::NewOnly) && (openMode & QFile::ExistingOnly)) {
142
qWarning(
"NewOnly and ExistingOnly are mutually exclusive"
);
143
result.error =
"NewOnly and ExistingOnly are mutually exclusive"_L1
;
144
return
result;
145
}
146
147
if
((openMode & QFile::ExistingOnly) && !(openMode & (QFile::ReadOnly | QFile::WriteOnly))) {
148
qWarning(
"ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite"
);
149
result.error =
150
"ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite"_L1
;
151
return
result;
152
}
153
154
// Either Append or NewOnly implies WriteOnly
155
if
(openMode & (QFile::Append | QFile::NewOnly))
156
openMode |= QFile::WriteOnly;
157
158
// WriteOnly implies Truncate when ReadOnly, Append, and NewOnly are not set.
159
if
((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append | QFile::NewOnly)))
160
openMode |= QFile::Truncate;
161
162
result.ok =
true
;
163
result.openMode = openMode;
164
return
result;
165
}
166
167
/*!
168
Destructs the QFSFileEngine.
169
*/
170
QFSFileEngine::~QFSFileEngine()
171
{
172
Q_D(QFSFileEngine);
173
if
(d->closeFileHandle) {
174
if
(d->fh) {
175
fclose(d->fh);
176
}
else
if
(d->fd != -1) {
177
QT_CLOSE(d->fd);
178
}
179
}
180
d->unmapAll();
181
}
182
183
/*!
184
\reimp
185
*/
186
void
QFSFileEngine::setFileName(
const
QString &file)
187
{
188
Q_D(QFSFileEngine);
189
d->init();
190
d->fileEntry = QFileSystemEntry(file);
191
}
192
193
/*!
194
\reimp
195
*/
196
bool
QFSFileEngine::open(QIODevice::OpenMode openMode,
197
std::optional<QFile::Permissions> permissions)
198
{
199
Q_ASSERT_X(openMode & QIODevice::Unbuffered,
"QFSFileEngine::open"
,
200
"QFSFileEngine no longer supports buffered mode; upper layer must buffer"
);
201
202
Q_D(QFSFileEngine);
203
if
(d->fileEntry.isEmpty()) {
204
qWarning(
"QFSFileEngine::open: No file name specified"
);
205
setError(QFile::OpenError,
"No file name specified"_L1
);
206
return
false
;
207
}
208
209
const
ProcessOpenModeResult res = processOpenModeFlags(openMode);
210
if
(!res.ok) {
211
setError(QFileDevice::OpenError, res.error);
212
return
false
;
213
}
214
215
d->openMode = res.openMode;
216
d->lastFlushFailed =
false
;
217
d->tried_stat = 0;
218
d->fh =
nullptr
;
219
d->fd = -1;
220
221
return
d->nativeOpen(d->openMode, permissions);
222
}
223
224
/*!
225
Opens the file handle \a fh in \a openMode mode. Returns \c true on
226
success; otherwise returns \c false.
227
*/
228
bool
QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags)
229
{
230
Q_ASSERT_X(openMode & QIODevice::Unbuffered,
"QFSFileEngine::open"
,
231
"QFSFileEngine no longer supports buffered mode; upper layer must buffer"
);
232
233
Q_D(QFSFileEngine);
234
235
const
ProcessOpenModeResult res = processOpenModeFlags(openMode);
236
if
(!res.ok) {
237
setError(QFileDevice::OpenError, res.error);
238
return
false
;
239
}
240
241
d->openMode = res.openMode;
242
d->lastFlushFailed =
false
;
243
d->closeFileHandle = handleFlags.testAnyFlag(QFile::AutoCloseHandle);
244
d->fileEntry.clear();
245
d->tried_stat = 0;
246
d->fd = -1;
247
248
return
d->openFh(d->openMode, fh);
249
}
250
251
/*!
252
\class QFSFileEnginePrivate
253
\inmodule QtCore
254
\internal
255
*/
256
257
/*!
258
Opens the file handle \a fh using the open mode \a flags.
259
*/
260
bool
QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
261
{
262
Q_ASSERT_X(openMode & QIODevice::Unbuffered,
"QFSFileEngine::open"
,
263
"QFSFileEngine no longer supports buffered mode; upper layer must buffer"
);
264
265
Q_Q(QFSFileEngine);
266
this
->fh = fh;
267
fd = -1;
268
269
// Seek to the end when in Append mode.
270
if
(openMode & QIODevice::Append) {
271
int
ret;
272
do
{
273
ret = QT_FSEEK(fh, 0, SEEK_END);
274
}
while
(ret != 0 && errno == EINTR);
275
276
if
(ret != 0) {
277
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
278
QSystemError::stdString(errno));
279
280
this
->openMode = QIODevice::NotOpen;
281
this
->fh =
nullptr
;
282
283
return
false
;
284
}
285
}
286
287
return
true
;
288
}
289
290
/*!
291
Opens the file descriptor \a fd in \a openMode mode. Returns \c true
292
on success; otherwise returns \c false.
293
*/
294
bool
QFSFileEngine::open(QIODevice::OpenMode openMode,
int
fd, QFile::FileHandleFlags handleFlags)
295
{
296
Q_D(QFSFileEngine);
297
298
const
ProcessOpenModeResult res = processOpenModeFlags(openMode);
299
if
(!res.ok) {
300
setError(QFileDevice::OpenError, res.error);
301
return
false
;
302
}
303
304
d->openMode = res.openMode;
305
d->lastFlushFailed =
false
;
306
d->closeFileHandle = handleFlags.testAnyFlag(QFile::AutoCloseHandle);
307
d->fileEntry.clear();
308
d->fh =
nullptr
;
309
d->fd = -1;
310
d->tried_stat = 0;
311
312
return
d->openFd(d->openMode, fd);
313
}
314
315
316
/*!
317
Opens the file descriptor \a fd to the file engine, using the open mode \a
318
flags.
319
*/
320
bool
QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode,
int
fd)
321
{
322
Q_Q(QFSFileEngine);
323
this
->fd = fd;
324
fh =
nullptr
;
325
326
// Seek to the end when in Append mode.
327
if
(openMode & QFile::Append) {
328
QT_OFF_T ret;
329
do
{
330
ret = QT_LSEEK(fd, 0, SEEK_END);
331
}
while
(ret == -1 && errno == EINTR);
332
333
if
(ret == -1) {
334
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
335
QSystemError::stdString(errno));
336
337
this
->openMode = QIODevice::NotOpen;
338
this
->fd = -1;
339
340
return
false
;
341
}
342
}
343
344
return
true
;
345
}
346
347
/*!
348
\reimp
349
*/
350
bool
QFSFileEngine::close()
351
{
352
Q_D(QFSFileEngine);
353
d->openMode = QIODevice::NotOpen;
354
return
d->nativeClose();
355
}
356
357
/*!
358
\internal
359
*/
360
bool
QFSFileEnginePrivate::closeFdFh()
361
{
362
Q_Q(QFSFileEngine);
363
if
(fd == -1 && !fh)
364
return
false
;
365
366
// Flush the file if it's buffered, and if the last flush didn't fail.
367
bool
flushed = !fh || (!lastFlushFailed && q->flush());
368
bool
closed =
true
;
369
tried_stat = 0;
370
371
// Close the file if we created the handle.
372
if
(closeFileHandle) {
373
int
ret;
374
375
if
(fh) {
376
// Close buffered file.
377
ret = fclose(fh);
378
}
else
{
379
// Close unbuffered file.
380
ret = QT_CLOSE(fd);
381
}
382
383
// We must reset these guys regardless; calling close again after a
384
// failed close causes crashes on some systems.
385
fh =
nullptr
;
386
fd = -1;
387
closed = (ret == 0);
388
}
389
390
// Report errors.
391
if
(!flushed || !closed) {
392
if
(flushed) {
393
// If not flushed, we want the flush error to fall through.
394
q->setError(QFile::UnspecifiedError, QSystemError::stdString(errno));
395
}
396
return
false
;
397
}
398
399
return
true
;
400
}
401
402
/*!
403
\reimp
404
*/
405
bool
QFSFileEngine::flush()
406
{
407
Q_D(QFSFileEngine);
408
if
((d->openMode & QIODevice::WriteOnly) == 0) {
409
// Nothing in the write buffers, so flush succeeds in doing
410
// nothing.
411
return
true
;
412
}
413
return
d->nativeFlush();
414
}
415
416
/*!
417
\reimp
418
*/
419
bool
QFSFileEngine::syncToDisk()
420
{
421
Q_D(QFSFileEngine);
422
if
((d->openMode & QIODevice::WriteOnly) == 0)
423
return
true
;
424
return
d->nativeSyncToDisk();
425
}
426
427
/*!
428
\internal
429
*/
430
bool
QFSFileEnginePrivate::flushFh()
431
{
432
Q_Q(QFSFileEngine);
433
434
// Never try to flush again if the last flush failed. Otherwise you can
435
// get crashes on some systems (AIX).
436
if
(lastFlushFailed)
437
return
false
;
438
439
int
ret = fflush(fh);
440
441
lastFlushFailed = (ret != 0);
442
lastIOCommand = QFSFileEnginePrivate::IOFlushCommand;
443
444
if
(ret != 0) {
445
q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
446
QSystemError::stdString(errno));
447
return
false
;
448
}
449
return
true
;
450
}
451
452
/*!
453
\reimp
454
*/
455
qint64 QFSFileEngine::size()
const
456
{
457
Q_D(
const
QFSFileEngine);
458
return
d->nativeSize();
459
}
460
461
/*!
462
\internal
463
*/
464
void
QFSFileEnginePrivate::unmapAll()
465
{
466
if
(!maps.isEmpty()) {
467
const
QList<uchar*> keys = maps.keys();
// Make a copy since unmap() modifies the map.
468
for
(
int
i = 0; i < keys.size(); ++i)
469
unmap(keys.at(i));
470
}
471
}
472
473
#
ifndef
Q_OS_WIN
474
/*!
475
\internal
476
*/
477
qint64 QFSFileEnginePrivate::sizeFdFh()
const
478
{
479
Q_Q(
const
QFSFileEngine);
480
const_cast
<QFSFileEngine *>(q)->flush();
481
482
tried_stat = 0;
483
metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
484
if
(!doStat(QFileSystemMetaData::SizeAttribute))
485
return
0;
486
return
metaData.size();
487
}
488
#
endif
489
490
/*!
491
\reimp
492
*/
493
qint64 QFSFileEngine::pos()
const
494
{
495
Q_D(
const
QFSFileEngine);
496
return
d->nativePos();
497
}
498
499
/*!
500
\internal
501
*/
502
qint64 QFSFileEnginePrivate::posFdFh()
const
503
{
504
if
(fh)
505
return
qint64(QT_FTELL(fh));
506
return
QT_LSEEK(fd, 0, SEEK_CUR);
507
}
508
509
/*!
510
\reimp
511
*/
512
bool
QFSFileEngine::seek(qint64 pos)
513
{
514
Q_D(QFSFileEngine);
515
return
d->nativeSeek(pos);
516
}
517
518
/*!
519
\reimp
520
*/
521
QDateTime QFSFileEngine::fileTime(QFile::FileTime time)
const
522
{
523
Q_D(
const
QFSFileEngine);
524
525
if
(time == QFile::FileAccessTime) {
526
// always refresh for the access time
527
d->metaData.clearFlags(QFileSystemMetaData::AccessTime);
528
}
529
530
if
(d->doStat(QFileSystemMetaData::Times))
531
return
d->metaData.fileTime(time);
532
533
return
QDateTime();
534
}
535
536
537
/*!
538
\internal
539
*/
540
bool
QFSFileEnginePrivate::seekFdFh(qint64 pos)
541
{
542
Q_Q(QFSFileEngine);
543
544
// On Windows' stdlib implementation, the results of calling fread and
545
// fwrite are undefined if not called either in sequence, or if preceded
546
// with a call to fflush().
547
if
(lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush())
548
return
false
;
549
550
if
(pos < 0 || pos != qint64(QT_OFF_T(pos)))
551
return
false
;
552
553
if
(fh) {
554
// Buffered stdlib mode.
555
int
ret;
556
do
{
557
ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
558
}
while
(ret != 0 && errno == EINTR);
559
560
if
(ret != 0) {
561
q->setError(QFile::ReadError, QSystemError::stdString(errno));
562
return
false
;
563
}
564
}
else
{
565
// Unbuffered stdio mode.
566
if
(QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
567
q->setError(QFile::PositionError, QSystemError::stdString(errno));
568
qWarning(
"QFile::at: Cannot set file position %lld"
, pos);
569
return
false
;
570
}
571
}
572
return
true
;
573
}
574
575
/*!
576
\reimp
577
*/
578
int
QFSFileEngine::handle()
const
579
{
580
Q_D(
const
QFSFileEngine);
581
return
d->nativeHandle();
582
}
583
584
/*!
585
\reimp
586
*/
587
qint64 QFSFileEngine::read(
char
*data, qint64 maxlen)
588
{
589
Q_D(QFSFileEngine);
590
591
// On Windows' stdlib implementation, the results of calling fread and
592
// fwrite are undefined if not called either in sequence, or if preceded
593
// with a call to fflush().
594
if
(d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
595
flush();
596
d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
597
}
598
599
return
d->nativeRead(data, maxlen);
600
}
601
602
/*!
603
\internal
604
*/
605
qint64 QFSFileEnginePrivate::readFdFh(
char
*data, qint64 len)
606
{
607
Q_Q(QFSFileEngine);
608
609
if
(len < 0 || len != qint64(size_t(len))) {
610
q->setError(QFile::ReadError, QSystemError::stdString(EINVAL));
611
return
-1;
612
}
613
614
qint64 readBytes = 0;
615
bool
eof =
false
;
616
617
if
(fh) {
618
// Buffered stdlib mode.
619
620
size_t result;
621
do
{
622
result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
623
eof = feof(fh);
// Doesn't change errno
624
if
(eof && result == 0) {
625
// On OS X, this is needed, e.g., if a file was written to
626
// through another stream since our last read. See test
627
// tst_QFile::appendAndRead
628
QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET);
// re-sync stream.
629
break
;
630
}
631
readBytes += result;
632
}
while
(!eof && (result == 0 ? errno == EINTR : readBytes < len));
633
634
}
else
if
(fd != -1) {
635
// Unbuffered stdio mode.
636
637
SignedIOType result;
638
do
{
639
// calculate the chunk size
640
// on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
641
// we limit to the size of the signed type, otherwise we could get a negative number as a result
642
quint64 wantedBytes = quint64(len) - quint64(readBytes);
643
UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
644
if
(chunkSize > wantedBytes)
645
chunkSize = wantedBytes;
646
result = QT_READ(fd, data + readBytes, chunkSize);
647
}
while
(result > 0 && (readBytes += result) < len);
648
649
// QT_READ (::read()) returns 0 to indicate end-of-file
650
eof = result == 0;
651
}
652
653
if
(!eof && readBytes == 0) {
654
readBytes = -1;
655
q->setError(QFile::ReadError, QSystemError::stdString(errno));
656
}
657
658
return
readBytes;
659
}
660
661
/*!
662
\reimp
663
*/
664
qint64 QFSFileEngine::readLine(
char
*data, qint64 maxlen)
665
{
666
Q_D(QFSFileEngine);
667
668
// On Windows' stdlib implementation, the results of calling fread and
669
// fwrite are undefined if not called either in sequence, or if preceded
670
// with a call to fflush().
671
if
(d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
672
flush();
673
d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
674
}
675
676
return
d->nativeReadLine(data, maxlen);
677
}
678
679
/*!
680
\internal
681
*/
682
qint64 QFSFileEnginePrivate::readLineFdFh(
char
*data, qint64 maxlen)
683
{
684
Q_Q(QFSFileEngine);
685
if
(!fh)
686
return
q->QAbstractFileEngine::readLine(data, maxlen);
687
688
QT_OFF_T oldPos = 0;
689
#
ifdef
Q_OS_WIN
690
bool
seq = q->isSequential();
691
if
(!seq)
692
#
endif
693
oldPos = QT_FTELL(fh);
694
695
// QIODevice::readLine() passes maxlen - 1 to QFile::readLineData()
696
// because it has made space for the '\0' at the end of data. But fgets
697
// does the same, so we'd get two '\0' at the end - passing maxlen + 1
698
// solves this.
699
if
(!fgets(data,
int
(maxlen + 1), fh)) {
700
if
(!feof(fh))
// Doesn't change errno
701
q->setError(QFile::ReadError, QSystemError::stdString(errno));
702
return
-1;
// error
703
}
704
705
#
ifdef
Q_OS_WIN
706
if
(seq)
707
return
qstrlen(data);
708
#
endif
709
710
qint64 lineLength = QT_FTELL(fh) - oldPos;
711
return
lineLength > 0 ? lineLength : qstrlen(data);
712
}
713
714
/*!
715
\reimp
716
*/
717
qint64 QFSFileEngine::write(
const
char
*data, qint64 len)
718
{
719
Q_D(QFSFileEngine);
720
d->metaData.clearFlags(QFileSystemMetaData::Times);
721
722
// On Windows' stdlib implementation, the results of calling fread and
723
// fwrite are undefined if not called either in sequence, or if preceded
724
// with a call to fflush().
725
if
(d->lastIOCommand != QFSFileEnginePrivate::IOWriteCommand) {
726
flush();
727
d->lastIOCommand = QFSFileEnginePrivate::IOWriteCommand;
728
}
729
730
return
d->nativeWrite(data, len);
731
}
732
733
/*!
734
\internal
735
*/
736
qint64 QFSFileEnginePrivate::writeFdFh(
const
char
*data, qint64 len)
737
{
738
Q_Q(QFSFileEngine);
739
740
if
(len < 0 || len != qint64(size_t(len))) {
741
q->setError(QFile::WriteError, QSystemError::stdString(EINVAL));
742
return
-1;
743
}
744
745
qint64 writtenBytes = 0;
746
747
if
(len) {
// avoid passing nullptr to fwrite() or QT_WRITE() (UB)
748
749
if
(fh) {
750
// Buffered stdlib mode.
751
752
size_t result;
753
do
{
754
result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
755
writtenBytes += result;
756
}
while
(result == 0 ? errno == EINTR : writtenBytes < len);
757
758
}
else
if
(fd != -1) {
759
// Unbuffered stdio mode.
760
761
SignedIOType result;
762
do
{
763
// calculate the chunk size
764
// on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
765
// we limit to the size of the signed type, otherwise we could get a negative number as a result
766
quint64 wantedBytes = quint64(len) - quint64(writtenBytes);
767
UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
768
if
(chunkSize > wantedBytes)
769
chunkSize = wantedBytes;
770
result = QT_WRITE(fd, data + writtenBytes, chunkSize);
771
}
while
(result > 0 && (writtenBytes += result) < len);
772
}
773
774
}
775
776
if
(len && writtenBytes == 0) {
777
writtenBytes = -1;
778
q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
779
QSystemError::stdString(errno));
780
}
else
{
781
// reset the cached size, if any
782
metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
783
}
784
785
return
writtenBytes;
786
}
787
788
#
ifndef
QT_NO_FILESYSTEMITERATOR
789
/*!
790
\internal
791
*/
792
QAbstractFileEngine::IteratorUniquePtr
793
QFSFileEngine::beginEntryList(
const
QString &path, QDirListing::IteratorFlags filters,
794
const
QStringList &filterNames)
795
{
796
return
std::make_unique<QFSFileEngineIterator>(path, filters, filterNames);
797
}
798
#
endif
// QT_NO_FILESYSTEMITERATOR
799
800
/*!
801
\reimp
802
*/
803
bool
QFSFileEngine::isSequential()
const
804
{
805
Q_D(
const
QFSFileEngine);
806
if
(d->is_sequential == 0)
807
d->is_sequential = d->nativeIsSequential() ? 1 : 2;
808
return
d->is_sequential == 1;
809
}
810
811
/*!
812
\internal
813
*/
814
#
ifdef
Q_OS_UNIX
815
bool
QFSFileEnginePrivate::isSequentialFdFh()
const
816
{
817
if
(doStat(QFileSystemMetaData::SequentialType))
818
return
metaData.isSequential();
819
return
true
;
820
}
821
#
endif
822
823
/*!
824
\reimp
825
*/
826
bool
QFSFileEngine::extension(Extension extension,
const
ExtensionOption *option, ExtensionReturn *output)
827
{
828
Q_D(QFSFileEngine);
829
if
(extension == AtEndExtension && d->fh && isSequential())
830
return
feof(d->fh);
831
832
if
(extension == MapExtension) {
833
const
MapExtensionOption *options = (
const
MapExtensionOption*)(option);
834
MapExtensionReturn *returnValue =
static_cast
<MapExtensionReturn*>(output);
835
returnValue->address = d->map(options->offset, options->size, options->flags);
836
return
(returnValue->address !=
nullptr
);
837
}
838
if
(extension == UnMapExtension) {
839
const
UnMapExtensionOption *options = (
const
UnMapExtensionOption*)option;
840
return
d->unmap(options->address);
841
}
842
843
return
false
;
844
}
845
846
/*!
847
\reimp
848
*/
849
bool
QFSFileEngine::supportsExtension(Extension extension)
const
850
{
851
Q_D(
const
QFSFileEngine);
852
if
(extension == AtEndExtension && d->fh && isSequential())
853
return
true
;
854
if
(extension == FastReadLineExtension && d->fh)
855
return
true
;
856
if
(extension == FastReadLineExtension && d->fd != -1 && isSequential())
857
return
true
;
858
if
(extension == UnMapExtension || extension == MapExtension)
859
return
true
;
860
return
false
;
861
}
862
863
/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
864
For Unix, returns the current working directory for the file
865
engine.
866
867
For Windows, returns the canonicalized form of the current path used
868
by the file engine for the drive specified by \a fileName. On
869
Windows, each drive has its own current directory, so a different
870
path is returned for file names that include different drive names
871
(e.g. A: or C:).
872
873
\sa setCurrentPath()
874
*/
875
876
/*! \fn QFileInfoList QFSFileEngine::drives()
877
For Windows, returns the list of drives in the file system as a list
878
of QFileInfo objects. On Unix, only the root path is returned.
879
On Windows, this function returns all drives (A:\, C:\, D:\, and so on).
880
881
For Unix, the list contains just the root path "/".
882
*/
883
884
/*! \fn QString QFSFileEngine::fileName(QAbstractFileEngine::FileName file) const
885
\reimp
886
*/
887
888
/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
889
\reimp
890
*/
891
892
/*! \fn bool QFSFileEngine::isRelativePath() const
893
\reimp
894
*/
895
896
/*! \fn bool QFSFileEngine::link(const QString &newName)
897
898
Creates a link from the file currently specified by fileName() to
899
\a newName. What a link is depends on the underlying filesystem
900
(be it a shortcut on Windows or a symbolic link on Unix). Returns
901
\c true if successful; otherwise returns \c false.
902
903
\note On Windows \a newName is expected to end with .lnk as the filename
904
extension.
905
*/
906
907
908
/*! \fn uint QFSFileEngine::ownerId(QAbstractFileEngine::FileOwner own) const
909
In Unix, if stat() is successful, the \c uid is returned if
910
\a own is the owner. Otherwise the \c gid is returned. If stat()
911
is unsuccessful, -2 is reuturned.
912
913
For Windows, -2 is always returned.
914
*/
915
916
/*! \fn QString QFSFileEngine::owner(QAbstractFileEngine::FileOwner own) const
917
\reimp
918
*/
919
920
/*!
921
For Windows or Apple platforms, copy the file to file \a copyName.
922
923
Not implemented for other Unix platforms.
924
*/
925
bool
QFSFileEngine::copy(
const
QString ©Name)
926
{
927
Q_D(QFSFileEngine);
928
QSystemError error;
929
bool
ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
930
if
(!ret)
931
setError(QFile::CopyError, error.toString());
932
return
ret;
933
}
934
935
/*!
936
\reimp
937
*/
938
bool
QFSFileEngine::remove()
939
{
940
Q_D(QFSFileEngine);
941
QSystemError error;
942
bool
ret = QFileSystemEngine::removeFile(d->fileEntry, error);
943
if
(!ret)
944
setError(QFile::RemoveError, error.toString());
945
else
946
d->metaData.clear();
947
return
ret;
948
}
949
950
/*
951
An alternative to setFileName() when you have already constructed
952
a QFileSystemEntry.
953
*/
954
void
QFSFileEngine::setFileEntry(QFileSystemEntry &&entry)
955
{
956
Q_D(QFSFileEngine);
957
d->init();
958
d->fileEntry = std::move(entry);
959
}
960
961
bool
QFSFileEngine::rename_helper(
const
QString &newName, RenameMode mode)
962
{
963
Q_D(QFSFileEngine);
964
965
auto
func = mode == Rename ? QFileSystemEngine::renameFile
966
: QFileSystemEngine::renameOverwriteFile;
967
QSystemError error;
968
auto
newEntry = QFileSystemEntry(newName);
969
const
bool
ret = func(d->fileEntry, newEntry, error);
970
if
(!ret) {
971
setError(QFile::RenameError, error.toString());
972
return
false
;
973
}
974
setFileEntry(std::move(newEntry));
975
return
true
;
976
}
977
978
/*!
979
\reimp
980
*/
981
bool
QFSFileEngine::mkdir(
const
QString &name,
bool
createParentDirectories,
982
std::optional<QFile::Permissions> permissions)
const
983
{
984
return
QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories,
985
permissions);
986
}
987
988
/*!
989
\reimp
990
*/
991
bool
QFSFileEngine::rmdir(
const
QString &name,
bool
recurseParentDirectories)
const
992
{
993
return
QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
994
}
995
996
997
/*!
998
Sets the current path (e.g., for QDir), to \a path. Returns \c true if the
999
new path exists; otherwise this function does nothing, and returns \c false.
1000
1001
\sa currentPath()
1002
*/
1003
bool
QFSFileEngine::setCurrentPath(
const
QString &path)
1004
{
1005
return
QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
1006
}
1007
1008
/*!
1009
Returns whether the file system considers the file name to be
1010
case sensitive.
1011
*/
1012
bool
QFSFileEngine::caseSensitive()
const
1013
{
1014
Q_D(
const
QFSFileEngine);
1015
return
QFileSystemEngine::isCaseSensitive(d->fileEntry, d->metaData);
1016
}
1017
1018
/*! \fn bool QFSFileEngine::setPermissions(uint perms)
1019
\reimp
1020
*/
1021
1022
/*! \fn bool QFSFileEngine::setSize(qint64 size)
1023
\reimp
1024
*/
1025
1026
/*! \fn QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const
1027
\internal
1028
*/
1029
1030
QT_END_NAMESPACE
1031
1032
#
endif
// QT_NO_FSFILEENGINE
UnsignedIOType
size_t UnsignedIOType
Definition
qfsfileengine.cpp:53
SignedIOType
ssize_t SignedIOType
Definition
qfsfileengine.cpp:52
processOpenModeFlags
ProcessOpenModeResult processOpenModeFlags(QIODevice::OpenMode openMode)
Definition
qfsfileengine.cpp:137
qtbase
src
corelib
io
qfsfileengine.cpp
Generated on
for Qt by
1.18.0