Use {u,}int64_t instead of SMB_BIG_{U,}INT.
[samba.git] / source3 / smbd / dfree.c
index 13a3e86c6e1775581eca812e43cb360f6f124c6d..cd09d739236c2aaa39ecde1557c249773a757729 100644 (file)
@@ -1,12 +1,11 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    functions to calculate the free disk space
    Copyright (C) Andrew Tridgell 1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
 /****************************************************************************
-normalise for DOS usage 
+ Normalise for DOS usage.
 ****************************************************************************/
-static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+
+static void disk_norm(bool small_query, uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
 {
        /* check if the disk is beyond the max disk size */
-       SMB_BIG_UINT maxdisksize = lp_maxdisksize();
+       uint64_t maxdisksize = lp_maxdisksize();
        if (maxdisksize) {
                /* convert to blocks - and don't overflow */
                maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
@@ -37,11 +36,11 @@ static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,
                   errors */
        }  
 
-       while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
-               *dfree /= 2;
-               *dsize /= 2;
-               *bsize *= 2;
-               if(small_query) {       
+       if(small_query) {       
+               while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
+                       *dfree /= 2;
+                       *dsize /= 2;
+                       *bsize *= 2;
                        /*
                         * Force max to fit in 16 bit fields.
                         */
@@ -60,17 +59,17 @@ static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,
 
 
 /****************************************************************************
-  return number of 1K blocks available on a path and total number 
+ Return number of 1K blocks available on a path and total number.
 ****************************************************************************/
 
-static SMB_BIG_UINT disk_free(const char *path, BOOL small_query, 
-                              SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+uint64_t sys_disk_free(connection_struct *conn, const char *path, bool small_query, 
+                              uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
 {
-       int dfree_retval;
-       SMB_BIG_UINT dfree_q = 0;
-       SMB_BIG_UINT bsize_q = 0;
-       SMB_BIG_UINT dsize_q = 0;
-       char *dfree_command;
+       uint64_t dfree_retval;
+       uint64_t dfree_q = 0;
+       uint64_t bsize_q = 0;
+       uint64_t dsize_q = 0;
+       const char *dfree_command;
 
        (*dfree) = (*dsize) = 0;
        (*bsize) = 512;
@@ -79,13 +78,21 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query,
         * If external disk calculation specified, use it.
         */
 
-       dfree_command = lp_dfree_command();
+       dfree_command = lp_dfree_command(SNUM(conn));
        if (dfree_command && *dfree_command) {
-               char *p;
-               char **lines;
-               pstring syscmd;
+               const char *p;
+               char **lines = NULL;
+               char *syscmd = NULL;
+
+               syscmd = talloc_asprintf(talloc_tos(),
+                               "%s %s",
+                               dfree_command,
+                               path);
+
+               if (!syscmd) {
+                       return (uint64_t)-1;
+               }
 
-               slprintf(syscmd, sizeof(syscmd)-1, "%s %s", dfree_command, path);
                DEBUG (3, ("disk_free: Running command %s\n", syscmd));
 
                lines = file_lines_pload(syscmd, NULL);
@@ -94,18 +101,18 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query,
 
                        DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
 
-                       *dsize = (SMB_BIG_UINT)strtoul(line, &p, 10);
-                       while (p && *p & isspace(*p))
+                       *dsize = STR_TO_SMB_BIG_UINT(line, &p);
+                       while (p && *p && isspace(*p))
                                p++;
                        if (p && *p)
-                               *dfree = (SMB_BIG_UINT)strtoul(p, &p, 10);
-                       while (p && *p & isspace(*p))
+                               *dfree = STR_TO_SMB_BIG_UINT(p, &p);
+                       while (p && *p && isspace(*p))
                                p++;
                        if (p && *p)
-                               *bsize = (SMB_BIG_UINT)strtoul(p, NULL, 10);
+                               *bsize = STR_TO_SMB_BIG_UINT(p, NULL);
                        else
                                *bsize = 1024;
-                       file_lines_free(lines);
+                       TALLOC_FREE(lines);
                        DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
                                (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
 
@@ -116,12 +123,21 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query,
                } else {
                        DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
                                syscmd, strerror(errno) ));
-                       sys_fsusage(path, dfree, dsize);
+                       if (sys_fsusage(path, dfree, dsize) != 0) {
+                               DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
+                                       strerror(errno) ));
+                               return (uint64_t)-1;
+                       }
                }
-       } else
-               sys_fsusage(path, dfree, dsize);
+       } else {
+               if (sys_fsusage(path, dfree, dsize) != 0) {
+                       DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
+                               strerror(errno) ));
+                       return (uint64_t)-1;
+               }
+       }
 
-       if (disk_quotas((char *)path, &bsize_q, &dfree_q, &dsize_q)) {
+       if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
                (*bsize) = bsize_q;
                (*dfree) = MIN(*dfree,dfree_q);
                (*dsize) = MIN(*dsize,dsize_q);
@@ -134,10 +150,10 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query,
        }
 
        if ((*dsize)<1) {
-               static int done;
+               static bool done = false;
                if (!done) {
                        DEBUG(0,("WARNING: dfree is broken on this system\n"));
-                       done=1;
+                       done=true;
                }
                *dsize = 20*1024*1024/(*bsize);
                *dfree = MAX(1,*dfree);
@@ -154,12 +170,54 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query,
        return(dfree_retval);
 }
 
-
 /****************************************************************************
-wrap it to get filenames right
+ Potentially returned cached dfree info.
 ****************************************************************************/
-SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query, 
-                           SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+
+uint64_t get_dfree_info(connection_struct *conn,
+                       const char *path,
+                       bool small_query,
+                       uint64_t *bsize,
+                       uint64_t *dfree,
+                       uint64_t *dsize)
 {
-       return disk_free(path,small_query, bsize,dfree,dsize);
+       int dfree_cache_time = lp_dfree_cache_time(SNUM(conn));
+       struct dfree_cached_info *dfc = conn->dfree_info;
+       uint64_t dfree_ret;
+
+       if (!dfree_cache_time) {
+               return SMB_VFS_DISK_FREE(conn,path,small_query,bsize,dfree,dsize);
+       }
+
+       if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
+               /* Return cached info. */
+               *bsize = dfc->bsize;
+               *dfree = dfc->dfree;
+               *dsize = dfc->dsize;
+               return dfc->dfree_ret;
+       }
+
+       dfree_ret = SMB_VFS_DISK_FREE(conn,path,small_query,bsize,dfree,dsize);
+
+       if (dfree_ret == (uint64_t)-1) {
+               /* Don't cache bad data. */
+               return dfree_ret;
+       }
+
+       /* No cached info or time to refresh. */
+       if (!dfc) {
+               dfc = TALLOC_P(conn, struct dfree_cached_info);
+               if (!dfc) {
+                       return dfree_ret;
+               }
+               conn->dfree_info = dfc;
+       }
+
+       dfc->bsize = *bsize;
+       dfc->dfree = *dfree;
+       dfc->dsize = *dsize;
+       dfc->dfree_ret = dfree_ret;
+       dfc->last_dfree_time = conn->lastused;
+
+       return dfree_ret;
 }