From eadd7bd2cbef3ca0bde3e93ad9671a783e4e90b0 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sat, 25 Aug 2001 16:54:14 +0000
Subject: [PATCH] added wxGetDiskSpace for Win/Unix

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11476 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt            |  3 +-
 docs/latex/wx/function.tex  | 21 +++++++++
 include/wx/utils.h          | 15 ++++--
 samples/console/console.cpp | 12 ++---
 src/msw/utils.cpp           | 91 +++++++++++++++++++++++++++++++++++++
 src/unix/utilsunx.cpp       | 32 +++++++++++++
 6 files changed, 164 insertions(+), 10 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index 48d3c7cc7c..f7dc556f01 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -7,7 +7,8 @@ wxWindows 2 Change Log
 wxBase:
 
 - wxRegEx class added
-- more fixes to wxMBConv classes. Conversion to and from wchar_t now works with 
+- wxGetDiskSpace() function added (Jonothan Farr, Markus Fieber)
+- more fixes to wxMBConv classes. Conversion to and from wchar_t now works with
   glibc 2.2 as well as with glibc 2.1. Unix version now checks for iconv()'s
   capabilities at runtime instead of in the configure script.
 
diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex
index aab0d2bcb6..f940c470ec 100644
--- a/docs/latex/wx/function.tex
+++ b/docs/latex/wx/function.tex
@@ -177,6 +177,27 @@ Returns the next file that matches the path passed to \helpref{wxFindFirstFile}{
 
 See \helpref{wxFindFirstFile}{wxfindfirstfile} for an example.
 
+\membersection{::wxGetDiskSpace}\label{wxgetdiskspace}
+
+\func{bool}{wxGetDiskSpace}{\param{const wxString\& }{path}, \path{wxLongLong }{*total = NULL}, \path{wxLongLong }{*free = NULL}}
+
+This function returns the total number of bytes and number of free bytes on
+the disk containing the directory {\it path} (it should exist). Both 
+{\it total} and {\it free} parameters may be {\tt NULL} if the corresponding
+information is not needed.
+
+\wxheading{Returns}
+
+{\tt TRUE} on success, {\tt FALSE} if an error occured (for example, the
+directory doesn't exist).
+
+\wxheading{Portability}
+
+This function is implemented for Win16 (only for drives less than 2Gb), Win32,
+Mac OS and generic Unix provided the system has {\tt statfs()} function.
+
+This function first appeared in wxWindows 2.3.2.
+
 \membersection{::wxGetOSDirectory}\label{wxgetosdirectory}
 
 \func{wxString}{wxGetOSDirectory}{\void}
diff --git a/include/wx/utils.h b/include/wx/utils.h
index 601f3cedbb..0235857076 100644
--- a/include/wx/utils.h
+++ b/include/wx/utils.h
@@ -25,6 +25,10 @@
 #include "wx/list.h"
 #include "wx/filefn.h"
 
+// need this for wxGetDiskSpace() as we can't, unfortunately, forward declare
+// wxLongLong
+#include "wx/longlong.h"
+
 #ifdef __X__
     #include <dirent.h>
     #include <unistd.h>
@@ -264,11 +268,16 @@ WXDLLEXPORT wxChar* wxGetUserHome(const wxString& user = wxEmptyString);
 #endif
 
 #ifdef __WXMAC__
-WXDLLEXPORT wxString wxMacFindFolder(short 					vRefNum,
-								 OSType 				folderType,
-								 Boolean 				createFolder);
+WXDLLEXPORT wxString wxMacFindFolder(short vRefNum,
+                                     OSType folderType,
+                                     Boolean createFolder);
 #endif
 
+// get number of total/free bytes on the disk where path belongs
+WXDLLEXPORT bool wxGetDiskSpace(const wxString& path,
+                                wxLongLong *pTotal = NULL,
+                                wxLongLong *pFree = NULL);
+
 #if wxUSE_GUI // GUI only things from now on
 
 // ----------------------------------------------------------------------------
diff --git a/samples/console/console.cpp b/samples/console/console.cpp
index 8a75d830ab..f7f43fc2ea 100644
--- a/samples/console/console.cpp
+++ b/samples/console/console.cpp
@@ -54,11 +54,11 @@
 //#define TEST_FILENAME
 //#define TEST_FTP
 //#define TEST_HASH
-//#define TEST_INFO_FUNCTIONS
+#define TEST_INFO_FUNCTIONS
 //#define TEST_LIST
 //#define TEST_LOCALE
 //#define TEST_LOG
-#define TEST_LONGLONG
+//#define TEST_LONGLONG
 //#define TEST_MIME
 //#define TEST_PATHLIST
 //#define TEST_REGCONF
@@ -1366,7 +1366,7 @@ static void TestMimeAssociate()
 
 static void TestDiskInfo()
 {
-    puts("*** Testing wxGetDiskSpace() ***\n");
+    puts("*** Testing wxGetDiskSpace() ***");
 
     for ( ;; )
     {
@@ -1385,9 +1385,9 @@ static void TestDiskInfo()
         }
         else
         {
-            wxPrintf(_T("%s total bytes, %s free bytes on '%s'.\n"),
-                    total.ToString().c_str(),
-                    free.ToString().c_str(),
+            wxPrintf(_T("%sKb total, %sKb free on '%s'.\n"),
+                    (total / 1024).ToString().c_str(),
+                    (free / 1024).ToString().c_str(),
                     pathname);
         }
     }
diff --git a/src/msw/utils.cpp b/src/msw/utils.cpp
index f9db6a472b..686ff7d697 100644
--- a/src/msw/utils.cpp
+++ b/src/msw/utils.cpp
@@ -449,6 +449,97 @@ bool wxDirExists(const wxString& dir)
 #endif // Win32/16
 }
 
+bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
+{
+    if ( path.empty() )
+        return FALSE;
+
+#ifdef __WIN32__
+    // GetDiskFreeSpaceEx() is not available under original Win95, check for
+    // it
+    typedef BOOL (*GetDiskFreeSpaceEx_t)(LPCTSTR,
+                                         PULARGE_INTEGER,
+                                         PULARGE_INTEGER,
+                                         PULARGE_INTEGER);
+
+    GetDiskFreeSpaceEx_t
+        pGetDiskFreeSpaceEx = ::GetProcAddress
+                              (
+                                ::GetModuleHandle(_T("kernel32.dll")),
+#if wxUSE_UNICODE
+                                "GetDiskFreeSpaceExW"
+#else
+                                "GetDiskFreeSpaceExA"
+#endif
+                              );
+
+    if ( pGetDiskFreeSpaceEx )
+    {
+        ULARGE_INTEGER bytesFree, bytesTotal;
+
+        // may pass the path as is, GetDiskFreeSpaceEx() is smart enough
+        if ( !pGetDiskFreeSpaceEx(path,
+                                  &bytesFree,
+                                  &bytesTotal,
+                                  NULL) )
+        {
+            wxLogLastError(_T("GetDiskFreeSpaceEx"));
+
+            return FALSE;
+        }
+
+        if ( pTotal )
+        {
+            *pTotal = wxLongLong(bytesTotal.HighPart, bytesTotal.LowPart);
+        }
+
+        if ( pFree )
+        {
+            *pFree = wxLongLong(bytesFree.HighPart, bytesFree.LowPart);
+        }
+    }
+    else
+#endif // Win32
+    {
+        DWORD lSectorsPerCluster,
+              lBytesPerSector,
+              lNumberOfFreeClusters,
+              lTotalNumberOfClusters;
+
+        // FIXME: this is wrong, we should extract the root drive from path
+        //        instead, but this is the job for wxFileName...
+        if ( !::GetDiskFreeSpace(path,
+                                 &lSectorsPerCluster,
+                                 &lBytesPerSector,
+                                 &lNumberOfFreeClusters,
+                                 &lTotalNumberOfClusters) )
+        {
+            wxLogLastError(_T("GetDiskFreeSpace"));
+
+            return FALSE;
+        }
+
+        // there's a problem with drives larger than 2GB on non Win32!!
+        // let's calculate it, nevertheless....
+        wxLongLong lBytesPerCluster = lSectorsPerCluster;
+        lBytesPerCluster *= lBytesPerSector;
+
+        if ( pTotal )
+        {
+            *pTotal = lBytesPerCluster;
+            *pTotal *= lTotalNumberOfClusters;
+        }
+
+        if ( pFree )
+        {
+            *pFree = lBytesPerCluster;
+            *pFree *= lNumberOfFreeClusters;
+        }
+    }
+
+    return TRUE;
+}
+
 // ----------------------------------------------------------------------------
 // env vars
 // ----------------------------------------------------------------------------
diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp
index ad8a078fab..3bd19ffbf6 100644
--- a/src/unix/utilsunx.cpp
+++ b/src/unix/utilsunx.cpp
@@ -28,6 +28,10 @@
 
 #include "wx/stream.h"
 
+#ifdef HAVE_STATFS
+    #include <sys/vfs.h>
+#endif // HAVE_STATFS
+
 #if wxUSE_GUI
     #include "wx/unix/execute.h"
 #endif
@@ -909,6 +913,34 @@ long wxGetFreeMemory()
     return -1;
 }
 
+bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
+{
+#ifdef HAVE_STATFS
+
+    struct statfs fs;
+    if ( statfs(path, &fs) != 0 )
+    {
+        wxLogSysError("Failed to get file system statistics");
+
+        return FALSE;
+    }
+
+    if ( pTotal )
+    {
+        *pTotal = wxLongLong(fs.f_blocks) * fs.f_bsize;
+    }
+
+    if ( pFree )
+    {
+        *pFree = wxLongLong(fs.f_bavail) * fs.f_bsize;
+    }
+
+    return TRUE;
+#endif // HAVE_STATFS
+
+    return FALSE;
+}
+
 // ----------------------------------------------------------------------------
 // env vars
 // ----------------------------------------------------------------------------
-- 
2.50.0

