bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) { const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR); const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600); #ifdef O_CLOEXEC // First try with O_CLOEXEC flag, if that fails, fall back to normal flags EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode)); if (hand == -1) EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag, omode)); #else EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag, omode)); #endif if (hand == -1) { const int errorNumber = errno; const QLatin1String function("QSharedMemory::attach (shm_open)"); switch (errorNumber) { case ENAMETOOLONG: case EINVAL: errorString = QSharedMemory::tr("%1: bad name").arg(function); error = QSharedMemory::KeyError; break; default: setErrorString(function); } hand = -1; return false; } // grab the size QT_STATBUF st; if (QT_FSTAT(hand, &st) == -1) { setErrorString(QLatin1String("QSharedMemory::attach (fstat)")); cleanHandle(); return false; } size = st.st_size; // grab the memory const int mprot = (mode == QSharedMemory::ReadOnly ? PROT_READ : PROT_READ | PROT_WRITE); memory = QT_MMAP(0, size, mprot, MAP_SHARED, hand, 0); if (memory == MAP_FAILED || !memory) { setErrorString(QLatin1String("QSharedMemory::attach (mmap)")); cleanHandle(); memory = 0; size = 0; return false; } #ifdef F_ADD_SEALS // Make sure the shared memory region will not shrink // otherwise someone could cause SIGBUS on us. // (see http://lwn.net/Articles/594919/) fcntl(hand, F_ADD_SEALS, F_SEAL_SHRINK); #endif return true; }
void QWSSharedMemory::detach() { #ifndef QT_POSIX_IPC if (shmBase && shmBase != (void*)-1) shmdt(shmBase); #else if (shmBase && shmBase != (void*)-1) munmap(shmBase, shmSize); if (hand > 0) { // get the number of current attachments int shm_nattch = 0; QT_STATBUF st; if (QT_FSTAT(hand, &st) == 0) { // subtract 2 from linkcount: one for our own open and one for the dir entry shm_nattch = st.st_nlink - 2; } qt_safe_close(hand); // if there are no attachments then unlink the shared memory if (shm_nattch == 0) { QByteArray shmName = makeKey(shmId); shm_unlink(shmName.constData()); } } #endif shmBase = 0; shmSize = 0; shmId = -1; }
bool QFSFileEnginePrivate::doStat() const { if (tried_stat == 0) { QFSFileEnginePrivate *that = const_cast<QFSFileEnginePrivate*>(this); if (fh && nativeFilePath.isEmpty()) { // ### actually covers two cases: d->fh and when the file is not open that->could_stat = (QT_FSTAT(fileno(fh), &st) == 0); } else if (fd == -1) { // ### actually covers two cases: d->fh and when the file is not open that->could_stat = (QT_STAT(nativeFilePath.constData(), &st) == 0); } else { that->could_stat = (QT_FSTAT(fd, &st) == 0); } that->tried_stat = 1; } return could_stat; }
bool QWSSharedMemory::create(int size) { if (shmId != -1) detach(); #ifndef QT_POSIX_IPC shmId = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); #else // ### generate really unique IDs shmId = (getpid() << 16) + (localUniqueId.fetchAndAddRelaxed(1) % ushort(-1)); QByteArray shmName = makeKey(shmId); EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR | O_CREAT, 0660)); if (hand != -1) { // the size may only be set once; ignore errors int ret; EINTR_LOOP(ret, ftruncate(hand, size)); if (ret == -1) shmId = -1; } else { shmId = -1; } #endif if (shmId == -1) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::create():"); qWarning("Error allocating shared memory of size %d", size); #endif detach(); return false; } #ifndef QT_POSIX_IPC shmBase = shmat(shmId, 0, 0); // On Linux, it is possible to attach a shared memory segment even if it // is already marked to be deleted. However, POSIX.1-2001 does not specify // this behaviour and many other implementations do not support it. shmctl(shmId, IPC_RMID, 0); #else // grab the size QT_STATBUF st; if (QT_FSTAT(hand, &st) != -1) { shmSize = st.st_size; // grab the memory shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0); } #endif if (shmBase == (void*)-1 || !shmBase) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::create():"); qWarning("Error attaching to shared memory id %d", shmId); #endif detach(); return false; } return true; }
/*! \internal */ qint64 QFSFileEnginePrivate::sizeFdFh() const { Q_Q(const QFSFileEngine); // ### Fix this function, it should not stat unless the file is closed. QT_STATBUF st; int ret = 0; const_cast<QFSFileEngine *>(q)->flush(); if (fh && nativeFilePath.isEmpty()) { // Buffered stdlib mode. // ### This should really be an ftell ret = QT_FSTAT(QT_FILENO(fh), &st); } else if (fd == -1) { // Stateless stat. ret = QT_STAT(nativeFilePath.constData(), &st); } else { // Unbuffered stdio mode. ret = QT_FSTAT(fd, &st); } if (ret == -1) return 0; return st.st_size; }
//static bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) { data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags; data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags; QT_STATBUF statBuffer; if (QT_FSTAT(fd, &statBuffer) == 0) { data.fillFromStatBuf(statBuffer); return true; } return false; }
bool QSharedMemoryPrivate::detach() { // detach from the memory segment if (::munmap(memory, size) == -1) { setErrorString(QLatin1String("QSharedMemory::detach (munmap)")); return false; } memory = 0; size = 0; #ifdef Q_OS_QNX // On QNX the st_nlink field of struct stat contains the number of // active shm_open() connections to the shared memory file, so we // can use it to automatically clean up the file once the last // user has detached from it. // get the number of current attachments int shm_nattch = 0; QT_STATBUF st; if (QT_FSTAT(hand, &st) == 0) { // subtract 2 from linkcount: one for our own open and one for the dir entry shm_nattch = st.st_nlink - 2; } cleanHandle(); // if there are no attachments then unlink the shared memory if (shm_nattch == 0) { const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT) setErrorString(QLatin1String("QSharedMemory::detach (shm_unlink)")); } #else // On non-QNX systems (tested Linux and Haiku), the st_nlink field is always 1, // so we'll simply leak the shared memory files. cleanHandle(); #endif return true; }
bool QWSSharedMemory::attach(int id) { if (shmId == id) return id != -1; detach(); if (id == -1) return false; shmId = id; #ifndef QT_POSIX_IPC shmBase = shmat(shmId, 0, 0); #else QByteArray shmName = makeKey(shmId); EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR, 0660)); if (hand != -1) { // grab the size QT_STATBUF st; if (QT_FSTAT(hand, &st) != -1) { shmSize = st.st_size; // grab the memory shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0); } } #endif if (shmBase == (void*)-1 || !shmBase) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::attach():"); qWarning("Error attaching to shared memory id %d", shmId); #endif detach(); return false; } return true; }
bool registerSelf(const QString &f) { bool fromMM = false; uchar *data = 0; unsigned int data_len = 0; #ifdef QT_USE_MMAP #ifndef MAP_FILE #define MAP_FILE 0 #endif #ifndef MAP_FAILED #define MAP_FAILED -1 #endif int fd = QT_OPEN(QFile::encodeName(f), O_RDONLY, #if defined(Q_OS_WIN) _S_IREAD | _S_IWRITE #else 0666 #endif ); if (fd >= 0) { QT_STATBUF st; if (!QT_FSTAT(fd, &st)) { uchar *ptr; ptr = reinterpret_cast<uchar *>( mmap(0, st.st_size, // any address, whole file PROT_READ, // read-only memory MAP_FILE | MAP_PRIVATE, // swap-backed map from file fd, 0)); // from offset 0 of fd if (ptr && ptr != reinterpret_cast<uchar *>(MAP_FAILED)) { data = ptr; data_len = st.st_size; fromMM = true; } } ::close(fd); } #endif // QT_USE_MMAP if(!data) { QFile file(f); if (!file.exists()) return false; data_len = file.size(); data = new uchar[data_len]; bool ok = false; if (file.open(QIODevice::ReadOnly)) ok = (data_len == (uint)file.read((char*)data, data_len)); if (!ok) { delete [] data; data = 0; data_len = 0; return false; } fromMM = false; } if(data && QDynamicBufferResourceRoot::registerSelf(data)) { if(fromMM) { unmapPointer = data; unmapLength = data_len; } fileName = f; return true; } return false; }
bool QTranslator::load(const QString & filename, const QString & directory, const QString & search_delimiters, const QString & suffix) { Q_D(QTranslator); d->clear(); QString prefix; if (QFileInfo(filename).isRelative()) { prefix = directory; if (prefix.length() && !prefix.endsWith(QLatin1Char('/'))) prefix += QLatin1Char('/'); } QString fname = filename; QString realname; QString delims; delims = search_delimiters.isNull() ? QString::fromLatin1("_.") : search_delimiters; for (;;) { QFileInfo fi; realname = prefix + fname + (suffix.isNull() ? QString::fromLatin1(".qm") : suffix); fi.setFile(realname); if (fi.isReadable() && fi.isFile()) break; realname = prefix + fname; fi.setFile(realname); if (fi.isReadable() && fi.isFile()) break; int rightmost = 0; for (int i = 0; i < (int)delims.length(); i++) { int k = fname.lastIndexOf(delims[i]); if (k > rightmost) rightmost = k; } // no truncations? fail if (rightmost == 0) return false; fname.truncate(rightmost); } // realname is now the fully qualified name of a readable file. bool ok = false; #ifdef QT_USE_MMAP #ifndef MAP_FILE #define MAP_FILE 0 #endif #ifndef MAP_FAILED #define MAP_FAILED -1 #endif int fd = -1; if (!realname.startsWith(QLatin1Char(':'))) fd = QT_OPEN(QFile::encodeName(realname), O_RDONLY, #if defined(Q_OS_WIN) _S_IREAD | _S_IWRITE #else 0666 #endif ); if (fd >= 0) { QT_STATBUF st; if (!QT_FSTAT(fd, &st)) { char *ptr; ptr = reinterpret_cast<char *>( mmap(0, st.st_size, // any address, whole file PROT_READ, // read-only memory MAP_FILE | MAP_PRIVATE, // swap-backed map from file fd, 0)); // from offset 0 of fd if (ptr && ptr != reinterpret_cast<char *>(MAP_FAILED)) { d->used_mmap = true; d->unmapPointer = ptr; d->unmapLength = st.st_size; ok = true; } } ::close(fd); } #endif // QT_USE_MMAP if (!ok) { QFile file(realname); d->unmapLength = file.size(); if (!d->unmapLength) return false; d->unmapPointer = new char[d->unmapLength]; if (file.open(QIODevice::ReadOnly)) ok = (d->unmapLength == (uint)file.read(d->unmapPointer, d->unmapLength)); if (!ok) { delete [] d->unmapPointer; d->unmapPointer = 0; d->unmapLength = 0; return false; } } return d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength); }
QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEngine *fontEngine) : fd(fileDescriptor), renderingFontEngine(fontEngine) { fontData = 0; dataSize = 0; fontDef = def; cache_cost = 100; freetype = 0; externalCMap = 0; cmapOffset = 0; cmapSize = 0; glyphMapOffset = 0; glyphMapEntries = 0; glyphDataOffset = 0; glyphDataSize = 0; kerning_pairs_loaded = false; readOnly = true; #if defined(DEBUG_FONTENGINE) qDebug() << "QFontEngineQPF::QFontEngineQPF( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ")"; #endif if (fd < 0) { if (!renderingFontEngine) return; fileName = fontDef.family.toLower() + QLatin1String("_") + QString::number(fontDef.pixelSize) + QLatin1String("_") + QString::number(fontDef.weight) + (fontDef.style != QFont::StyleNormal ? QLatin1String("_italic") : QLatin1String("")) + QLatin1String(".qsf"); fileName.replace(QLatin1Char(' '), QLatin1Char('_')); fileName.prepend(qws_fontCacheDir()); const QByteArray encodedName = QFile::encodeName(fileName); if (::access(encodedName, F_OK) == 0) { #if defined(DEBUG_FONTENGINE) qDebug() << "found existing qpf:" << fileName; #endif if (::access(encodedName, W_OK | R_OK) == 0) fd = ::open(encodedName, O_RDWR); else if (::access(encodedName, R_OK) == 0) fd = ::open(encodedName, O_RDONLY); } else { #if defined(DEBUG_FONTENGINE) qDebug() << "creating qpf on the fly:" << fileName; #endif if (::access(QFile::encodeName(qws_fontCacheDir()), W_OK) == 0) { fd = ::open(encodedName, O_RDWR | O_EXCL | O_CREAT, 0644); QBuffer buffer; buffer.open(QIODevice::ReadWrite); QPFGenerator generator(&buffer, renderingFontEngine); generator.generate(); buffer.close(); const QByteArray &data = buffer.data(); ::write(fd, data.constData(), data.size()); } } } QT_STATBUF st; if (QT_FSTAT(fd, &st)) { #if defined(DEBUG_FONTENGINE) qDebug() << "stat failed!"; #endif return; } dataSize = st.st_size; fontData = (const uchar *)::mmap(0, st.st_size, PROT_READ | (renderingFontEngine ? PROT_WRITE : 0), MAP_SHARED, fd, 0); if (!fontData || fontData == (const uchar *)MAP_FAILED) { #if defined(DEBUG_FONTENGINE) perror("mmap failed"); #endif fontData = 0; return; } if (!verifyHeader(fontData, st.st_size)) { #if defined(DEBUG_FONTENGINE) qDebug() << "verifyHeader failed!"; #endif return; } const Header *header = reinterpret_cast<const Header *>(fontData); readOnly = (header->lock == 0xffffffff); const uchar *data = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize); const uchar *endPtr = fontData + dataSize; while (data <= endPtr - 8) { quint16 blockTag = readValue<quint16>(data); data += 2; // skip padding quint32 blockSize = readValue<quint32>(data); if (blockTag == CMapBlock) { cmapOffset = data - fontData; cmapSize = blockSize; } else if (blockTag == GMapBlock) { glyphMapOffset = data - fontData; glyphMapEntries = blockSize / 4; } else if (blockTag == GlyphBlock) { glyphDataOffset = data - fontData; glyphDataSize = blockSize; } data += blockSize; } face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString()); face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt(); #if !defined(QT_NO_FREETYPE) freetype = QFreetypeFace::getFace(face_id); if (!freetype) { QString newPath = #ifndef QT_NO_SETTINGS QLibraryInfo::location(QLibraryInfo::LibrariesPath) + #endif QLatin1String("/fonts/") + QFileInfo(QFile::decodeName(face_id.filename)).fileName(); face_id.filename = QFile::encodeName(newPath); freetype = QFreetypeFace::getFace(face_id); } if (freetype) { const quint32 qpfTtfRevision = extractHeaderField(fontData, Tag_FontRevision).toUInt(); uchar data[4]; uint length = 4; bool ok = freetype->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'), data, &length); if (!ok || length != 4 || qFromBigEndian<quint32>(data) != qpfTtfRevision) { freetype->release(face_id); freetype = 0; } } if (!cmapOffset && freetype) { freetypeCMapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); externalCMap = reinterpret_cast<const uchar *>(freetypeCMapTable.constData()); cmapSize = freetypeCMapTable.size(); } #endif // get the real cmap if (cmapOffset) { int tableSize = cmapSize; const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize); if (cmapPtr) cmapOffset = cmapPtr - fontData; else cmapOffset = 0; } else if (externalCMap) { int tableSize = cmapSize; externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize); } // verify all the positions in the glyphMap if (glyphMapOffset) { const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset); for (uint i = 0; i < glyphMapEntries; ++i) { quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]); if (glyphDataPos == 0xffffffff) continue; if (glyphDataPos >= glyphDataSize) { // error glyphMapOffset = 0; glyphMapEntries = 0; break; } } } #if defined(DEBUG_FONTENGINE) if (!isValid()) qDebug() << "fontData" << fontData << "dataSize" << dataSize << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset << "fd" << fd << "glyphDataSize" << glyphDataSize; #endif #if defined(Q_WS_QWS) if (isValid() && renderingFontEngine) qt_fbdpy->sendFontCommand(QWSFontCommand::StartedUsingFont, QFile::encodeName(fileName)); #endif }
QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) { QStringList p = paths; { QMutexLocker locker(&mutex); QMutableListIterator<QString> it(p); while (it.hasNext()) { QString path = it.next(); int fd; #if defined(O_EVTONLY) fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY); #else fd = qt_safe_open(QFile::encodeName(path), O_RDONLY); #endif if (fd == -1) { perror("QKqueueFileSystemWatcherEngine::addPaths: open"); continue; } if (fd >= (int)FD_SETSIZE / 2 && fd < (int)FD_SETSIZE) { int fddup = fcntl(fd, F_DUPFD, FD_SETSIZE); if (fddup != -1) { ::close(fd); fd = fddup; } } fcntl(fd, F_SETFD, FD_CLOEXEC); QT_STATBUF st; if (QT_FSTAT(fd, &st) == -1) { perror("QKqueueFileSystemWatcherEngine::addPaths: fstat"); ::close(fd); continue; } int id = (S_ISDIR(st.st_mode)) ? -fd : fd; if (id < 0) { if (directories->contains(path)) { ::close(fd); continue; } } else { if (files->contains(path)) { ::close(fd); continue; } } struct kevent kev; EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0); if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { perror("QKqueueFileSystemWatcherEngine::addPaths: kevent"); ::close(fd); continue; } it.remove(); if (id < 0) { DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path; directories->append(path); } else { DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path; files->append(path); } pathToID.insert(path, id); idToPath.insert(id, path); } } if (!isRunning()) start(); else write(kqpipe[1], "@", 1); return p; }
bool QTranslatorPrivate::do_load(const QString &realname) { QTranslatorPrivate *d = this; bool ok = false; const bool isResourceFile = realname.startsWith(QLatin1Char(':')); if (isResourceFile) { // If the translation is in a non-compressed resource file, the data is already in // memory, so no need to use QFile to copy it again. Q_ASSERT(!d->resource); d->resource = new QResource(realname); if (d->resource->isValid() && !d->resource->isCompressed()) { d->unmapLength = d->resource->size(); d->unmapPointer = reinterpret_cast<char *>(const_cast<uchar *>(d->resource->data())); d->used_mmap = false; ok = true; } else { delete d->resource; d->resource = 0; } } #ifdef QT_USE_MMAP #ifndef MAP_FILE #define MAP_FILE 0 #endif #ifndef MAP_FAILED #define MAP_FAILED -1 #endif else { int fd = QT_OPEN(QFile::encodeName(realname), O_RDONLY, #if defined(Q_OS_WIN) _S_IREAD | _S_IWRITE #else 0666 #endif ); if (fd >= 0) { QT_STATBUF st; if (!QT_FSTAT(fd, &st)) { char *ptr; ptr = reinterpret_cast<char *>( mmap(0, st.st_size, // any address, whole file PROT_READ, // read-only memory MAP_FILE | MAP_PRIVATE, // swap-backed map from file fd, 0)); // from offset 0 of fd if (ptr && ptr != reinterpret_cast<char *>(MAP_FAILED)) { d->used_mmap = true; d->unmapPointer = ptr; d->unmapLength = st.st_size; ok = true; } } ::close(fd); } } #endif // QT_USE_MMAP if (!ok) { QFile file(realname); d->unmapLength = file.size(); if (!d->unmapLength) return false; d->unmapPointer = new char[d->unmapLength]; if (file.open(QIODevice::ReadOnly)) ok = (d->unmapLength == (uint)file.read(d->unmapPointer, d->unmapLength)); if (!ok) { delete [] d->unmapPointer; d->unmapPointer = 0; d->unmapLength = 0; return false; } } return d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength); }