QResource: quick refactor of registerSelf for files to support LFS

This commit adds sufficient support for large files in resources, but
not completely because the rest Qt is not ready for it (and not
tested). We've had the QT_MMAP macro in qplatformdefs.h for a while, so
let's use it and use qsizetype where we can.

This also the check that the file existed before opening it (you can
only open it if it exists), plus a few nullptr updates.

Change-Id: I42a48bd64ccc41aebf84fffd15653ffdabb0e66b
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Thiago Macieira 2018-11-08 12:26:46 -08:00
parent 9ee29b826c
commit 12e843581a

View File

@ -68,6 +68,11 @@
# include "private/qcore_unix_p.h" # include "private/qcore_unix_p.h"
#endif #endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
# include <sys/mman.h>
#endif
//#define DEBUG_RESOURCE_MATCH //#define DEBUG_RESOURCE_MATCH
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -969,7 +974,7 @@ public:
ResourceRootType type() const override { return Resource_Buffer; } ResourceRootType type() const override { return Resource_Buffer; }
// size == -1 means "unknown" // size == -1 means "unknown"
bool registerSelf(const uchar *b, int size) bool registerSelf(const uchar *b, qsizetype size)
{ {
// 5 int "pointers" // 5 int "pointers"
if (size >= 0 && size < 20) if (size >= 0 && size < 20)
@ -1010,28 +1015,12 @@ public:
} }
}; };
#if defined(Q_OS_UNIX) && !defined (Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
#define QT_USE_MMAP
#endif
// most of the headers below are already included in qplatformdefs.h
// also this lacks Large File support but that's probably irrelevant
#if defined(QT_USE_MMAP)
// for mmap
QT_BEGIN_INCLUDE_NAMESPACE
#include <sys/mman.h>
#include <errno.h>
QT_END_INCLUDE_NAMESPACE
#endif
class QDynamicFileResourceRoot: public QDynamicBufferResourceRoot class QDynamicFileResourceRoot: public QDynamicBufferResourceRoot
{ {
QString fileName; QString fileName;
// for mmap'ed files, this is what needs to be unmapped. // for mmap'ed files, this is what needs to be unmapped.
uchar *unmapPointer; uchar *unmapPointer;
unsigned int unmapLength; qsizetype unmapLength;
public: public:
inline QDynamicFileResourceRoot(const QString &_root) : QDynamicBufferResourceRoot(_root), unmapPointer(0), unmapLength(0) { } inline QDynamicFileResourceRoot(const QString &_root) : QDynamicBufferResourceRoot(_root), unmapPointer(0), unmapLength(0) { }
@ -1057,14 +1046,14 @@ public:
# define MAP_FILE 0 # define MAP_FILE 0
#endif #endif
#ifndef MAP_FAILED #ifndef MAP_FAILED
# define MAP_FAILED -1 # define MAP_FAILED reinterpret_cast<void *>(-1)
#endif #endif
bool QDynamicFileResourceRoot::registerSelf(const QString &f) bool QDynamicFileResourceRoot::registerSelf(const QString &f)
{ {
bool fromMM = false; bool fromMM = false;
uchar *data = 0; uchar *data = nullptr;
unsigned int data_len = 0; qsizetype data_len = 0;
#ifdef QT_USE_MMAP #ifdef QT_USE_MMAP
int fd = QT_OPEN(QFile::encodeName(f), O_RDONLY, int fd = QT_OPEN(QFile::encodeName(f), O_RDONLY,
@ -1076,35 +1065,35 @@ bool QDynamicFileResourceRoot::registerSelf(const QString &f)
); );
if (fd >= 0) { if (fd >= 0) {
QT_STATBUF st; QT_STATBUF st;
if (!QT_FSTAT(fd, &st)) { if (!QT_FSTAT(fd, &st) && st.st_size <= std::numeric_limits<qsizetype>::max()) {
uchar *ptr; int protection = PROT_READ; // read-only memory
ptr = reinterpret_cast<uchar *>( int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
mmap(0, st.st_size, // any address, whole file void *ptr = QT_MMAP(nullptr, st.st_size, // any address, whole file
PROT_READ, // read-only memory protection, flags,
MAP_FILE | MAP_PRIVATE, // swap-backed map from file fd, 0); // from offset 0 of fd
fd, 0)); // from offset 0 of fd if (ptr != MAP_FAILED) {
if (ptr && ptr != reinterpret_cast<uchar *>(MAP_FAILED)) { data = static_cast<uchar *>(ptr);
data = ptr;
data_len = st.st_size; data_len = st.st_size;
fromMM = true; fromMM = true;
} }
} }
::close(fd); QT_CLOSE(fd);
} }
#endif // QT_USE_MMAP #endif // QT_USE_MMAP
if (!data) { if (!data) {
QFile file(f); QFile file(f);
if (!file.exists()) bool ok = false;
return false; if (file.open(QIODevice::ReadOnly)) {
qint64 fsize = file.size();
if (fsize <= std::numeric_limits<qsizetype>::max()) {
data_len = file.size(); data_len = file.size();
data = new uchar[data_len]; data = new uchar[data_len];
ok = (data_len == file.read((char*)data, data_len));
bool ok = false; }
if (file.open(QIODevice::ReadOnly)) }
ok = (data_len == (uint)file.read((char*)data, data_len));
if (!ok) { if (!ok) {
delete [] data; delete [] data;
data = 0; data = nullptr;
data_len = 0; data_len = 0;
return false; return false;
} }