root/source3/smbd/dfree.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. disk_norm
  2. sys_disk_free
  3. get_dfree_info

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    functions to calculate the free disk space
   4    Copyright (C) Andrew Tridgell 1998
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 #include "smbd/globals.h"
  22 
  23 /****************************************************************************
  24  Normalise for DOS usage.
  25 ****************************************************************************/
  26 
  27 static void disk_norm(bool small_query, uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
     /* [<][>][^][v][top][bottom][index][help] */
  28 {
  29         /* check if the disk is beyond the max disk size */
  30         uint64_t maxdisksize = lp_maxdisksize();
  31         if (maxdisksize) {
  32                 /* convert to blocks - and don't overflow */
  33                 maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
  34                 if (*dsize > maxdisksize) *dsize = maxdisksize;
  35                 if (*dfree > maxdisksize) *dfree = maxdisksize-1; 
  36                 /* the -1 should stop applications getting div by 0
  37                    errors */
  38         }  
  39 
  40         if(small_query) {       
  41                 while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
  42                         *dfree /= 2;
  43                         *dsize /= 2;
  44                         *bsize *= 2;
  45                         /*
  46                          * Force max to fit in 16 bit fields.
  47                          */
  48                         if (*bsize > (WORDMAX*512)) {
  49                                 *bsize = (WORDMAX*512);
  50                                 if (*dsize > WORDMAX)
  51                                         *dsize = WORDMAX;
  52                                 if (*dfree >  WORDMAX)
  53                                         *dfree = WORDMAX;
  54                                 break;
  55                         }
  56                 }
  57         }
  58 }
  59 
  60 
  61 
  62 /****************************************************************************
  63  Return number of 1K blocks available on a path and total number.
  64 ****************************************************************************/
  65 
  66 uint64_t sys_disk_free(connection_struct *conn, const char *path, bool small_query, 
     /* [<][>][^][v][top][bottom][index][help] */
  67                               uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
  68 {
  69         uint64_t dfree_retval;
  70         uint64_t dfree_q = 0;
  71         uint64_t bsize_q = 0;
  72         uint64_t dsize_q = 0;
  73         const char *dfree_command;
  74 
  75         (*dfree) = (*dsize) = 0;
  76         (*bsize) = 512;
  77 
  78         /*
  79          * If external disk calculation specified, use it.
  80          */
  81 
  82         dfree_command = lp_dfree_command(SNUM(conn));
  83         if (dfree_command && *dfree_command) {
  84                 const char *p;
  85                 char **lines = NULL;
  86                 char *syscmd = NULL;
  87 
  88                 syscmd = talloc_asprintf(talloc_tos(),
  89                                 "%s %s",
  90                                 dfree_command,
  91                                 path);
  92 
  93                 if (!syscmd) {
  94                         return (uint64_t)-1;
  95                 }
  96 
  97                 DEBUG (3, ("disk_free: Running command %s\n", syscmd));
  98 
  99                 lines = file_lines_pload(syscmd, NULL);
 100                 if (lines) {
 101                         char *line = lines[0];
 102 
 103                         DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
 104 
 105                         *dsize = STR_TO_SMB_BIG_UINT(line, &p);
 106                         while (p && *p && isspace(*p))
 107                                 p++;
 108                         if (p && *p)
 109                                 *dfree = STR_TO_SMB_BIG_UINT(p, &p);
 110                         while (p && *p && isspace(*p))
 111                                 p++;
 112                         if (p && *p)
 113                                 *bsize = STR_TO_SMB_BIG_UINT(p, NULL);
 114                         else
 115                                 *bsize = 1024;
 116                         TALLOC_FREE(lines);
 117                         DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
 118                                 (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
 119 
 120                         if (!*dsize)
 121                                 *dsize = 2048;
 122                         if (!*dfree)
 123                                 *dfree = 1024;
 124                 } else {
 125                         DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
 126                                 syscmd, strerror(errno) ));
 127                         if (sys_fsusage(path, dfree, dsize) != 0) {
 128                                 DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
 129                                         strerror(errno) ));
 130                                 return (uint64_t)-1;
 131                         }
 132                 }
 133         } else {
 134                 if (sys_fsusage(path, dfree, dsize) != 0) {
 135                         DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n",
 136                                 strerror(errno) ));
 137                         return (uint64_t)-1;
 138                 }
 139         }
 140 
 141         if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
 142                 (*bsize) = bsize_q;
 143                 (*dfree) = MIN(*dfree,dfree_q);
 144                 (*dsize) = MIN(*dsize,dsize_q);
 145         }
 146 
 147         /* FIXME : Any reason for this assumption ? */
 148         if (*bsize < 256) {
 149                 DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize));
 150                 *bsize = 512;
 151         }
 152 
 153         if ((*dsize)<1) {
 154                 if (!dfree_broken) {
 155                         DEBUG(0,("WARNING: dfree is broken on this system\n"));
 156                         dfree_broken=true;
 157                 }
 158                 *dsize = 20*1024*1024/(*bsize);
 159                 *dfree = MAX(1,*dfree);
 160         }
 161 
 162         disk_norm(small_query,bsize,dfree,dsize);
 163 
 164         if ((*bsize) < 1024) {
 165                 dfree_retval = (*dfree)/(1024/(*bsize));
 166         } else {
 167                 dfree_retval = ((*bsize)/1024)*(*dfree);
 168         }
 169 
 170         return(dfree_retval);
 171 }
 172 
 173 /****************************************************************************
 174  Potentially returned cached dfree info.
 175 ****************************************************************************/
 176 
 177 uint64_t get_dfree_info(connection_struct *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 178                         const char *path,
 179                         bool small_query,
 180                         uint64_t *bsize,
 181                         uint64_t *dfree,
 182                         uint64_t *dsize)
 183 {
 184         int dfree_cache_time = lp_dfree_cache_time(SNUM(conn));
 185         struct dfree_cached_info *dfc = conn->dfree_info;
 186         uint64_t dfree_ret;
 187 
 188         if (!dfree_cache_time) {
 189                 return SMB_VFS_DISK_FREE(conn,path,small_query,bsize,dfree,dsize);
 190         }
 191 
 192         if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
 193                 /* Return cached info. */
 194                 *bsize = dfc->bsize;
 195                 *dfree = dfc->dfree;
 196                 *dsize = dfc->dsize;
 197                 return dfc->dfree_ret;
 198         }
 199 
 200         dfree_ret = SMB_VFS_DISK_FREE(conn,path,small_query,bsize,dfree,dsize);
 201 
 202         if (dfree_ret == (uint64_t)-1) {
 203                 /* Don't cache bad data. */
 204                 return dfree_ret;
 205         }
 206 
 207         /* No cached info or time to refresh. */
 208         if (!dfc) {
 209                 dfc = TALLOC_P(conn, struct dfree_cached_info);
 210                 if (!dfc) {
 211                         return dfree_ret;
 212                 }
 213                 conn->dfree_info = dfc;
 214         }
 215 
 216         dfc->bsize = *bsize;
 217         dfc->dfree = *dfree;
 218         dfc->dsize = *dsize;
 219         dfc->dfree_ret = dfree_ret;
 220         dfc->last_dfree_time = conn->lastused;
 221 
 222         return dfree_ret;
 223 }

/* [<][>][^][v][top][bottom][index][help] */