Removed version number from file header.
[ira/wip.git] / source3 / smbd / dfree.c
index 020386645c219fb299532796d850412d0fe2307f..71b3f2bf7724dd15f89244b7a04790c54c3655a6 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    functions to calculate the free disk space
    Copyright (C) Andrew Tridgell 1998
    
 
 #include "includes.h"
 
-
-extern int DEBUGLEVEL;
-
 /****************************************************************************
 normalise for DOS usage 
 ****************************************************************************/
-static void disk_norm(SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+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 */
        SMB_BIG_UINT maxdisksize = lp_maxdisksize();
@@ -39,163 +35,90 @@ static void disk_norm(SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsiz
                /* the -1 should stop applications getting div by 0
                   errors */
        }  
-       
+
        while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
                *dfree /= 2;
                *dsize /= 2;
                *bsize *= 2;
-               if (*bsize > WORDMAX) {
-                       *bsize = WORDMAX;
-                       if (*dsize > WORDMAX)
-                               *dsize = WORDMAX;
-                       if (*dfree >  WORDMAX)
-                               *dfree = WORDMAX;
-                       break;
+               if(small_query) {       
+                       /*
+                        * Force max to fit in 16 bit fields.
+                        */
+                       if (*bsize > (WORDMAX*512)) {
+                               *bsize = (WORDMAX*512);
+                               if (*dsize > WORDMAX)
+                                       *dsize = WORDMAX;
+                               if (*dfree >  WORDMAX)
+                                       *dfree = WORDMAX;
+                               break;
+                       }
                }
        }
 }
 
 
