1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/**********************************************************************
Audacity: A Digital Audio Editor
DiskFunctions.cpp
Win: Mark Tomlinson
Mac: Dominic Mazzoni
**********************************************************************/
#ifdef WIN32
#include <windows.h> //the windows stuff
#include <tchar.h>
#endif
#ifdef linux
#include <sys/vfs.h>
#endif
#include <iostream.h>
#include <stdio.h> //the std I/O stuff
#include <wx/longlong.h>
//GetFreeSpace is an obsoleted Win-16 API name and cannot be used.
#ifdef WIN32
wxLongLong GetFreeDiskSpace(TCHAR * path);
#else
wxLongLong GetFreeDiskSpace(const char *path);
#endif
/**
* <path> could be a drive letter, full path to a file or directory,
* or local path (in which case the default drive and directory should be
* grabbed).
*
* Since this API is specific only to a DRIVE the path information is moot.
* If a UNC name (\\myhost\myshare\) is passed in then the trailing \ is
* required otherwise it is not needed. With a "" or NULL string for <path>
* the default drive is used. If a 'local' path is used, it MUST include
* the leading `\' (i.e. \mydir1\mydir2).
**/
#ifdef WIN32
wxLongLong GetFreeDiskSpace(TCHAR * path)
{
DWORD dwSectorsPerCluster = 0;
DWORD dwBytesPerSector = 0;
DWORD dwNumberOfFreeClusters = 0;
DWORD dwTotalNumberOfClusters = 0;
DWORD dwTotalFree = 0;
TCHAR *pszPath = path;
TCHAR szPath[3];
memset(szPath, 0, sizeof(char));
/* First some logic to sort out what is getting passed in. if it is a
* local directory, we will use NULL as the API will default to the current
* local drive. If it is a UNC then we simply pass it along unchanged. If
* it is neither of these, then we grab the drive letter off and append a
* colon.
**/
if (*pszPath == '\\') {
// local dir or UNC?
pszPath = _tcsinc(path);
if (*pszPath != '\\') {
// it is a local dir
pszPath = NULL;
}
//it is a UNC
pszPath = path;
} else {
//grab just the drive letter
_tcsncpy(szPath, path, 1);
//append the :
szPath[1] = _T(':');
pszPath = szPath;
}
/* Now we make the windows API call to get the free space information and do
* a little math to add up the free bytes.
**/
/* There are two WIN32 API calls that report free disk space: GetDiskFreeSpace() and
* GetDiskFreeSpaceEx(). The first is supported on all Win32 machines, but doesn't work
* on driver >2GB. The latter does, but is only available on Win95OSR2 and up (which
* is practically everything anyway... we support both by detecting whether
* GetDiskFreeSpaceEx() is available at runtime */
if(GetProcAddress(GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA")) {
/* GetDiskFreeSpaceEx() is supported */
ULARGE_INTEGER bytesFreeToCaller;
ULARGE_INTEGER bytesTotal;
ULARGE_INTEGER bytesFree;
if(!GetDiskFreeSpaceEx(path, &bytesFreeToCaller, &bytesTotal, &bytesFree))
return -1L;
return bytesFreeToCaller.QuadPart;
}
else {
if (GetDiskFreeSpace
(pszPath, &dwSectorsPerCluster, &dwBytesPerSector,
&dwNumberOfFreeClusters, &dwTotalNumberOfClusters)) {
return (dwNumberOfFreeClusters * dwSectorsPerCluster *
dwBytesPerSector);
} else {
//normally you would call GetLastError here to parse the OS error
return -1;
}
}
}
#elif defined(__WXMAC__)
#include <Files.h>
void my_c2pstr(char *str)
{
int len = strlen((const char *) str);
for (int i = len; i > 0; i--)
str[i] = str[i - 1];
str[0] = (len > 255 ? 255 : (char) len);
}
wxLongLong GetFreeDiskSpace(const char *path)
{
char *str = new char[strlen(path) + 1];
strcpy(str, path);
char *p = str;
/* We expect something like ":Macintosh HD:Audacity:"
* and we want to get rid of everything up to the second
* colon: "Macintosh HD"
*/
if (p[0] == 0)
return -1;
char *colon2 = &p[1];
while (*colon2 && *colon2 != ':')
colon2++;
*colon2 = 0;
if (*p == ':')
*p++;
/* Mac routines want Pascal strings */
my_c2pstr(p);
HVolumeParam pb;
pb.ioCompletion = NULL;
pb.ioVolIndex = -1;
pb.ioNamePtr = (unsigned char *) p;
pb.ioVRefNum = 0;
OSErr err = PBHGetVInfo((HParamBlockRec *) & pb, 0);
if (err)
return -1;
long freeBytes = ((long) pb.ioVFrBlk) * ((long) pb.ioVAlBlkSiz);
delete[]str;
return freeBytes;
}
#elif defined(__WXGTK__)
#ifdef linux
wxLongLong GetFreeDiskSpace(const char *path)
{
struct statfs theStats;
if (statfs(path, &theStats) != 0)
return -1L;
/* f_bsize is described in the man page as "optimal transfer block size."
* I'm not sure what they mean my that, but on my system at least, it
* correctly reports the block size of the filesystem. glibc >= 2.1
* offers a function "statvfs" which has a field for the actual block
* size, but I'd rather not create a dependency on glibc.
*
* f_bavail is "free blocks available to non-superuser." */
return wxLongLong(theStats.f_bavail) * theStats.f_bsize;
}
#else
#warning GetFreeDiskSpace has not been implemented on this system...
wxLongLong GetFreeDiskSpace(const char *path)
{
return -1;
}
#endif
#endif
|