1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // Copyright (C) 2015 Ivan Komissarov <ABBAPOH@gmail.com> |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #include "qstorageinfo.h" |
6 | #include "qstorageinfo_p.h" |
7 | |
8 | #include "qdebug.h" |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | QT_IMPL_METATYPE_EXTERN(QStorageInfo) |
13 | |
14 | /*! |
15 | \class QStorageInfo |
16 | \inmodule QtCore |
17 | \since 5.4 |
18 | \brief Provides information about currently mounted storage and drives. |
19 | |
20 | \ingroup io |
21 | \ingroup shared |
22 | |
23 | \compares equality |
24 | |
25 | Allows retrieving information about the volume's space, its mount point, |
26 | label, and filesystem name. |
27 | |
28 | You can create an instance of QStorageInfo by passing the path to the |
29 | volume's mount point as a constructor parameter, or you can set it using |
30 | the setPath() method. The static mountedVolumes() method can be used to get the |
31 | list of all mounted filesystems. |
32 | |
33 | QStorageInfo always caches the retrieved information, but you can call |
34 | refresh() to invalidate the cache. |
35 | |
36 | The following example retrieves the most common information about the root |
37 | volume of the system, and prints information about it. |
38 | |
39 | \snippet code/src_corelib_io_qstorageinfo.cpp 2 |
40 | */ |
41 | |
42 | QStorageInfo::QStorageInfo(QStorageInfoPrivate &dd) |
43 | : d(&dd) |
44 | { |
45 | } |
46 | |
47 | /*! |
48 | Constructs an empty QStorageInfo object. |
49 | |
50 | Objects created with the default constructor will be invalid and therefore |
51 | not ready for use. |
52 | |
53 | \sa setPath(), isReady(), isValid() |
54 | */ |
55 | QStorageInfo::QStorageInfo() |
56 | : d(new QStorageInfoPrivate) |
57 | { |
58 | } |
59 | |
60 | /*! |
61 | Constructs a new QStorageInfo object that gives information about the volume |
62 | mounted at \a path. |
63 | |
64 | If you pass a directory or file, the QStorageInfo object will refer to the |
65 | volume where this directory or file is located. |
66 | You can check if the created object is correct using the isValid() method. |
67 | |
68 | The following example shows how to get the volume on which the application is |
69 | located. It is recommended to always check that the volume is ready and valid. |
70 | |
71 | \snippet code/src_corelib_io_qstorageinfo.cpp 0 |
72 | |
73 | \sa setPath() |
74 | */ |
75 | QStorageInfo::QStorageInfo(const QString &path) |
76 | : d(new QStorageInfoPrivate) |
77 | { |
78 | setPath(path); |
79 | } |
80 | |
81 | /*! |
82 | Constructs a new QStorageInfo object that gives information about the volume |
83 | containing the \a dir folder. |
84 | */ |
85 | QStorageInfo::QStorageInfo(const QDir &dir) |
86 | : d(new QStorageInfoPrivate) |
87 | { |
88 | setPath(dir.absolutePath()); |
89 | } |
90 | |
91 | /*! |
92 | Constructs a new QStorageInfo object that is a copy of the \a other QStorageInfo object. |
93 | */ |
94 | QStorageInfo::QStorageInfo(const QStorageInfo &other) |
95 | : d(other.d) |
96 | { |
97 | } |
98 | |
99 | /*! |
100 | Destroys the QStorageInfo object and frees its resources. |
101 | */ |
102 | QStorageInfo::~QStorageInfo() |
103 | { |
104 | } |
105 | |
106 | /*! |
107 | Makes a copy of the QStorageInfo object \a other and assigns it to this QStorageInfo object. |
108 | */ |
109 | QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other) |
110 | { |
111 | d = other.d; |
112 | return *this; |
113 | } |
114 | |
115 | /*! |
116 | \fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other) |
117 | |
118 | Assigns \a other to this QStorageInfo instance. |
119 | */ |
120 | |
121 | /*! |
122 | \fn void QStorageInfo::swap(QStorageInfo &other) |
123 | \memberswap{volume info} |
124 | */ |
125 | |
126 | /*! |
127 | Sets this QStorageInfo object to the filesystem mounted where \a path is located. |
128 | |
129 | \a path can either be a root path of the filesystem, a directory, or a file |
130 | within that filesystem. |
131 | |
132 | \sa rootPath() |
133 | */ |
134 | void QStorageInfo::setPath(const QString &path) |
135 | { |
136 | if (d->rootPath == path) |
137 | return; |
138 | d.detach(); |
139 | d->rootPath = path; |
140 | d->doStat(); |
141 | } |
142 | |
143 | /*! |
144 | Returns the mount point of the filesystem this QStorageInfo object |
145 | represents. |
146 | |
147 | On Windows, it returns the volume letter in case the volume is not mounted to |
148 | a directory. |
149 | |
150 | Note that the value returned by rootPath() is the real mount point of a |
151 | volume, and may not be equal to the value passed to the constructor or setPath() |
152 | method. For example, if you have only the root volume in the system, and |
153 | pass '/directory' to setPath(), then this method will return '/'. |
154 | |
155 | \sa setPath(), device() |
156 | */ |
157 | QString QStorageInfo::rootPath() const |
158 | { |
159 | return d->rootPath; |
160 | } |
161 | |
162 | /*! |
163 | Returns the size (in bytes) available for the current user. It returns |
164 | the total size available if the user is the root user or a system administrator. |
165 | |
166 | This size can be less than or equal to the free size returned by |
167 | bytesFree() function. |
168 | |
169 | Returns -1 if QStorageInfo object is not valid. |
170 | |
171 | \sa bytesTotal(), bytesFree() |
172 | */ |
173 | qint64 QStorageInfo::bytesAvailable() const |
174 | { |
175 | return d->bytesAvailable; |
176 | } |
177 | |
178 | /*! |
179 | Returns the number of free bytes in a volume. Note that if there are |
180 | quotas on the filesystem, this value can be larger than the value |
181 | returned by bytesAvailable(). |
182 | |
183 | Returns -1 if QStorageInfo object is not valid. |
184 | |
185 | \sa bytesTotal(), bytesAvailable() |
186 | */ |
187 | qint64 QStorageInfo::bytesFree() const |
188 | { |
189 | return d->bytesFree; |
190 | } |
191 | |
192 | /*! |
193 | Returns the total volume size in bytes. |
194 | |
195 | Returns -1 if QStorageInfo object is not valid. |
196 | |
197 | \sa bytesFree(), bytesAvailable() |
198 | */ |
199 | qint64 QStorageInfo::bytesTotal() const |
200 | { |
201 | return d->bytesTotal; |
202 | } |
203 | |
204 | /*! |
205 | \since 5.6 |
206 | Returns the optimal transfer block size for this filesystem. |
207 | |
208 | Returns -1 if QStorageInfo could not determine the size or if the QStorageInfo |
209 | object is not valid. |
210 | */ |
211 | int QStorageInfo::blockSize() const |
212 | { |
213 | return d->blockSize; |
214 | } |
215 | |
216 | /*! |
217 | Returns the type name of the filesystem. |
218 | |
219 | This is a platform-dependent function, and filesystem names can vary |
220 | between different operating systems. For example, on Windows filesystems |
221 | they can be named \c NTFS, and on Linux they can be named \c ntfs-3g or \c fuseblk. |
222 | |
223 | \sa name() |
224 | */ |
225 | QByteArray QStorageInfo::fileSystemType() const |
226 | { |
227 | return d->fileSystemType; |
228 | } |
229 | |
230 | /*! |
231 | Returns the device for this volume. |
232 | |
233 | For example, on Unix filesystems (including \macos), this returns the |
234 | devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC |
235 | path starting with \c \\\\?\\ for local storages (in other words, the volume GUID). |
236 | |
237 | \sa rootPath(), subvolume() |
238 | */ |
239 | QByteArray QStorageInfo::device() const |
240 | { |
241 | return d->device; |
242 | } |
243 | |
244 | /*! |
245 | \since 5.9 |
246 | Returns the subvolume name for this volume. |
247 | |
248 | Some filesystem types allow multiple subvolumes inside one device, which |
249 | may be mounted in different paths (e.g. 'bind' mounts on Unix, or Btrfs |
250 | filesystem subvolumes). If the subvolume could be detected, its name is |
251 | returned by this function. The format of the subvolume name is specific |
252 | to each filesystem type. |
253 | |
254 | If this volume was not mounted from a subvolume of a larger filesystem or |
255 | if the subvolume could not be detected, this function returns an empty byte |
256 | array. |
257 | |
258 | \sa device() |
259 | */ |
260 | QByteArray QStorageInfo::subvolume() const |
261 | { |
262 | return d->subvolume; |
263 | } |
264 | |
265 | /*! |
266 | Returns the human-readable name of a filesystem, usually called \c label. |
267 | |
268 | Not all filesystems support this feature. In this case, the value returned by |
269 | this method could be empty. An empty string is returned if the file system |
270 | does not support labels, or if no label is set. |
271 | |
272 | On Linux, retrieving the volume's label requires \c udev to be present in the |
273 | system. |
274 | |
275 | \sa fileSystemType() |
276 | */ |
277 | QString QStorageInfo::name() const |
278 | { |
279 | return d->name; |
280 | } |
281 | |
282 | /*! |
283 | Returns the volume's name, if available, or the root path if not. |
284 | */ |
285 | QString QStorageInfo::displayName() const |
286 | { |
287 | if (!d->name.isEmpty()) |
288 | return d->name; |
289 | return d->rootPath; |
290 | } |
291 | |
292 | /*! |
293 | \fn bool QStorageInfo::isRoot() const |
294 | |
295 | Returns true if this QStorageInfo represents the system root volume; false |
296 | otherwise. |
297 | |
298 | On Unix filesystems, the root volume is a volume mounted on \c /. On Windows, |
299 | the root volume is the volume where the OS is installed. |
300 | |
301 | \sa root() |
302 | */ |
303 | |
304 | /*! |
305 | Returns true if the current filesystem is protected from writing; false |
306 | otherwise. |
307 | */ |
308 | bool QStorageInfo::isReadOnly() const |
309 | { |
310 | return d->readOnly; |
311 | } |
312 | |
313 | /*! |
314 | Returns true if the current filesystem is ready to work; false otherwise. For |
315 | example, false is returned if the CD volume is not inserted. |
316 | |
317 | Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and |
318 | bytesAvailable() will return invalid data until the volume is ready. |
319 | |
320 | \sa isValid() |
321 | */ |
322 | bool QStorageInfo::isReady() const |
323 | { |
324 | return d->ready; |
325 | } |
326 | |
327 | /*! |
328 | Returns true if the QStorageInfo specified by rootPath exists and is mounted |
329 | correctly. |
330 | |
331 | \sa isReady() |
332 | */ |
333 | bool QStorageInfo::isValid() const |
334 | { |
335 | return d->valid; |
336 | } |
337 | |
338 | /*! |
339 | Resets QStorageInfo's internal cache. |
340 | |
341 | QStorageInfo caches information about storage to speed up performance. |
342 | QStorageInfo retrieves information during object construction and/or when calling |
343 | the setPath() method. You have to manually reset the cache by calling this |
344 | function to update storage information. |
345 | */ |
346 | void QStorageInfo::refresh() |
347 | { |
348 | d.detach(); |
349 | d->doStat(); |
350 | } |
351 | |
352 | /*! |
353 | Returns the list of QStorageInfo objects that corresponds to the list of currently |
354 | mounted filesystems. |
355 | |
356 | On Windows, this returns the drives visible in the \gui{My Computer} folder. On Unix |
357 | operating systems, it returns the list of all mounted filesystems (except for |
358 | pseudo filesystems). |
359 | |
360 | Returns all currently mounted filesystems by default. |
361 | |
362 | The example shows how to retrieve all available filesystems, skipping read-only ones. |
363 | |
364 | \snippet code/src_corelib_io_qstorageinfo.cpp 1 |
365 | |
366 | \sa root() |
367 | */ |
368 | QList<QStorageInfo> QStorageInfo::mountedVolumes() |
369 | { |
370 | return QStorageInfoPrivate::mountedVolumes(); |
371 | } |
372 | |
373 | Q_GLOBAL_STATIC(QStorageInfo, getRoot, QStorageInfoPrivate::root()) |
374 | |
375 | /*! |
376 | Returns a QStorageInfo object that represents the system root volume. |
377 | |
378 | On Unix systems this call returns the root ('/') volume; in Windows the volume where |
379 | the operating system is installed. |
380 | |
381 | \sa isRoot() |
382 | */ |
383 | QStorageInfo QStorageInfo::root() |
384 | { |
385 | return *getRoot(); |
386 | } |
387 | |
388 | /*! |
389 | \fn bool QStorageInfo::operator==(const QStorageInfo &lhs, const QStorageInfo &rhs) |
390 | |
391 | Returns \c true if the QStorageInfo object \a lhs refers to the same drive or |
392 | volume as the QStorageInfo object \a rhs; otherwise it returns \c false. |
393 | |
394 | Note that the result of comparing two invalid QStorageInfo objects is always |
395 | positive. |
396 | */ |
397 | |
398 | /*! |
399 | \fn bool QStorageInfo::operator!=(const QStorageInfo &lhs, const QStorageInfo &rhs) |
400 | |
401 | Returns \c true if the QStorageInfo object \a lhs refers to a different drive or |
402 | volume than the QStorageInfo object \a rhs; otherwise returns \c false. |
403 | */ |
404 | |
405 | bool comparesEqual(const QStorageInfo &lhs, const QStorageInfo &rhs) noexcept |
406 | { |
407 | if (lhs.d == rhs.d) |
408 | return true; |
409 | return lhs.d->device == rhs.d->device && lhs.d->rootPath == rhs.d->rootPath; |
410 | } |
411 | |
412 | #ifndef QT_NO_DEBUG_STREAM |
413 | QDebug operator<<(QDebug debug, const QStorageInfo &s) |
414 | { |
415 | QDebugStateSaver saver(debug); |
416 | debug.nospace(); |
417 | debug.noquote(); |
418 | debug << "QStorageInfo(" ; |
419 | if (s.isValid()) { |
420 | const QStorageInfoPrivate *d = s.d.constData(); |
421 | debug << '"' << d->rootPath << '"'; |
422 | if (!d->fileSystemType.isEmpty()) |
423 | debug << ", type=" << d->fileSystemType; |
424 | if (!d->name.isEmpty()) |
425 | debug << ", name=\"" << d->name << '"'; |
426 | if (!d->device.isEmpty()) |
427 | debug << ", device=\"" << d->device << '"'; |
428 | if (!d->subvolume.isEmpty()) |
429 | debug << ", subvolume=\"" << d->subvolume << '"'; |
430 | if (d->readOnly) |
431 | debug << " [read only]" ; |
432 | debug << (d->ready ? " [ready]" : " [not ready]" ); |
433 | if (d->bytesTotal > 0) { |
434 | debug << ", bytesTotal=" << d->bytesTotal << ", bytesFree=" << d->bytesFree |
435 | << ", bytesAvailable=" << d->bytesAvailable; |
436 | } |
437 | } else { |
438 | debug << "invalid" ; |
439 | } |
440 | debug << ')'; |
441 | return debug; |
442 | } |
443 | #endif // !QT_NO_DEBUG_STREAM |
444 | |
445 | QT_END_NAMESPACE |
446 | |