-/* Return the number of TOSIZE-byte blocks used by
-   BLOCKS FROMSIZE-byte blocks, rounding away from zero.
-*/
-static SMB_BIG_UINT adjust_blocks(SMB_BIG_UINT blocks, SMB_BIG_UINT fromsize, SMB_BIG_UINT tosize)
-{
-       if (fromsize == tosize) /* e.g., from 512 to 512 */
-               return blocks;
-       else if (fromsize > tosize)     /* e.g., from 2048 to 512 */
-               return blocks * (fromsize / tosize);
-       else                            /* e.g., from 256 to 512 */
-               return (blocks + 1) / (tosize / fromsize);
-}
-
-/* this does all of the system specific guff to get the free disk space.
-   It is derived from code in the GNU fileutils package, but has been
-   considerably mangled for use here 
-
-   results are returned in *dfree and *dsize, in 512 byte units
-*/
-static int fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
-{
-#ifdef STAT_STATFS3_OSF1
-#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
-       struct statfs fsd;
-
-       if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
-               return -1;
-#endif /* STAT_STATFS3_OSF1 */
-       
-#ifdef STAT_STATFS2_FS_DATA    /* Ultrix */
-#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)1024, (SMB_BIG_UINT)512)     
-       struct fs_data fsd;
-       
-       if (statfs (path, &fsd) != 1)
-               return -1;
-       
-       (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
-       (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
-#endif /* STAT_STATFS2_FS_DATA */
-       
-#ifdef STAT_STATFS2_BSIZE      /* 4.3BSD, SunOS 4, HP-UX, AIX */
-#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
-       struct statfs fsd;
-       
-       if (statfs (path, &fsd) < 0)
-               return -1;
-       
-#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
-       /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
-          struct statfs are truncated to 2GB.  These conditions detect that
-          truncation, presumably without botching the 4.1.1 case, in which
-          the values are not truncated.  The correct counts are stored in
-          undocumented spare fields.  */
-       if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
-               fsd.f_blocks = fsd.f_spare[0];
-               fsd.f_bfree = fsd.f_spare[1];
-               fsd.f_bavail = fsd.f_spare[2];
-       }
-#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
-#endif /* STAT_STATFS2_BSIZE */
-       
-
-#ifdef STAT_STATFS2_FSIZE      /* 4.4BSD */
-#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
-       
-       struct statfs fsd;
-       
-       if (statfs (path, &fsd) < 0)
-               return -1;
-#endif /* STAT_STATFS2_FSIZE */
-       
-#ifdef STAT_STATFS4            /* SVR3, Dynix, Irix, AIX */
-# if _AIX || defined(_CRAY)
-#  define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
-#  ifdef _CRAY
-#   define f_bavail f_bfree
-#  endif
-# else
-#  define CONVERT_BLOCKS(B) ((SMB_BIG_UINT)B)
-#  ifndef _SEQUENT_            /* _SEQUENT_ is DYNIX/ptx */
-#   ifndef DOLPHIN             /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
-#    define f_bavail f_bfree
-#   endif
-#  endif
-# endif
-       
-       struct statfs fsd;
-
-       if (statfs (path, &fsd, sizeof fsd, 0) < 0)
-               return -1;
-       /* Empirically, the block counts on most SVR3 and SVR3-derived
-          systems seem to always be in terms of 512-byte blocks,
-          no matter what value f_bsize has.  */
-
-#endif /* STAT_STATFS4 */
-
-#ifdef STAT_STATVFS            /* SVR4 */
-# define CONVERT_BLOCKS(B) \
-       adjust_blocks ((SMB_BIG_UINT)(B), fsd.f_frsize ? (SMB_BIG_UINT)fsd.f_frsize : (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
-
-#ifdef STAT_STATVFS64
-       struct statvfs64 fsd;
-       if (statvfs64(path, &fsd) < 0) return -1;
-#else
-       struct statvfs fsd;
-       if (statvfs(path, &fsd) < 0) return -1;
-#endif
-
-       /* f_frsize isn't guaranteed to be supported.  */
-
-#endif /* STAT_STATVFS */
-
-#ifndef CONVERT_BLOCKS
-       /* we don't have any dfree code! */
-       return -1;
-#else
-#if !defined(STAT_STATFS2_FS_DATA)
-       /* !Ultrix */
-       (*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
-       (*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
-#endif /* not STAT_STATFS2_FS_DATA */
-#endif
-
-       return 0;
-}
 
 /****************************************************************************
   return number of 1K blocks available on a path and total number 
 ****************************************************************************/
-static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+
+static SMB_BIG_UINT disk_free(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_q = 0;
        SMB_BIG_UINT bsize_q = 0;
        SMB_BIG_UINT dsize_q = 0;
+       char *dfree_command;
 
        (*dfree) = (*dsize) = 0;
        (*bsize) = 512;
 
-       fsusage(path, dfree, dsize);
+       /*
+        * If external disk calculation specified, use it.
+        */
+
+       dfree_command = lp_dfree_command();
+       if (dfree_command && *dfree_command) {
+               char *p;
+               char **lines;
+               pstring syscmd;
+
+               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);
+               if (lines) {
+                       char *line = lines[0];
+
+                       DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
+
+                       *dsize = (SMB_BIG_UINT)strtoul(line, &p, 10);
+                       while (p && *p & isspace(*p))
+                               p++;
+                       if (p && *p)
+                               *dfree = (SMB_BIG_UINT)strtoul(p, &p, 10);
+                       while (p && *p & isspace(*p))
+                               p++;
+                       if (p && *p)
+                               *bsize = (SMB_BIG_UINT)strtoul(p, NULL, 10);
+                       else
+                               *bsize = 1024;
+                       file_lines_free(lines);
+                       DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
+                               (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
+
+                       if (!*dsize)
+                               *dsize = 2048;
+                       if (!*dfree)
+                               *dfree = 1024;
+               } else {
+                       DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
+                               syscmd, strerror(errno) ));
+                       sys_fsusage(path, dfree, dsize);
+               }
+       } else
+               sys_fsusage(path, dfree, dsize);
 
        if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
                (*bsize) = bsize_q;
@@ -205,7 +128,7 @@ static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree
 
        /* FIXME : Any reason for this assumption ? */
        if (*bsize < 256) {
-               DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",*bsize));
+               DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize));
                *bsize = 512;
        }
 
@@ -219,7 +142,7 @@ static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree
                *dfree = MAX(1,*dfree);
        }
 
-       disk_norm(bsize,dfree,dsize);
+       disk_norm(small_query,bsize,dfree,dsize);
 
        if ((*bsize) < 1024) {
                dfree_retval = (*dfree)/(1024/(*bsize));
@@ -234,7 +157,8 @@ static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree
 /****************************************************************************
 wrap it to get filenames right
 ****************************************************************************/
-SMB_BIG_UINT sys_disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query, 
+                           SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
 {
-       return(disk_free(dos_to_unix(path,False),bsize,dfree,dsize));
+       return disk_free(path,small_query, bsize,dfree,dsize);
 }