123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 | // Copyright (C) 2021 The Qt Company Ltd.// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>// Copyright (C) 2016 Intel Corporation.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qstorageinfo_p.h"#include <QtCore/qfileinfo.h>#include <QtCore/qtextstream.h>#include <QtCore/private/qcore_unix_p.h>#include <QtCore/private/qlocale_tools_p.h>#include <errno.h>#include <sys/stat.h>#if defined(Q_OS_BSD4)# include <sys/mount.h># include <sys/statvfs.h>#elif defined(Q_OS_HURD)# include <mntent.h># include <sys/statvfs.h># include <sys/sysmacros.h>#elif defined(Q_OS_SOLARIS)# include <sys/mnttab.h># include <sys/statvfs.h>#elif defined(Q_OS_HAIKU)# include <Directory.h># include <Path.h># include <Volume.h># include <VolumeRoster.h># include <fs_info.h># include <sys/statvfs.h>#else# include <sys/statvfs.h>#endif#if defined(Q_OS_BSD4)# if defined(Q_OS_NETBSD)# define QT_STATFSBUF struct statvfs# define QT_STATFS ::statvfs# else# define QT_STATFSBUF struct statfs# define QT_STATFS ::statfs# endif# if !defined(ST_RDONLY)# define ST_RDONLY MNT_RDONLY# endif# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD)# define _STATFS_F_FLAGS 1# endif#elif defined(Q_OS_HAIKU) || defined(Q_OS_CYGWIN)# define QT_STATFSBUF struct statvfs# define QT_STATFS ::statvfs#else# if defined(QT_LARGEFILE_SUPPORT)# define QT_STATFSBUF struct statvfs64# define QT_STATFS ::statvfs64# else# define QT_STATFSBUF struct statvfs# define QT_STATFS ::statvfs# endif// QT_LARGEFILE_SUPPORT#endif// Q_OS_BSD4#if __has_include(<paths.h>)# include <paths.h>#endif#ifndef _PATH_MOUNTED# define _PATH_MOUNTED"/etc/mnttab"#endif QT_BEGIN_NAMESPACE using namespaceQt::StringLiterals;class QStorageIterator {public:QStorageIterator();~QStorageIterator();inlineboolisValid()const;inlineboolnext();inline QString rootPath()const;inline QByteArray fileSystemType()const;inline QByteArray device()const;inline QByteArray options()const;inline QByteArray subvolume()const;private:#if defined(Q_OS_BSD4) QT_STATFSBUF *stat_buf;int entryCount;int currentIndex;#elif defined(Q_OS_SOLARIS)FILE*fp; mnttab mnt;#elif defined(Q_OS_HURD)FILE*fp; QByteArray buffer;struct mntent mnt;#elif defined(Q_OS_HAIKU) BVolumeRoster m_volumeRoster; QByteArray m_rootPath; QByteArray m_fileSystemType; QByteArray m_device;#endif};#if defined(Q_OS_BSD4)#ifndef MNT_NOWAIT# define MNT_NOWAIT 0#endifinline QStorageIterator::QStorageIterator():entryCount(::getmntinfo(&stat_buf, MNT_NOWAIT)),currentIndex(-1){}inline QStorageIterator::~QStorageIterator(){}inlineboolQStorageIterator::isValid()const{return entryCount != -1;}inlineboolQStorageIterator::next(){return++currentIndex < entryCount;}inline QString QStorageIterator::rootPath()const{returnQFile::decodeName(stat_buf[currentIndex].f_mntonname);}inline QByteArray QStorageIterator::fileSystemType()const{returnQByteArray(stat_buf[currentIndex].f_fstypename);}inline QByteArray QStorageIterator::device()const{returnQByteArray(stat_buf[currentIndex].f_mntfromname);}inline QByteArray QStorageIterator::options()const{returnQByteArray();}inline QByteArray QStorageIterator::subvolume()const{returnQByteArray();}#elif defined(Q_OS_SOLARIS)inline QStorageIterator::QStorageIterator(){const int fd =qt_safe_open(_PATH_MOUNTED, O_RDONLY); fp = ::fdopen(fd,"r");}inline QStorageIterator::~QStorageIterator(){if(fp)::fclose(fp);}inlineboolQStorageIterator::isValid()const{return fp !=nullptr;}inlineboolQStorageIterator::next(){return::getmntent(fp, &mnt) ==0;}inline QString QStorageIterator::rootPath()const{returnQFile::decodeName(mnt.mnt_mountp);}inline QByteArray QStorageIterator::fileSystemType()const{returnQByteArray(mnt.mnt_fstype);}inline QByteArray QStorageIterator::device()const{returnQByteArray(mnt.mnt_mntopts);}inline QByteArray QStorageIterator::subvolume()const{returnQByteArray();}#elif defined(Q_OS_HURD)static const int bufferSize =1024;// 2 paths (mount point+device) and metainfo;// should be enoughinline QStorageIterator::QStorageIterator() :buffer(QByteArray(bufferSize,0)){ fp = ::setmntent(_PATH_MOUNTED,"r");}inline QStorageIterator::~QStorageIterator(){if(fp)::endmntent(fp);}inlineboolQStorageIterator::isValid()const{return fp !=nullptr;}inlineboolQStorageIterator::next(){return::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) !=nullptr;}inline QString QStorageIterator::rootPath()const{returnQFile::decodeName(mnt.mnt_dir);}inline QByteArray QStorageIterator::fileSystemType()const{returnQByteArray(mnt.mnt_type);}inline QByteArray QStorageIterator::device()const{returnQByteArray(mnt.mnt_fsname);}inline QByteArray QStorageIterator::options()const{returnQByteArray(mnt.mnt_opts);}inline QByteArray QStorageIterator::subvolume()const{returnQByteArray();}#elif defined(Q_OS_HAIKU)inline QStorageIterator::QStorageIterator(){}inline QStorageIterator::~QStorageIterator(){}inlineboolQStorageIterator::isValid()const{return true;}inlineboolQStorageIterator::next(){ BVolume volume;if(m_volumeRoster.GetNextVolume(&volume) != B_OK)return false; BDirectory directory;if(volume.GetRootDirectory(&directory) != B_OK)return false;const BPath path(&directory); fs_info fsInfo;memset(&fsInfo,0,sizeof(fsInfo));if(fs_stat_dev(volume.Device(), &fsInfo) !=0)return false; m_rootPath = path.Path(); m_fileSystemType =QByteArray(fsInfo.fsh_name);const QByteArray deviceName(fsInfo.device_name); m_device = (deviceName.isEmpty() ?QByteArray::number(qint32(volume.Device())) : deviceName);return true;}inline QString QStorageIterator::rootPath()const{returnQFile::decodeName(m_rootPath);}inline QByteArray QStorageIterator::fileSystemType()const{return m_fileSystemType;}inline QByteArray QStorageIterator::device()const{return m_device;}inline QByteArray QStorageIterator::options()const{returnQByteArray();}inline QByteArray QStorageIterator::subvolume()const{returnQByteArray();}#elseinline QStorageIterator::QStorageIterator(){}inline QStorageIterator::~QStorageIterator(){}inlineboolQStorageIterator::isValid()const{return false;}inlineboolQStorageIterator::next(){return false;}inline QString QStorageIterator::rootPath()const{returnQString();}inline QByteArray QStorageIterator::fileSystemType()const{returnQByteArray();}inline QByteArray QStorageIterator::device()const{returnQByteArray();}inline QByteArray QStorageIterator::options()const{returnQByteArray();}inline QByteArray QStorageIterator::subvolume()const{returnQByteArray();}#endifstaticinline QString retrieveLabel(const QByteArray &device){#if defined Q_OS_HAIKU fs_info fsInfo;memset(&fsInfo,0,sizeof(fsInfo)); int32 pos =0; dev_t dev;while((dev =next_dev(&pos)) >=0) {if(fs_stat_dev(dev, &fsInfo) !=0)continue;if(qstrcmp(fsInfo.device_name, device.constData()) ==0)returnQString::fromLocal8Bit(fsInfo.volume_name);}#elseQ_UNUSED(device);#endifreturnQString();}voidQStorageInfoPrivate::doStat(){ valid = ready =false;initRootPath();if(rootPath.isEmpty())return;retrieveVolumeInfo(); name =retrieveLabel(device);}voidQStorageInfoPrivate::retrieveVolumeInfo(){ QT_STATFSBUF statfs_buf;int result;QT_EINTR_LOOP(result,QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf)); valid = ready = (result ==0);if(valid) {#if defined(Q_OS_INTEGRITY) || (defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)) || defined(Q_OS_RTEMS) bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize; bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize; bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize;#else bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize; bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize; bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;#endif blockSize =int(statfs_buf.f_bsize);#if defined(Q_OS_ANDROID) || defined(Q_OS_BSD4) || defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS)#if defined(_STATFS_F_FLAGS) readOnly = (statfs_buf.f_flags & ST_RDONLY) !=0;#endif#else readOnly = (statfs_buf.f_flag & ST_RDONLY) !=0;#endif}}voidQStorageInfoPrivate::initRootPath(){ rootPath =QFileInfo(rootPath).canonicalFilePath();if(rootPath.isEmpty())return; QStorageIterator it;if(!it.isValid()) { rootPath =QStringLiteral("/");return;}int maxLength =0;const QString oldRootPath = rootPath; rootPath.clear();while(it.next()) {const QString mountDir = it.rootPath();const QByteArray fsName = it.fileSystemType();// we try to find most suitable entryif(maxLength < mountDir.size() &&isParentOf(mountDir, oldRootPath)) { maxLength = mountDir.size(); rootPath = mountDir; device = it.device(); fileSystemType = fsName; subvolume = it.subvolume();}}} QList<QStorageInfo>QStorageInfoPrivate::mountedVolumes(){ QStorageIterator it;if(!it.isValid())return QList<QStorageInfo>() <<root(); QList<QStorageInfo> volumes;while(it.next()) {if(!shouldIncludeFs(it.rootPath(), it.fileSystemType()))continue;const QString mountDir = it.rootPath(); QStorageInfo info(mountDir); info.d->device = it.device(); info.d->fileSystemType = it.fileSystemType(); info.d->subvolume = it.subvolume();if(info.bytesTotal() <=0&& info !=root())continue; volumes.append(info);}return volumes;} QT_END_NAMESPACE
|