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 2 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, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23/**************************************************************************** 24normalise for DOS usage 25****************************************************************************/ 26static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) 27{ 28 /* check if the disk is beyond the max disk size */ 29 SMB_BIG_UINT maxdisksize = lp_maxdisksize(); 30 if (maxdisksize) { 31 /* convert to blocks - and don't overflow */ 32 maxdisksize = ((maxdisksize*1024)/(*bsize))*1024; 33 if (*dsize > maxdisksize) *dsize = maxdisksize; 34 if (*dfree > maxdisksize) *dfree = maxdisksize-1; 35 /* the -1 should stop applications getting div by 0 36 errors */ 37 } 38 39 if(small_query) { 40 while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) { 41 *dfree /= 2; 42 *dsize /= 2; 43 *bsize *= 2; 44 /* 45 * Force max to fit in 16 bit fields. 46 */ 47 if (*bsize > (WORDMAX*512)) { 48 *bsize = (WORDMAX*512); 49 if (*dsize > WORDMAX) 50 *dsize = WORDMAX; 51 if (*dfree > WORDMAX) 52 *dfree = WORDMAX; 53 break; 54 } 55 } 56 } 57} 58 59 60 61/**************************************************************************** 62 return number of 1K blocks available on a path and total number 63****************************************************************************/ 64 65static SMB_BIG_UINT disk_free(const char *path, BOOL small_query, 66 SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) 67{ 68 int dfree_retval; 69 SMB_BIG_UINT dfree_q = 0; 70 SMB_BIG_UINT bsize_q = 0; 71 SMB_BIG_UINT dsize_q = 0; 72 char *dfree_command; 73 74 (*dfree) = (*dsize) = 0; 75 (*bsize) = 512; 76 77 /* 78 * If external disk calculation specified, use it. 79 */ 80 81 dfree_command = lp_dfree_command(); 82 if (dfree_command && *dfree_command) { 83 const char *p; 84 char **lines; 85 pstring syscmd; 86 87 slprintf(syscmd, sizeof(syscmd)-1, "%s %s", dfree_command, path); 88 DEBUG (3, ("disk_free: Running command %s\n", syscmd)); 89 90 lines = file_lines_pload(syscmd, NULL); 91 if (lines) { 92 char *line = lines[0]; 93 94 DEBUG (3, ("Read input from dfree, \"%s\"\n", line)); 95 96 *dsize = STR_TO_SMB_BIG_UINT(line, &p); 97 while (p && *p && isspace(*p)) 98 p++; 99 if (p && *p) 100 *dfree = STR_TO_SMB_BIG_UINT(p, &p); 101 while (p && *p && isspace(*p)) 102 p++; 103 if (p && *p) 104 *bsize = STR_TO_SMB_BIG_UINT(p, NULL); 105 else 106 *bsize = 1024; 107 file_lines_free(lines); 108 DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n", 109 (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize)); 110 111 if (!*dsize) 112 *dsize = 2048; 113 if (!*dfree) 114 *dfree = 1024; 115 } else { 116 DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n", 117 syscmd, strerror(errno) )); 118 if (sys_fsusage(path, dfree, dsize) != 0) { 119 DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n", 120 strerror(errno) )); 121 return (SMB_BIG_UINT)-1; 122 } 123 } 124 } else { 125 if (sys_fsusage(path, dfree, dsize) != 0) { 126 DEBUG (0, ("disk_free: sys_fsusage() failed. Error was : %s\n", 127 strerror(errno) )); 128 return (SMB_BIG_UINT)-1; 129 } 130 } 131 132 if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) { 133 (*bsize) = bsize_q; 134 (*dfree) = MIN(*dfree,dfree_q); 135 (*dsize) = MIN(*dsize,dsize_q); 136 } 137 138 /* FIXME : Any reason for this assumption ? */ 139 if (*bsize < 256) { 140 DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize)); 141 *bsize = 512; 142 } 143 144 if ((*dsize)<1) { 145 static int done; 146 if (!done) { 147 DEBUG(0,("WARNING: dfree is broken on this system\n")); 148 done=1; 149 } 150 *dsize = 20*1024*1024/(*bsize); 151 *dfree = MAX(1,*dfree); 152 } 153 154 disk_norm(small_query,bsize,dfree,dsize); 155 156 if ((*bsize) < 1024) { 157 dfree_retval = (*dfree)/(1024/(*bsize)); 158 } else { 159 dfree_retval = ((*bsize)/1024)*(*dfree); 160 } 161 162 return(dfree_retval); 163} 164 165 166/**************************************************************************** 167wrap it to get filenames right 168****************************************************************************/ 169SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query, 170 SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) 171{ 172 return disk_free(path,small_query, bsize,dfree,dsize); 173} 174