Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qstorageinfo_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
3// Copyright (C) 2016 Intel Corporation.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5// Qt-Security score:significant reason:default
6
8
9#include <QtCore/qfileinfo.h>
10#include <QtCore/qtextstream.h>
11
12#include <QtCore/private/qcore_unix_p.h>
13#include <QtCore/private/qlocale_tools_p.h>
14
15#include <errno.h>
16#include <sys/stat.h>
17
18#if defined(Q_OS_BSD4)
19# include <sys/mount.h>
20# include <sys/statvfs.h>
21#elif defined(Q_OS_HURD)
22# include <mntent.h>
23# include <sys/statvfs.h>
24# include <sys/sysmacros.h>
25#elif defined(Q_OS_SOLARIS)
26# include <sys/mnttab.h>
27# include <sys/statvfs.h>
28#elif defined(Q_OS_HAIKU)
29# include <Directory.h>
30# include <Path.h>
31# include <Volume.h>
32# include <VolumeRoster.h>
33# include <fs_info.h>
34# include <sys/statvfs.h>
35#else
36# include <sys/statvfs.h>
37#endif
38
39#if defined(Q_OS_BSD4)
40# if defined(Q_OS_NETBSD)
41# define QT_STATFSBUF struct statvfs
42# define QT_STATFS ::statvfs
43# else
44# define QT_STATFSBUF struct statfs
45# define QT_STATFS ::statfs
46# endif
47
48# if !defined(ST_RDONLY)
49# define ST_RDONLY MNT_RDONLY
50# endif
51# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD)
52# define _STATFS_F_FLAGS 1
53# endif
54#elif defined(Q_OS_HAIKU) || defined(Q_OS_CYGWIN)
55# define QT_STATFSBUF struct statvfs
56# define QT_STATFS ::statvfs
57#else
58# if defined(QT_LARGEFILE_SUPPORT)
59# define QT_STATFSBUF struct statvfs64
60# define QT_STATFS ::statvfs64
61# else
62# define QT_STATFSBUF struct statvfs
63# define QT_STATFS ::statvfs
64# endif // QT_LARGEFILE_SUPPORT
65#endif // Q_OS_BSD4
66
67#if __has_include(<paths.h>)
68# include <paths.h>
69#endif
70#ifndef _PATH_MOUNTED
71# define _PATH_MOUNTED "/etc/mnttab"
72#endif
73
74QT_BEGIN_NAMESPACE
75
76using namespace Qt::StringLiterals;
77
79{
80public:
83
84 inline bool isValid() const;
85 inline bool next();
86 inline QString rootPath() const;
87 inline QByteArray fileSystemType() const;
88 inline QByteArray device() const;
89 inline QByteArray options() const;
90 inline QByteArray subvolume() const;
91private:
92#if defined(Q_OS_BSD4)
94 int entryCount;
95 int currentIndex;
96#elif defined(Q_OS_SOLARIS)
97 FILE *fp;
98 mnttab mnt;
99#elif defined(Q_OS_HURD)
100 FILE *fp;
102 struct mntent mnt;
103#elif defined(Q_OS_HAIKU)
105
109#endif
110};
111
112#if defined(Q_OS_BSD4)
113
114#ifndef MNT_NOWAIT
115# define MNT_NOWAIT 0
116#endif
117
118inline QStorageIterator::QStorageIterator()
119 : entryCount(::getmntinfo(&stat_buf, MNT_NOWAIT)),
120 currentIndex(-1)
121{
122}
123
124inline QStorageIterator::~QStorageIterator()
125{
126}
127
128inline bool QStorageIterator::isValid() const
129{
130 return entryCount != -1;
131}
132
133inline bool QStorageIterator::next()
134{
135 return ++currentIndex < entryCount;
136}
137
138inline QString QStorageIterator::rootPath() const
139{
140 return QFile::decodeName(stat_buf[currentIndex].f_mntonname);
141}
142
143inline QByteArray QStorageIterator::fileSystemType() const
144{
145 return QByteArray(stat_buf[currentIndex].f_fstypename);
146}
147
148inline QByteArray QStorageIterator::device() const
149{
150 return QByteArray(stat_buf[currentIndex].f_mntfromname);
151}
152
153inline QByteArray QStorageIterator::options() const
154{
155 return QByteArray();
156}
157
158inline QByteArray QStorageIterator::subvolume() const
159{
160 return QByteArray();
161}
162#elif defined(Q_OS_SOLARIS)
163
164inline QStorageIterator::QStorageIterator()
165{
166 const int fd = qt_safe_open(_PATH_MOUNTED, O_RDONLY);
167 fp = ::fdopen(fd, "r");
168}
169
170inline QStorageIterator::~QStorageIterator()
171{
172 if (fp)
173 ::fclose(fp);
174}
175
176inline bool QStorageIterator::isValid() const
177{
178 return fp != nullptr;
179}
180
181inline bool QStorageIterator::next()
182{
183 return ::getmntent(fp, &mnt) == 0;
184}
185
186inline QString QStorageIterator::rootPath() const
187{
188 return QFile::decodeName(mnt.mnt_mountp);
189}
190
191inline QByteArray QStorageIterator::fileSystemType() const
192{
193 return QByteArray(mnt.mnt_fstype);
194}
195
196inline QByteArray QStorageIterator::device() const
197{
198 return QByteArray(mnt.mnt_mntopts);
199}
200
201inline QByteArray QStorageIterator::subvolume() const
202{
203 return QByteArray();
204}
205
206#elif defined(Q_OS_HURD)
207
208static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo;
209 // should be enough
210
211inline QStorageIterator::QStorageIterator() :
212 buffer(QByteArray(bufferSize, 0))
213{
214 fp = ::setmntent(_PATH_MOUNTED, "r");
215}
216
217inline QStorageIterator::~QStorageIterator()
218{
219 if (fp)
220 ::endmntent(fp);
221}
222
223inline bool QStorageIterator::isValid() const
224{
225 return fp != nullptr;
226}
227
228inline bool QStorageIterator::next()
229{
230 return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != nullptr;
231}
232
233inline QString QStorageIterator::rootPath() const
234{
235 return QFile::decodeName(mnt.mnt_dir);
236}
237
238inline QByteArray QStorageIterator::fileSystemType() const
239{
240 return QByteArray(mnt.mnt_type);
241}
242
243inline QByteArray QStorageIterator::device() const
244{
245 return QByteArray(mnt.mnt_fsname);
246}
247
248inline QByteArray QStorageIterator::options() const
249{
250 return QByteArray(mnt.mnt_opts);
251}
252
253inline QByteArray QStorageIterator::subvolume() const
254{
255 return QByteArray();
256}
257#elif defined(Q_OS_HAIKU)
258inline QStorageIterator::QStorageIterator()
259{
260}
261
262inline QStorageIterator::~QStorageIterator()
263{
264}
265
266inline bool QStorageIterator::isValid() const
267{
268 return true;
269}
270
271inline bool QStorageIterator::next()
272{
273 BVolume volume;
274
275 if (m_volumeRoster.GetNextVolume(&volume) != B_OK)
276 return false;
277
278 BDirectory directory;
279 if (volume.GetRootDirectory(&directory) != B_OK)
280 return false;
281
282 const BPath path(&directory);
283
284 fs_info fsInfo;
285 memset(&fsInfo, 0, sizeof(fsInfo));
286
287 if (fs_stat_dev(volume.Device(), &fsInfo) != 0)
288 return false;
289
290 m_rootPath = path.Path();
291 m_fileSystemType = QByteArray(fsInfo.fsh_name);
292
293 const QByteArray deviceName(fsInfo.device_name);
294 m_device = (deviceName.isEmpty() ? QByteArray::number(qint32(volume.Device())) : deviceName);
295
296 return true;
297}
298
299inline QString QStorageIterator::rootPath() const
300{
301 return QFile::decodeName(m_rootPath);
302}
303
304inline QByteArray QStorageIterator::fileSystemType() const
305{
306 return m_fileSystemType;
307}
308
309inline QByteArray QStorageIterator::device() const
310{
311 return m_device;
312}
313
314inline QByteArray QStorageIterator::options() const
315{
316 return QByteArray();
317}
318
319inline QByteArray QStorageIterator::subvolume() const
320{
321 return QByteArray();
322}
323
324#else
325
329
333
334inline bool QStorageIterator::isValid() const
335{
336 return false;
337}
338
339inline bool QStorageIterator::next()
340{
341 return false;
342}
343
345{
346 return QString();
347}
348
350{
351 return QByteArray();
352}
353
355{
356 return QByteArray();
357}
358
360{
361 return QByteArray();
362}
363
365{
366 return QByteArray();
367}
368#endif
369
370static inline QString retrieveLabel(const QByteArray &device)
371{
372#if defined Q_OS_HAIKU
373 fs_info fsInfo;
374 memset(&fsInfo, 0, sizeof(fsInfo));
375
376 int32 pos = 0;
377 dev_t dev;
378 while ((dev = next_dev(&pos)) >= 0) {
379 if (fs_stat_dev(dev, &fsInfo) != 0)
380 continue;
381
382 if (qstrcmp(fsInfo.device_name, device.constData()) == 0)
383 return QString::fromLocal8Bit(fsInfo.volume_name);
384 }
385#else
386 Q_UNUSED(device);
387#endif
388
389 return QString();
390}
391
392void QStorageInfoPrivate::doStat()
393{
394 valid = ready = false;
395 initRootPath();
396 if (rootPath.isEmpty())
397 return;
398
399 retrieveVolumeInfo();
400 name = retrieveLabel(device);
401}
402
403void QStorageInfoPrivate::retrieveVolumeInfo()
404{
405 QT_STATFSBUF statfs_buf;
406 int result;
407 QT_EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
408 valid = ready = (result == 0);
409 if (valid) {
410#if defined(Q_OS_INTEGRITY) || (defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)) || defined(Q_OS_RTEMS)
411 bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize;
412 bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize;
413 bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize;
414#else
415 bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize;
416 bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
417 bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
418#endif
419 blockSize = int(statfs_buf.f_bsize);
420#if defined(Q_OS_ANDROID) || defined(Q_OS_BSD4) || defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS)
421#if defined(_STATFS_F_FLAGS)
422 readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
423#endif
424#else
425 readOnly = (statfs_buf.f_flag & ST_RDONLY) != 0;
426#endif
427 }
428}
429
430void QStorageInfoPrivate::initRootPath()
431{
432 rootPath = QFileInfo(rootPath).canonicalFilePath();
433
434 if (rootPath.isEmpty())
435 return;
436
437 QStorageIterator it;
438 if (!it.isValid()) {
439 rootPath = QStringLiteral("/");
440 return;
441 }
442
443 int maxLength = 0;
444 const QString oldRootPath = rootPath;
445 rootPath.clear();
446
447 while (it.next()) {
448 const QString mountDir = it.rootPath();
449 const QByteArray fsName = it.fileSystemType();
450 // we try to find most suitable entry
451 if (maxLength < mountDir.size() && isParentOf(mountDir, oldRootPath)) {
452 maxLength = mountDir.size();
453 rootPath = mountDir;
454 device = it.device();
455 fileSystemType = fsName;
456 subvolume = it.subvolume();
457 }
458 }
459}
460
461QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
462{
463 QStorageIterator it;
464 if (!it.isValid())
465 return QList<QStorageInfo>() << root();
466
467 QList<QStorageInfo> volumes;
468
469 while (it.next()) {
470 if (!shouldIncludeFs(it.rootPath(), it.fileSystemType()))
471 continue;
472
473 const QString mountDir = it.rootPath();
474 QStorageInfo info(mountDir);
475 info.d->device = it.device();
476 info.d->fileSystemType = it.fileSystemType();
477 info.d->subvolume = it.subvolume();
478 if (info.bytesTotal() <= 0 && info != root())
479 continue;
480 volumes.append(info);
481 }
482
483 return volumes;
484}
485
486QT_END_NAMESPACE
QByteArray device() const
QByteArray subvolume() const
QString rootPath() const
QByteArray options() const
QByteArray fileSystemType() const
#define __has_include(x)
#define ST_RDONLY
#define QT_STATFS
#define QT_STATFSBUF
#define _PATH_MOUNTED
static QString retrieveLabel(const QByteArray &device)