src/corelib/io/qfile.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtCore module of the Qt Toolkit.
     7 ** This file is part of the QtCore module of the Qt Toolkit.
     8 **
     8 **
    60 
    60 
    61 static const int QFILE_WRITEBUFFER_SIZE = 16384;
    61 static const int QFILE_WRITEBUFFER_SIZE = 16384;
    62 
    62 
    63 static QByteArray locale_encode(const QString &f)
    63 static QByteArray locale_encode(const QString &f)
    64 {
    64 {
    65 #ifndef Q_OS_DARWIN
    65 #if defined(Q_OS_DARWIN)
    66     return f.toLocal8Bit();
       
    67 #else
       
    68     // Mac always expects UTF-8... and decomposed...
    66     // Mac always expects UTF-8... and decomposed...
    69     return f.normalized(QString::NormalizationForm_D).toUtf8();
    67     return f.normalized(QString::NormalizationForm_D).toUtf8();
       
    68 #elif defined(Q_OS_SYMBIAN)
       
    69     return f.toUtf8();
       
    70 #else
       
    71     return f.toLocal8Bit();
    70 #endif
    72 #endif
    71 }
    73 }
    72 
    74 
    73 static QString locale_decode(const QByteArray &f)
    75 static QString locale_decode(const QByteArray &f)
    74 {
    76 {
    75 #ifndef Q_OS_DARWIN
    77 #if defined(Q_OS_DARWIN)
    76     return QString::fromLocal8Bit(f);
       
    77 #else
       
    78     // Mac always gives us UTF-8 and decomposed, we want that composed...
    78     // Mac always gives us UTF-8 and decomposed, we want that composed...
    79     return QString::fromUtf8(f).normalized(QString::NormalizationForm_C);
    79     return QString::fromUtf8(f).normalized(QString::NormalizationForm_C);
       
    80 #elif defined(Q_OS_SYMBIAN)
       
    81     return QString::fromUtf8(f);
       
    82 #else
       
    83     return QString::fromLocal8Bit(f);
    80 #endif
    84 #endif
    81 }
    85 }
    82 
    86 
    83 //************* QFilePrivate
    87 //************* QFilePrivate
    84 QFile::EncoderFn QFilePrivate::encoder = locale_encode;
    88 QFile::EncoderFn QFilePrivate::encoder = locale_encode;
    85 QFile::DecoderFn QFilePrivate::decoder = locale_decode;
    89 QFile::DecoderFn QFilePrivate::decoder = locale_decode;
    86 
    90 
    87 QFilePrivate::QFilePrivate()
    91 QFilePrivate::QFilePrivate()
    88     : fileEngine(0), lastWasWrite(false),
    92     : fileEngine(0), lastWasWrite(false),
    89       writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError)
    93       writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError),
       
    94       cachedSize(0)
    90 {
    95 {
    91 }
    96 }
    92 
    97 
    93 QFilePrivate::~QFilePrivate()
    98 QFilePrivate::~QFilePrivate()
    94 {
    99 {
   641     Q_D(QFile);
   646     Q_D(QFile);
   642     if (d->fileName.isEmpty()) {
   647     if (d->fileName.isEmpty()) {
   643         qWarning("QFile::remove: Empty or null file name");
   648         qWarning("QFile::remove: Empty or null file name");
   644         return false;
   649         return false;
   645     }
   650     }
       
   651     unsetError();
   646     close();
   652     close();
   647     if(error() == QFile::NoError) {
   653     if(error() == QFile::NoError) {
   648         if(fileEngine()->remove()) {
   654         if(fileEngine()->remove()) {
   649             unsetError();
   655             unsetError();
   650             return true;
   656             return true;
   651         }
   657         }
   652         d->setError(QFile::RemoveError, fileEngine()->errorString());
   658         d->setError(QFile::RemoveError, d->fileEngine->errorString());
   653     }
   659     }
   654     return false;
   660     return false;
   655 }
   661 }
   656 
   662 
   657 /*!
   663 /*!
   701     close();
   707     close();
   702     if(error() == QFile::NoError) {
   708     if(error() == QFile::NoError) {
   703         if (fileEngine()->rename(newName)) {
   709         if (fileEngine()->rename(newName)) {
   704             unsetError();
   710             unsetError();
   705             // engine was able to handle the new name so we just reset it
   711             // engine was able to handle the new name so we just reset it
   706             fileEngine()->setFileName(newName);
   712             d->fileEngine->setFileName(newName);
   707             d->fileName = newName;
   713             d->fileName = newName;
   708             return true;
   714             return true;
   709         }
   715         }
   710 
   716 
   711         if (isSequential()) {
   717         if (isSequential()) {
   737                     }
   743                     }
   738                 }
   744                 }
   739                 if (error) {
   745                 if (error) {
   740                     out.remove();
   746                     out.remove();
   741                 } else {
   747                 } else {
   742                     fileEngine()->setFileName(newName);
   748                     d->fileEngine->setFileName(newName);
   743                     setPermissions(permissions());
   749                     setPermissions(permissions());
   744                     unsetError();
   750                     unsetError();
   745                     setFileName(newName);
   751                     setFileName(newName);
   746                 }
   752                 }
   747                 close();
   753                 close();
   802     QFileInfo fi(linkName);
   808     QFileInfo fi(linkName);
   803     if(fileEngine()->link(fi.absoluteFilePath())) {
   809     if(fileEngine()->link(fi.absoluteFilePath())) {
   804         unsetError();
   810         unsetError();
   805         return true;
   811         return true;
   806     }
   812     }
   807     d->setError(QFile::RenameError, fileEngine()->errorString());
   813     d->setError(QFile::RenameError, d->fileEngine->errorString());
   808     return false;
   814     return false;
   809 }
   815 }
   810 
   816 
   811 /*!
   817 /*!
   812     \overload
   818     \overload
   966 
   972 
   967     \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite}
   973     \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite}
   968     mode, if the relevant file does not already exist, this function
   974     mode, if the relevant file does not already exist, this function
   969     will try to create a new file before opening it.
   975     will try to create a new file before opening it.
   970 
   976 
   971     \note Because of limitations in the native API, QFile ignores the
       
   972     Unbuffered flag on Windows.
       
   973 
       
   974     \sa QIODevice::OpenMode, setFileName()
   977     \sa QIODevice::OpenMode, setFileName()
   975 */
   978 */
   976 bool QFile::open(OpenMode mode)
   979 bool QFile::open(OpenMode mode)
   977 {
   980 {
   978     Q_D(QFile);
   981     Q_D(QFile);
   986     unsetError();
   989     unsetError();
   987     if ((mode & (ReadOnly | WriteOnly)) == 0) {
   990     if ((mode & (ReadOnly | WriteOnly)) == 0) {
   988         qWarning("QIODevice::open: File access not specified");
   991         qWarning("QIODevice::open: File access not specified");
   989         return false;
   992         return false;
   990     }
   993     }
   991     if (fileEngine()->open(mode)) {
   994 
       
   995     // QIODevice provides the buffering, so there's no need to request it from the file engine.
       
   996     if (fileEngine()->open(mode | QIODevice::Unbuffered)) {
   992         QIODevice::open(mode);
   997         QIODevice::open(mode);
   993         if (mode & Append)
   998         if (mode & Append)
   994             seek(size());
   999             seek(size());
   995         return true;
  1000         return true;
   996     }
  1001     }
   997     QFile::FileError err = fileEngine()->error();
  1002     QFile::FileError err = d->fileEngine->error();
   998     if(err == QFile::UnspecifiedError)
  1003     if(err == QFile::UnspecifiedError)
   999         err = QFile::OpenError;
  1004         err = QFile::OpenError;
  1000     d->setError(err, fileEngine()->errorString());
  1005     d->setError(err, d->fileEngine->errorString());
  1001     return false;
  1006     return false;
  1002 }
  1007 }
  1003 
  1008 
  1004 /*! \fn QFile::open(OpenMode, FILE*)
  1009 /*! \fn QFile::open(OpenMode, FILE*)
  1005 
  1010 
  1150 */
  1155 */
  1151 
  1156 
  1152 int
  1157 int
  1153 QFile::handle() const
  1158 QFile::handle() const
  1154 {
  1159 {
  1155     if (!isOpen())
  1160     Q_D(const QFile);
       
  1161     if (!isOpen() || !d->fileEngine)
  1156         return -1;
  1162         return -1;
  1157 
  1163 
  1158     if (QAbstractFileEngine *engine = fileEngine())
  1164     return d->fileEngine->handle();
  1159         return engine->handle();
       
  1160     return -1;
       
  1161 }
  1165 }
  1162 
  1166 
  1163 /*!
  1167 /*!
  1164     \enum QFile::MemoryMapFlags
  1168     \enum QFile::MemoryMapFlags
  1165     \since 4.4
  1169     \since 4.4
  1187     \sa unmap(), QAbstractFileEngine::supportsExtension()
  1191     \sa unmap(), QAbstractFileEngine::supportsExtension()
  1188  */
  1192  */
  1189 uchar *QFile::map(qint64 offset, qint64 size, MemoryMapFlags flags)
  1193 uchar *QFile::map(qint64 offset, qint64 size, MemoryMapFlags flags)
  1190 {
  1194 {
  1191     Q_D(QFile);
  1195     Q_D(QFile);
  1192     QAbstractFileEngine *engine = fileEngine();
  1196     if (fileEngine()
  1193     if (engine
  1197             && d->fileEngine->supportsExtension(QAbstractFileEngine::MapExtension)) {
  1194         && engine->supportsExtension(QAbstractFileEngine::MapExtension)) {
       
  1195         unsetError();
  1198         unsetError();
  1196         uchar *address = engine->map(offset, size, flags);
  1199         uchar *address = d->fileEngine->map(offset, size, flags);
  1197         if (address == 0)
  1200         if (address == 0)
  1198             d->setError(engine->error(), engine->errorString());
  1201             d->setError(d->fileEngine->error(), d->fileEngine->errorString());
  1199         return address;
  1202         return address;
  1200     }
  1203     }
  1201     return 0;
  1204     return 0;
  1202 }
  1205 }
  1203 
  1206 
  1210     \sa map(), QAbstractFileEngine::supportsExtension()
  1213     \sa map(), QAbstractFileEngine::supportsExtension()
  1211  */
  1214  */
  1212 bool QFile::unmap(uchar *address)
  1215 bool QFile::unmap(uchar *address)
  1213 {
  1216 {
  1214     Q_D(QFile);
  1217     Q_D(QFile);
  1215     QAbstractFileEngine *engine = fileEngine();
  1218     if (fileEngine()
  1216     if (engine
  1219         && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
  1217         && engine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
       
  1218         unsetError();
  1220         unsetError();
  1219         bool success = engine->unmap(address);
  1221         bool success = d->fileEngine->unmap(address);
  1220         if (!success)
  1222         if (!success)
  1221             d->setError(engine->error(), engine->errorString());
  1223             d->setError(d->fileEngine->error(), d->fileEngine->errorString());
  1222         return success;
  1224         return success;
  1223     }
  1225     }
  1224     return false;
  1226     return false;
  1225 }
  1227 }
  1226 
  1228 
  1249 QFile::resize(qint64 sz)
  1251 QFile::resize(qint64 sz)
  1250 {
  1252 {
  1251     Q_D(QFile);
  1253     Q_D(QFile);
  1252     if (!d->ensureFlushed())
  1254     if (!d->ensureFlushed())
  1253         return false;
  1255         return false;
  1254     if (isOpen() && fileEngine()->pos() > sz)
  1256     fileEngine();
       
  1257     if (isOpen() && d->fileEngine->pos() > sz)
  1255         seek(sz);
  1258         seek(sz);
  1256     if(fileEngine()->setSize(sz)) {
  1259     if(d->fileEngine->setSize(sz)) {
  1257         unsetError();
  1260         unsetError();
       
  1261         d->cachedSize = sz;
  1258         return true;
  1262         return true;
  1259     }
  1263     }
  1260     d->setError(QFile::ResizeError, fileEngine()->errorString());
  1264     d->cachedSize = 0;
       
  1265     d->setError(QFile::ResizeError, d->fileEngine->errorString());
  1261     return false;
  1266     return false;
  1262 }
  1267 }
  1263 
  1268 
  1264 /*!
  1269 /*!
  1265     \overload
  1270     \overload
  1319     Q_D(QFile);
  1324     Q_D(QFile);
  1320     if(fileEngine()->setPermissions(permissions)) {
  1325     if(fileEngine()->setPermissions(permissions)) {
  1321         unsetError();
  1326         unsetError();
  1322         return true;
  1327         return true;
  1323     }
  1328     }
  1324     d->setError(QFile::PermissionsError, fileEngine()->errorString());
  1329     d->setError(QFile::PermissionsError, d->fileEngine->errorString());
  1325     return false;
  1330     return false;
  1326 }
  1331 }
  1327 
  1332 
  1328 /*!
  1333 /*!
  1329     \overload
  1334     \overload
  1352 
  1357 
  1353 bool
  1358 bool
  1354 QFile::flush()
  1359 QFile::flush()
  1355 {
  1360 {
  1356     Q_D(QFile);
  1361     Q_D(QFile);
       
  1362     if (!d->fileEngine) {
       
  1363         qWarning("QFile::flush: No file engine. Is IODevice open?");
       
  1364         return false;
       
  1365     }
       
  1366 
  1357     if (!d->writeBuffer.isEmpty()) {
  1367     if (!d->writeBuffer.isEmpty()) {
  1358         qint64 size = d->writeBuffer.size();
  1368         qint64 size = d->writeBuffer.size();
  1359         if (_qfile_writeData(d->fileEngine ? d->fileEngine : fileEngine(),
  1369         if (_qfile_writeData(d->fileEngine, &d->writeBuffer) != size) {
  1360                              &d->writeBuffer) != size) {
  1370             QFile::FileError err = d->fileEngine->error();
  1361             QFile::FileError err = fileEngine()->error();
       
  1362             if(err == QFile::UnspecifiedError)
  1371             if(err == QFile::UnspecifiedError)
  1363                 err = QFile::WriteError;
  1372                 err = QFile::WriteError;
  1364             d->setError(err, fileEngine()->errorString());
  1373             d->setError(err, d->fileEngine->errorString());
  1365             return false;
  1374             return false;
  1366         }
  1375         }
  1367     }
  1376     }
  1368 
  1377 
  1369     if (!fileEngine()->flush()) {
  1378     if (!d->fileEngine->flush()) {
  1370         QFile::FileError err = fileEngine()->error();
  1379         QFile::FileError err = d->fileEngine->error();
  1371         if(err == QFile::UnspecifiedError)
  1380         if(err == QFile::UnspecifiedError)
  1372             err = QFile::WriteError;
  1381             err = QFile::WriteError;
  1373         d->setError(err, fileEngine()->errorString());
  1382         d->setError(err, d->fileEngine->errorString());
  1374         return false;
  1383         return false;
  1375     }
  1384     }
  1376     return true;
  1385     return true;
  1377 }
  1386 }
  1378 
  1387 
  1385 QFile::close()
  1394 QFile::close()
  1386 {
  1395 {
  1387     Q_D(QFile);
  1396     Q_D(QFile);
  1388     if(!isOpen())
  1397     if(!isOpen())
  1389         return;
  1398         return;
  1390     flush();
  1399     bool flushed = flush();
  1391     QIODevice::close();
  1400     QIODevice::close();
  1392 
  1401 
  1393     unsetError();
  1402     // reset write buffer
  1394     if(!fileEngine()->close())
  1403     d->lastWasWrite = false;
  1395         d->setError(fileEngine()->error(), fileEngine()->errorString());
  1404     d->writeBuffer.clear();
       
  1405 
       
  1406     // keep earlier error from flush
       
  1407     if (d->fileEngine->close() && flushed)
       
  1408         unsetError();
       
  1409     else if (flushed)
       
  1410         d->setError(d->fileEngine->error(), d->fileEngine->errorString());
  1396 }
  1411 }
  1397 
  1412 
  1398 /*!
  1413 /*!
  1399   Returns the size of the file.
  1414   Returns the size of the file.
  1400 
  1415 
  1406 qint64 QFile::size() const
  1421 qint64 QFile::size() const
  1407 {
  1422 {
  1408     Q_D(const QFile);
  1423     Q_D(const QFile);
  1409     if (!d->ensureFlushed())
  1424     if (!d->ensureFlushed())
  1410         return 0;
  1425         return 0;
  1411     return fileEngine()->size();
  1426     d->cachedSize = fileEngine()->size();
       
  1427     return d->cachedSize;
  1412 }
  1428 }
  1413 
  1429 
  1414 /*!
  1430 /*!
  1415   \reimp
  1431   \reimp
  1416 */
  1432 */
  1432 
  1448 
  1433 bool QFile::atEnd() const
  1449 bool QFile::atEnd() const
  1434 {
  1450 {
  1435     Q_D(const QFile);
  1451     Q_D(const QFile);
  1436 
  1452 
       
  1453     // If there's buffered data left, we're not at the end.
       
  1454     if (!d->buffer.isEmpty())
       
  1455         return false;
       
  1456 
  1437     if (!isOpen())
  1457     if (!isOpen())
  1438         return true;
  1458         return true;
  1439 
  1459 
  1440     if (!d->ensureFlushed())
  1460     if (!d->ensureFlushed())
  1441         return false;
  1461         return false;
  1442 
  1462 
  1443     // If there's buffered data left, we're not at the end.
       
  1444     if (!d->buffer.isEmpty())
       
  1445         return false;
       
  1446 
       
  1447     // If the file engine knows best, say what it says.
  1463     // If the file engine knows best, say what it says.
  1448     if (fileEngine()->supportsExtension(QAbstractFileEngine::AtEndExtension)) {
  1464     if (d->fileEngine->supportsExtension(QAbstractFileEngine::AtEndExtension)) {
  1449         // Check if the file engine supports AtEndExtension, and if it does,
  1465         // Check if the file engine supports AtEndExtension, and if it does,
  1450         // check if the file engine claims to be at the end.
  1466         // check if the file engine claims to be at the end.
  1451         return fileEngine()->atEnd();
  1467         return d->fileEngine->atEnd();
  1452     }
  1468     }
       
  1469 
       
  1470     // if it looks like we are at the end, or if size is not cached,
       
  1471     // fall through to bytesAvailable() to make sure.
       
  1472     if (pos() < d->cachedSize)
       
  1473         return false;
  1453 
  1474 
  1454     // Fall back to checking how much is available (will stat files).
  1475     // Fall back to checking how much is available (will stat files).
  1455     return bytesAvailable() == 0;
  1476     return bytesAvailable() == 0;
  1456 }
  1477 }
  1457 
  1478 
  1468     }
  1489     }
  1469 
  1490 
  1470     if (!d->ensureFlushed())
  1491     if (!d->ensureFlushed())
  1471         return false;
  1492         return false;
  1472 
  1493 
  1473     if (!fileEngine()->seek(off) || !QIODevice::seek(off)) {
  1494     if (!d->fileEngine->seek(off) || !QIODevice::seek(off)) {
  1474         QFile::FileError err = fileEngine()->error();
  1495         QFile::FileError err = d->fileEngine->error();
  1475         if(err == QFile::UnspecifiedError)
  1496         if(err == QFile::UnspecifiedError)
  1476             err = QFile::PositionError;
  1497             err = QFile::PositionError;
  1477         d->setError(err, fileEngine()->errorString());
  1498         d->setError(err, d->fileEngine->errorString());
  1478         return false;
  1499         return false;
  1479     }
  1500     }
  1480     unsetError();
  1501     unsetError();
  1481     return true;
  1502     return true;
  1482 }
  1503 }
  1488 {
  1509 {
  1489     Q_D(QFile);
  1510     Q_D(QFile);
  1490     if (!d->ensureFlushed())
  1511     if (!d->ensureFlushed())
  1491         return -1;
  1512         return -1;
  1492 
  1513 
  1493     if (fileEngine()->supportsExtension(QAbstractFileEngine::FastReadLineExtension))
  1514     qint64 read;
  1494         return fileEngine()->readLine(data, maxlen);
  1515     if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) {
  1495 
  1516         read = d->fileEngine->readLine(data, maxlen);
  1496     // Fall back to QIODevice's readLine implementation if the engine
  1517     } else {
  1497     // cannot do it faster.
  1518         // Fall back to QIODevice's readLine implementation if the engine
  1498     return QIODevice::readLineData(data, maxlen);
  1519         // cannot do it faster.
       
  1520         read = QIODevice::readLineData(data, maxlen);
       
  1521     }
       
  1522 
       
  1523     if (read < maxlen) {
       
  1524         // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
       
  1525         d->cachedSize = 0;
       
  1526     }
       
  1527 
       
  1528     return read;
  1499 }
  1529 }
  1500 
  1530 
  1501 /*!
  1531 /*!
  1502   \reimp
  1532   \reimp
  1503 */
  1533 */
  1507     Q_D(QFile);
  1537     Q_D(QFile);
  1508     unsetError();
  1538     unsetError();
  1509     if (!d->ensureFlushed())
  1539     if (!d->ensureFlushed())
  1510         return -1;
  1540         return -1;
  1511 
  1541 
  1512     qint64 ret = -1;
  1542     qint64 read = d->fileEngine->read(data, len);
  1513     qint64 read = fileEngine()->read(data, len);
  1543     if(read < 0) {
  1514     if (read != -1)
  1544         QFile::FileError err = d->fileEngine->error();
  1515         ret = read;
       
  1516 
       
  1517     if(ret < 0) {
       
  1518         QFile::FileError err = fileEngine()->error();
       
  1519         if(err == QFile::UnspecifiedError)
  1545         if(err == QFile::UnspecifiedError)
  1520             err = QFile::ReadError;
  1546             err = QFile::ReadError;
  1521         d->setError(err, fileEngine()->errorString());
  1547         d->setError(err, d->fileEngine->errorString());
  1522     }
  1548     }
  1523     return ret;
  1549 
       
  1550     if (read < len) {
       
  1551         // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
       
  1552         d->cachedSize = 0;
       
  1553     }
       
  1554 
       
  1555     return read;
  1524 }
  1556 }
  1525 
  1557 
  1526 /*!
  1558 /*!
  1527     \internal
  1559     \internal
  1528 */
  1560 */
  1598     }
  1630     }
  1599 
  1631 
  1600     // Write directly to the engine if the block size is larger than
  1632     // Write directly to the engine if the block size is larger than
  1601     // the write buffer size.
  1633     // the write buffer size.
  1602     if (!buffered || len > QFILE_WRITEBUFFER_SIZE) {
  1634     if (!buffered || len > QFILE_WRITEBUFFER_SIZE) {
  1603         QAbstractFileEngine *fe = d->fileEngine ? d->fileEngine : fileEngine();
  1635         qint64 ret = d->fileEngine->write(data, len);
  1604         qint64 ret = fe->write(data, len);
       
  1605         if(ret < 0) {
  1636         if(ret < 0) {
  1606             QFile::FileError err = fileEngine()->error();
  1637             QFile::FileError err = d->fileEngine->error();
  1607             if(err == QFile::UnspecifiedError)
  1638             if(err == QFile::UnspecifiedError)
  1608                 err = QFile::WriteError;
  1639                 err = QFile::WriteError;
  1609             d->setError(err, fileEngine()->errorString());
  1640             d->setError(err, d->fileEngine->errorString());
  1610         }
  1641         }
  1611         return ret;
  1642         return ret;
  1612     }
  1643     }
  1613 
  1644 
  1614     // Write to the buffer.
  1645     // Write to the buffer.