I need to get specifications of hard disk on both Win and *nix machines. I used <hdreg.h> on Linux like this:
static struct hd_driveid hd;
int device;
if ((device = open("/dev/sda", O_RDONLY | O_NONBLOCK)) < 0)
{
cerr << "ERROR: Cannot open device /dev/sda \n";
exit(1);
}
if (!ioctl(device, HDIO_GET_IDENTITY, &hd))
{
cout << hd.model << endl;
cout << hd.serial_no << endl;
cout << hd.heads << endl;
}
I need hd_driveid to tell me some more information about disk. I want to know:
Number of partitions
Specifications of each partition (format, label, flags, size, start point, number of tracks etc.)
Number of tracks per cylinder
Number of total tracks
Maximum block size
Minimum Block size
Default block size
Total size of device
My questions are:
Is there a common
(platform-independent) way to
connect hardware? I would like use
same code for win and *nix. (even if
there was no way other than
embedding assembly code into cpp)
If there isn't, how do I get above information in *nix?
Nearly everything in your list has nothing to do with "specifications of hard disk":
The number of partitions depends on reading the partition table, and if you have any extended partitions, the partition tables of those partitions. The OS will usually do this bit for you when the device driver loads.
Partition information (namely the volume label) typically isn't available in the partition table. You need to guess the file system type and parse the file system header. The only thing in the partition table is the "type" byte, which doesn't tell you all that much, and the start/size.
Hard drives won't give you "real" CHS information. Additionally, the CHS information that the drive provides is "wrong" from the point of view of the BIOS (the BIOS does its own fudging).
Hard drives have a fixed sector size, which you can get with hd_driveid.sector_bytes (usually 512, but some modern drives use 4096). I'm not aware of a maximum "block size", which is a property of the filesystem. I'm also not sure why this is useful.
The total size in sectors is in hd_driveid.lba_capacity_2. Additionally, the size in bytes can probably be obtained with something like
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
#include <unistd.h>
...
off_t size_in_bytes = lseek(device, 0, SEEK_END);
if (size_in_bytes == (off_t)-1) { ... error, error code in ERRNO ... }
Note that in both cases, it'll probably be a few megabytes bigger than sizes calculated by C×H×S.
It might help if you told us why you wanted this information...
//-------------------------------------------------
// Without Boost LIB usage
//-------------------------------------------------
#include <sys/statvfs.h>
#include <sys/sysinfo.h>
//-------------------------------------------------
stringstream strStream;
unsigned long hdd_size;
unsigned long hdd_free;
ostringstream strConvert;
//---
struct sysinfo info;
sysinfo( &info );
//---
struct statvfs fsinfo;
statvfs("/", &fsinfo);
//---
//---
unsigned num_cpu = std::thread::hardware_concurrency();
//---
ifstream cpu_freq("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq");
strStream << cpu_freq.rdbuf();
std::string cpufrequency = strStream.str();
//---
strStream.str("");
ifstream cpu_temp("/sys/class/thermal/thermal_zone0/temp");
strStream << cpu_temp.rdbuf();
strConvert<< fixed << setprecision(2) << std::stof(strStream.str());
std::string cputemp = strConvert.str();
//---
std::string mem_size = to_string( (size_t)info.totalram * (size_t)info.mem_unit );
//---
hdd_size = fsinfo.f_frsize * fsinfo.f_blocks;
hdd_free = fsinfo.f_bsize * fsinfo.f_bfree;
//---
std::cout << "CPU core number ==" << num_cpu << endl;
std::cout << "CPU core speed ==" << cpufrequency << endl;
std::cout << "CPU temperature (C) ==" << cputemp << endl;
//---
std::cout << "Memory size ==" << mem_size << endl;
//---
std::cout << "Disk, filesystem size ==" << hdd_size << endl;
std::cout << "Disk free space ==" << hdd_free << endl;
//---
No, there is no platform-independent way. There is even no *nix way. There is just Linux way.
In Linux, all relevant information is available in various files in the /proc filesystem. The /proc/devices will tell you what devices there are (the files in /dev/ may exist even when the devices are not available, though opening them will fail in that case), /proc/partitions will tell you what partitions are available on each disk and than you'll have to look in the various subdirectories for the information. Just look around on some linux system where is what you need.
For GNU/Linux have a look at this: obtaining hard disk metadata
//Piece of code working for me with Boost LIB usage
//-----------------------------------------------------
#include <sys/sysinfo.h>
#include <boost/filesystem.hpp>
//---
using namespace boost::filesystem;
//---
struct sysinfo info;
sysinfo( &info );
//---
space_info si = space(".");
//---
unsigned num_cpu = std::thread::hardware_concurrency();
//---
ifstream cpu_freq("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq");
ifstream cpu_temp("/sys/class/thermal/thermal_zone0/temp");
//---
std::string cpunumber = to_string(num_cpu);
std::string cpufrequency = cpu_freq.str();
std::string cputemp = cpu_temp.str();
std::string mem_size = to_string( (size_t)info.totalram * (size_t)info.mem_unit );
std::string disk_available = to_string(si.available);
std::string fslevel = to_string( (si.available/si.capacity)*100 );
//---
Related
The need is to access S.M.A.R.T. data (Self-Monitoring, Analysis and Reporting Technology) for a storage diagnostic tool.
From Wikipedia:
S.M.A.R.T. (Self-Monitoring, Analysis and Reporting Technology; often
written as SMART) is a monitoring system included in computer hard
disk drives (HDDs), solid-state drives (SSDs),1 and eMMC drives. Its
primary function is to detect and report various indicators of drive
reliability with the intent of anticipating imminent hardware
failures.
When S.M.A.R.T. data indicates a possible imminent drive failure,
software running on the host system may notify the user so
preventative action can be taken to prevent data loss, and the failing
drive can be replaced and data integrity maintained.
However, I could not find any relevant information about how to retrieve those values from a disk programmatically.
Note: Even if the question is tagged IOKit, it would run in user-mode (not a driver), but could require root privileges if needed.
Following is a sample code to list disk connected to the PC (Not production-ready):
#include <iostream>
#include <string.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOMedia.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFString.h>
using namespace std;
static void printPairs (const void* key, const void* value, void* context) {
CFShow(key);
CFShow(value);
}
int main()
{
// create matching dictionary
CFMutableDictionaryRef classesToMatch;
classesToMatch = IOServiceMatching(kIOMediaClass);
if (!classesToMatch) cout << "Error: IOServiceMathing failed" << endl;
// get iterator of matching services
io_iterator_t mediaIterator;
kern_return_t kernResult;
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault,classesToMatch,&mediaIterator);
if (KERN_SUCCESS != kernResult) cout << "Error: IOServiceGetMatchingService failed" << endl;
// Iterate medias
io_object_t nextMedia;
while ( (nextMedia = IOIteratorNext(mediaIterator)) )
{
CFMutableDictionaryRef dict = nullptr;
kernResult = IORegistryEntryCreateCFProperties(
nextMedia,&dict, kCFAllocatorDefault, 0);
if (KERN_SUCCESS != kernResult) cout << "Error: IORegistryEntryCreateCFProperties failed" << endl;
CFNumberRef objWhole = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, CFSTR("Whole")));
CFNumberRef objRaid = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, CFSTR("RAID")));
int64_t whole = 0;
CFNumberGetValue(objWhole, kCFNumberSInt64Type, &whole);
// skip partitions
if (objWhole && whole)
{
io_name_t name;
IORegistryEntryGetName(nextMedia, name);
cout << "=============" << name << "============" << endl;
CFDictionaryApplyFunction(dict, printPairs, nullptr);
// PRINT SMART HERE
cout << endl;
}
// clean-up
CFRelease(dict);
IOObjectRelease(nextMedia);
}
IOObjectRelease(mediaIterator);
}
I'm working on what will be a pretty large and complicated system and trying to make sure it's as watertight as possible right from the start. Whilst running some memory checks, I noticed something odd when using stringstreams: they don't always seem to release all the memory when they get deleted/go out of scope.
I've tried searching the internet for answers, but most are old (so possibly out of date) and/or are more concerned with refreshing the contents than releasing the memory, so I've not really been able to tell if it's a known issue or a common mistake I'm making.
I've written a simple test to show what's going on:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
float getMemUsage(int& pid)
{
if (pid < 0)
pid = getpid();
char buf[30];
snprintf(buf, 30, "/proc/%u/statm", (unsigned)pid);
FILE* pf = fopen(buf, "r");
if (pf)
{
unsigned size; // total program size
//unsigned resident;// resident set size
//unsigned share;// shared pages
//unsigned text;// text (code)
//unsigned lib;// library
//unsigned data;// data/stack
//unsigned dt;// dirty pages (unused in Linux 2.6)
fscanf(pf, "%u" /* %u %u %u %u %u"*/, &size/*, &resident, &share, &text, &lib, &data*/);
fclose(pf);
return size/1024.0;
}
else
return -1.0;
}
int main(int argc, char* argv[])
{
if (argc < 2)
cerr << "no file specified\n";
ifstream file;
file.open(argv[1]);
int pid = -1;
const float memUseAtStart = getMemUsage(pid);
{
float memUseBefore = getMemUsage(pid);
stringstream sstream;
float memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after stringstream declaration: " << memUseAfter - memUseBefore << endl;
memUseBefore = getMemUsage(pid);
filebuf* pbuf = file.rdbuf();
memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after getting file buffer: " << memUseAfter - memUseBefore << endl;
memUseBefore = getMemUsage(pid);
sstream << pbuf;
memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after copying file contents: " << memUseAfter - memUseBefore << endl;
memUseBefore = getMemUsage(pid);
sstream.clear();
sstream.str( string() );
memUseAfter = getMemUsage(pid);
cerr << "\tMemory use change after 'clearing': " << memUseAfter - memUseBefore << endl;
}
cerr << "Overall memory use change: " << getMemUsage(pid) - memUseAtStart << endl;
file.close();
return 0;
}
Which gives me the following output when called with a file larger than around 32K:
Memory use change after stringstream declaration: 0
Memory use change after getting file buffer: 0
Memory use change after copying file contents: 0.0322266
Memory use change after 'clearing': 0
Overall memory use change: 0.00195312
I'm running on Linux (SL6.6) and compiling with gcc 4.1.2 (though I've also tried clang and ICC with similar results).
Obviously, it's not a huge leak; it's just a little annoying that I can't make it completely tidy... Is there something I can/should do to release the memory manually? Or is it just something weird (with my setup and/or stringstream itself) I'll have to live with?
NB The intended use for the stringstream is to read in some file contents above and then parse them line by line; I would try using istringstream but I couldn't figure out how to set its value from the ifstream...
Thanks!
I'm trying to make some experiments on disk I/O using cache and not using it. In order to perform a read directly from the disk, I open the file with the O_DIRECT flag (defining the variable DISK_DIRECT).
Now the two branches of the if beneath, should perform the same operation, with the difference that one is helped by the cache and the other not.
The files to which I try to access are stored on disk and they do not change over time.
Also the two branches access to the same files.
At some point here, when I use fread I get ferror() to be true. While when I use read everything goes fine.
I'm sure they access the same files.
Do you have any idea why this could happen?
EDIT
Ok, i'm posting here an minimal example. the code i use is:
#include <iostream>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <sstream>
using namespace std;
typedef float fftwf_complex [2] ;
void fetch_level(unsigned long long tid, unsigned short level, fftwf_complex* P_read, fftwf_complex* P_fread, int n_coeff_per_level, FILE** files_o_direct, fstream* & files) {
int b_read;
fseek(files_o_direct[level],(long int) (tid * sizeof(fftwf_complex)*n_coeff_per_level), SEEK_SET);
b_read = fread(reinterpret_cast<char*>(P_fread),sizeof(fftwf_complex), n_coeff_per_level,files_o_direct[level]);
if(b_read == 0){
cerr << "nothing read\n";
}
files[level].seekg((streamoff) (tid * sizeof(fftwf_complex)*n_coeff_per_level), files[level].beg);
files[level].read(reinterpret_cast<char*>(P_read),
sizeof(fftwf_complex) * n_coeff_per_level);
}
void open_files (fstream* & files){
for(int i=0; i<1;i++) {
std::ostringstream oss;
oss << "./Test_fread_read/1.txt.bin";
files[i].open(oss.str().c_str(),
std::ios::in | std::ios::out |
std::ios::binary | std::ios::ate);
if (!files[i])
{
cerr << "fstream could not open " << oss.str() << endl;
}
}
}
void open_files_o_direct (FILE** files_o_direct, int* fd){
for(unsigned int i=0;i<1; i++){
std::ostringstream oss;
oss << "./Test_fread_read/1.txt.bin";
fd[i]=open(oss.str().c_str(), O_RDONLY | O_DIRECT);
files_o_direct[i] = fdopen(fd[i], "rb");
if(!files_o_direct[i])
cerr << "Could not open " << oss.str() << endl;
}
}
int close_files(FILE** files_o_direct, int* fd, fstream* & files) {
for(unsigned int i=0; i<1; i++){
//#if defined (DISK_DIRECT)
if(files_o_direct[i])
close(fd[i]);
//#else
if(files[i].is_open())
files[i].close();
//#endif
}
return 0;
}
int main(){
FILE**files_o_direct = new FILE* [256];
fstream* files = new fstream [256];
int * fd = new int [256];
fftwf_complex * P_read = new fftwf_complex [1];
fftwf_complex * P_fread = new fftwf_complex [1];
open_files_o_direct(files_o_direct, fd);
open_files(files);
fetch_level(2, 0, P_read, P_fread, 1, files_o_direct, files);
cout << "P_read: " << P_read[0][0] << " P_fread: " << P_fread[0][0] << endl;
cout << "P_read: " << P_read[0][1] << " P_fread: " << P_fread[0][1] << endl;
fetch_level(7, 0, P_read, P_fread, 1, files_o_direct, files);
cout << "P_read: " << P_read[0][0] << " P_fread: " << P_fread[0][0] << endl;
cout << "P_read: " << P_read[0][1] << " P_fread: " << P_fread[0][1] << endl;
fetch_level(8, 0, P_read, P_fread, 1, files_o_direct, files);
cout << "P_read: " << P_read[0][0] << " P_fread: " << P_fread[0][0] << endl;
cout << "P_read: " << P_read[0][1] << " P_fread: " << P_fread[0][1] << endl;
close_files(files_o_direct, fd, files);
delete [] P_read;
delete [] P_fread;
delete [] files;
delete [] files_o_direct;
return 0;
}
and the file which is accessed is:
0.133919 0.0458176
1.67441 2.40805
0.997525 -0.279977
-2.39672 -3.076
-0.0390913 0.854464
-0.0176478 -1.3142
-0.667981 -0.486272
0.831051 0.282802
-0.638032 -0.630943
-0.669854 -1.49762
which is stored in a binary format and that can be download from here: 1.txt.bin.
The output i get is:
nothing read
P_read: 0.997525 P_fread: 0
P_read: -0.279977 P_fread: 0
nothing read
P_read: 0.831051 P_fread: 0
P_read: 0.282802 P_fread: 0
nothing read
P_read: -0.638032 P_fread: 0
P_read: -0.630943 P_fread: 0
The problem persists even if i change the type of fftwf_complex from float[2] to simple float.
If i remove the fseek line everything works correctly.
This if (b_read == 0), will be true at the end of the file, and you will enter this branch
if(ferror(this->files_o_direct[level]))
fseek(this->files_o_direct[level], 0, SEEK_END); //ftell here returns 4800000
cerr << "nothing read\n";
even if ferror returns 0, the end of the file was reached anyway
fseek(this->files_o_direct[level], 0, SEEK_END);
makes no sense, and "nothing read\n" will be output either or not ferror returns nonzero.
From the manual page
fread() does not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
so you have to check feof and if it is false you use ferror.
For who ever may have the same problem here there is the answer:
The O_DIRECT flag may impose alignment restrictions on the length and
address of user-space buffers and the file offset of I/Os. In Linux
alignment restrictions vary by filesystem and kernel version and
might be absent entirely. However there is currently no
filesystem-independent interface for an application to discover these
restrictions for a given file or filesystem. Some filesystems
provide their own interfaces for doing so, for example the
XFS_IOC_DIOINFO operation in xfsctl(3).
Under Linux 2.4, transfer sizes, and the alignment of the user buffer
and the file offset must all be multiples of the logical block size
of the filesystem. Since Linux 2.6.0, alignment to the logical block
size of the underlying storage (typically 512 bytes) suffices. The
logical block size can be determined using the ioctl(2) BLKSSZGET
operation or from the shell using the command:
blockdev --getss
linux reference page
I am having trouble with shared memory. I have one process that creates and writes to a shared memory segment just fine. But I cannot get a second process to attach that same existing segment. My second process can create a new shared segment if I use IPC_CREATE flag but I need to attach to the existing shared segment that was created by the 1st process.
This is my code in the 2nd process:
int nSharedMemoryID = 10;
key_t tKey = ftok("/dev/null", nSharedMemoryID);
if (tKey == -1) {
std::cerr << "ERROR: ftok(id: " << nSharedMemoryID << ") failed, " << strerror(errno) << std::endl;
exit(3);
}
std::cout << "ftok() successful " << std::endl;
size_t nSharedMemorySize = 10000;
int id = shmget(tKey, nSharedMemorySize, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (id == -1) {
std::cerr << "ERROR: shmget() failed, " << strerror(errno) << std::endl << std::endl;
exit(4);
}
std::cout << "shmget() successful, id: " << id << std::endl;
unsigned char *pBaseSM = (unsigned char *)shmat(id, (const void *)NULL, SHM_RDONLY);
if (pBaseSM == (unsigned char *)-1) {
std::cerr << "ERROR: shmat() failed, " << strerror(errno) << std::endl << std::endl;
exit(5);
}
std::cout << "shmat() successful " << std::endl;
The problem is that the 2nd process always errors out on the call to shmget() with a "No such file or directory" error. But this is the exact same code I used in the 1st process and it works just fine there. In the 1st process that created the shared segment, I can write to the memory segment, I can see it with "ipcs -m" Also, if I get the shmid from the "ipcs -m" command of the segment and hard code it in my 2nd process and the 2nd process can attach to it just fine. So the problem seems to be generation of the common id that both processes use to identify a single shared segment.
I have several questions:
(1) Is there an easier way to get the shmid of an existing shared memory segment? It seems crazy to me that I have to pass three separate parameters from the 1st process (that created the segment) to the 2nd process just so the 2nd process can get the same shared segment. I can live with having to pass 2 parameters: the file name like "/dev/null" and the same shared id (nSharedMemoryID in my code). But the size of the segment that has to be passed to the shmget() routine in order to get the shmid seems senseless because I have no idea of exactly how much memory was actually allocated (because of the page size issues) so I cannot be certain it is the same.
(2) does the segment size that I use in the 2nd process have to be the same as the size of the segment used to initially create the segment in the 1st process? I have tried to specify it as 0 but I still get errors.
(3) likewise, do the permissions have to be the same? that is, if the shared segment was created with read/write for user/group/world, can the 2nd process just use read for user? (same user for both processes).
(4) and why does shmget() fail with the "No such file or directory" error when the file "/dev/null" obviously exists for both processes? I am assuming that the 1st process does not put some kind of a lock on that node because that would be senseless.
Thanks for any help anyone can give. I have been struggling with this for hours--which means I am probably doing something really stupid and will ultimately embarrass myself when someone points out my error :-)
thanks,
-Andres
(1) as a different way: the attaching process scan the existing segments of the user, tries to attach with the needed size, check for a "magic byte sequence" at the beginning of the segment (to exclude other programs of the same user). Alternatively you can check if the process attached is the one that you expect. If one of the steps fails, this is the first one and will create the segment... cumbersome yes, I saw it in a code from the '70s.
Eventually you can evaluate to use the POSIX compliant shm_open() alternative - should be simpler or at least more modern...
(2) Regarding the size, it's important that the size specified be less/equal than the size of the existing segment, so no issues if it's rounded to the next memory page size. you get the EINVAL error only if it's larger.
(3) the mode flags are only relevant when you create the segment the first time (mostly sure).
(4) The fact that shmget() fail with the "No such file or directory" means only that it hasn't found a segment with that key (being now pedantic: not id - with id we usually refer to the value returnet by shmget(), used subsequently) - have you checked that the tKey is the same? Your code works fine on my system. Just added a main() around it.
EDIT: attached the working program
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char **argv) {
int nSharedMemoryID = 10;
if (argc > 1) {
nSharedMemoryID = atoi(argv[1]);
}
key_t tKey = ftok("/dev/null", nSharedMemoryID);
if (tKey == -1) {
std::cerr << "ERROR: ftok(id: " << nSharedMemoryID << ") failed, " << strerror(errno) << std::endl;
exit(3);
}
std::cout << "ftok() successful. key = " << tKey << std::endl;
size_t nSharedMemorySize = 10000;
int id = shmget(tKey, nSharedMemorySize, 0);
if (id == -1) {
std::cerr << "ERROR: shmget() failed (WILL TRY TO CREATE IT NEW), " << strerror(errno) << std::endl << std::endl;
id = shmget(tKey, nSharedMemorySize, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | IPC_CREAT);
if (id == -1) {
std::cerr << "ERROR: shmget() failed, " << strerror(errno) << std::endl << std::endl;
exit(4);
}
}
std::cout << "shmget() successful, id: " << id << std::endl;
unsigned char *pBaseSM = (unsigned char *)shmat(id, (const void *)NULL, SHM_RDONLY);
if (pBaseSM == (unsigned char *)-1) {
std::cerr << "ERROR: shmat() failed, " << strerror(errno) << std::endl << std::endl;
exit(5);
}
std::cout << "shmat() successful " << std::endl;
}
EDIT: output
$ ./a.out 33
ftok() successful. key = 553976853
ERROR: shmget() failed (WILL TRY TO CREATE IT NEW), No such file or directory
shmget() successful, id: 20381699
shmat() successful
$ ./a.out 33
ftok() successful. key = 553976853
shmget() successful, id: 20381699
shmat() successful
SOLUTION - after in-chat (wow SO has a chat!) discussion:
At the end the problem was that in the original code he was calling shmctl() later on to tell to detach the segment as the last process detached it, before the other process was attached.
The problem is that this in fact make the segment private. It's key is marked as 0x00000000 by ipcs -m and cannot be attached anymore by other processes - it's in fact marked for lazy deletion.
I just want to post the result of all the help Sigismondo gave me and post the solution to this issue just in case anyone else has the same problem.
The clue was using "ipcs -m" and noticing that the key value was 0 which means that the shared segment is private and so the 2nd process could not attach to it.
An additional quirk was this: I was calling the following:
int nReturnCode = shmctl(id, IPC_RMID, &m_stCtrlStruct);
My intent was to set the mode for the segment so that it would be deleted when all processes that are using it have exited. However, this call has the side effect of making the segment private even though it was created without using the IPC_EXCL flag.
Hopefully this will help anyone else who trips across this issue.
And, many, many thanks to Sigismondo for taking the time to help me--I learned a lot from our chat!
-Andres
I'm using Qt and want a platform-independent way of getting the available free disk space.
I know in Linux I can use statfs and in Windows I can use GetDiskFreeSpaceEx(). I know boost has a way, boost::filesystem::space(Path const & p).
But I don't want those. I'm in Qt and would like to do it in a Qt-friendly way.
I looked at QDir, QFile, QFileInfo -- nothing!
I know It's quite old topic but somebody can still find it useful.
Since QT 5.4 the QSystemStorageInfo is discontinued, instead there is a new class QStorageInfo that makes the whole task really simple and it's cross-platform.
QStorageInfo storage = QStorageInfo::root();
qDebug() << storage.rootPath();
if (storage.isReadOnly())
qDebug() << "isReadOnly:" << storage.isReadOnly();
qDebug() << "name:" << storage.name();
qDebug() << "fileSystemType:" << storage.fileSystemType();
qDebug() << "size:" << storage.bytesTotal()/1024/1024 << "MB";
qDebug() << "availableSize:" << storage.bytesAvailable()/1024/1024 << "MB";
Code has been copied from the example in QT 5.5 docs
The new QStorageInfo class, introduced in Qt 5.4, can do this (and more). It's part of the Qt Core module so no additional dependencies required.
#include <QStorageInfo>
#include <QDebug>
void printRootDriveInfo() {
QStorageInfo storage = QStorageInfo::root();
qDebug() << storage.rootPath();
if (storage.isReadOnly())
qDebug() << "isReadOnly:" << storage.isReadOnly();
qDebug() << "name:" << storage.name();
qDebug() << "filesystem type:" << storage.fileSystemType();
qDebug() << "size:" << storage.bytesTotal()/1024/1024 << "MB";
qDebug() << "free space:" << storage.bytesAvailable()/1024/1024 << "MB";
}
I wrote this back when I wrote the question (after voting on QTBUG-3780); I figure I'll save someone (or myself) from doing this from scratch.
This is for Qt 4.8.x.
#ifdef WIN32
/*
* getDiskFreeSpaceInGB
*
* Returns the amount of free drive space for the given drive in GB. The
* value is rounded to the nearest integer value.
*/
int getDiskFreeSpaceInGB( LPCWSTR drive )
{
ULARGE_INTEGER freeBytesToCaller;
freeBytesToCaller.QuadPart = 0L;
if( !GetDiskFreeSpaceEx( drive, &freeBytesToCaller, NULL, NULL ) )
{
qDebug() << "ERROR: Call to GetDiskFreeSpaceEx() failed.";
}
int freeSpace_gb = freeBytesToCaller.QuadPart / B_per_GB;
qDebug() << "Free drive space: " << freeSpace_gb << "GB";
return freeSpace_gb;
}
#endif
Usage:
// Check available hard drive space
#ifdef WIN32
// The L in front of the string does some WINAPI magic to convert
// a string literal into a Windows LPCWSTR beast.
if( getDiskFreeSpaceInGB( L"c:" ) < MinDriveSpace_GB )
{
errString = "ERROR: Less than the recommended amount of free space available!";
isReady = false;
}
#else
# pragma message( "WARNING: Hard drive space will not be checked at application start-up!" )
#endif
There is nothing in Qt at time of writing.
Consider commenting on or voting for QTBUG-3780.
I need to write to a mounted USB-Stick and I got the available size of memory with the following code:
QFile usbMemoryInfo;
QStringList usbMemoryLines;
QStringList usbMemoryColumns;
system("df /dev/sdb1 > /tmp/usb_usage.info");
usbMemoryInfo.setFileName( "/tmp/usb_usage.info" );
usbMemoryInfo.open(QIODevice::ReadOnly);
QTextStream readData(&usbMemoryInfo);
while (!readData.atEnd())
{
usbMemoryLines << readData.readLine();
}
usbMemoryInfo.close();
usbMemoryColumns = usbMemoryLines.at(1).split(QRegExp("\\s+"));
QString available_bytes = usbMemoryColumns.at(3);
I know that this question is already quite old by now, but I searched stackoverflow and found that nobody got solution for this, so I decided to post.
There is QSystemStorageInfo class in QtMobility, it provides cross-platform way to get info about logical drives. For example: logicalDrives() returns list of paths which you can use as parameters for other methods: availableDiskSpace(), totalDiskSpace() to get free and total drive's space, accordingly, in bytes.
Usage example:
QtMobility::QSystemStorageInfo sysStrgInfo;
QStringList drives = sysStrgInfo.logicalDrives();
foreach (QString drive, drives)
{
qDebug() << sysStrgInfo.availableDiskSpace(drive);
qDebug() << sysStrgInfo.totalDiskSpace(drive);
}
This example prints free and total space in bytes for all logical drives in OS. Don't forget to add QtMobility in Qt project file:
CONFIG += mobility
MOBILITY += systeminfo
I used these methods in a project I'm working on now and it worked for me. Hope it'll help someone!
this code`s working for me:
#ifdef _WIN32 //win
#include "windows.h"
#else //linux
#include <sys/stat.h>
#include <sys/statfs.h>
#endif
bool GetFreeTotalSpace(const QString& sDirPath, double& fTotal, double& fFree)
{
double fKB = 1024;
#ifdef _WIN32
QString sCurDir = QDir::current().absolutePath();
QDir::setCurrent(sDirPath);
ULARGE_INTEGER free,total;
bool bRes = ::GetDiskFreeSpaceExA( 0 , &free , &total , NULL );
if ( !bRes )
return false;
QDir::setCurrent( sCurDir );
fFree = static_cast<__int64>(free.QuadPart) / fKB;
fTotal = static_cast<__int64>(total.QuadPart) / fKB;
#else // Linux
struct stat stst;
struct statfs stfs;
if ( ::stat(sDirPath.toLocal8Bit(),&stst) == -1 )
return false;
if ( ::statfs(sDirPath.toLocal8Bit(),&stfs) == -1 )
return false;
fFree = stfs.f_bavail * ( stst.st_blksize / fKB );
fTotal = stfs.f_blocks * ( stst.st_blksize / fKB );
#endif // _WIN32
return true;
}