r25118: More pstring elimination.
[jra/samba/.git] / source3 / smbd / dfree.c
index 7848309a5ea190813b8ce0ff7b2f2bb49ca588b6..94394686009d7d0a845c4c6ef744cfe1ad7c72ff 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"
 
-
-extern int DEBUGLEVEL;
-
 /****************************************************************************
-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)
 {
        /* check if the disk is beyond the max disk size */
@@ -40,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.
                         */
@@ -63,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 sys_disk_free(connection_struct *conn, const char *path, BOOL small_query, 
                               SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
 {
-       int dfree_retval;
+       SMB_BIG_UINT dfree_retval;
        SMB_BIG_UINT dfree_q = 0;
        SMB_BIG_UINT bsize_q = 0;
        SMB_BIG_UINT dsize_q = 0;
-       char *dfree_command;
+       const char *dfree_command;
 
        (*dfree) = (*dsize) = 0;
        (*bsize) = 512;
@@ -82,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 (SMB_BIG_UINT)-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);
@@ -97,15 +101,15 @@ 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);
@@ -119,10 +123,19 @@ 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 (SMB_BIG_UINT)-1;
+                       }
+               }
+       } else {
+               if (sys_fsusage(path, dfree, dsize) != 0) {
+                       DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
+                               strerror(errno) ));
+                       return (SMB_BIG_UINT)-1;
                }
-       } else
-               sys_fsusage(path, dfree, dsize);
+       }
 
        if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
                (*bsize) = bsize_q;
@@ -157,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)
+
+SMB_BIG_UINT get_dfree_info(connection_struct *conn,
+                       const char *path,
+                       BOOL small_query,
+                       SMB_BIG_UINT *bsize,
+                       SMB_BIG_UINT *dfree,
+                       SMB_BIG_UINT *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;
+       SMB_BIG_UINT 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 == (SMB_BIG_UINT)-1) {
+               /* Don't cache bad data. */
+               return dfree_ret;
+       }
+
+       /* No cached info or time to refresh. */
+       if (!dfc) {
+               dfc = TALLOC_P(conn->mem_ctx, 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;
 }