This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[sfrench/samba-autobuild/.git] / source3 / smbd / dfree.c
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 /****************************************************************************
24 normalise for DOS usage 
25 ****************************************************************************/
26 static 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         while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
40                 *dfree /= 2;
41                 *dsize /= 2;
42                 *bsize *= 2;
43                 if(small_query) {       
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
65 static 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                         sys_fsusage(path, dfree, dsize);
119                 }
120         } else
121                 sys_fsusage(path, dfree, dsize);
122
123         if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
124                 (*bsize) = bsize_q;
125                 (*dfree) = MIN(*dfree,dfree_q);
126                 (*dsize) = MIN(*dsize,dsize_q);
127         }
128
129         /* FIXME : Any reason for this assumption ? */
130         if (*bsize < 256) {
131                 DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize));
132                 *bsize = 512;
133         }
134
135         if ((*dsize)<1) {
136                 static int done;
137                 if (!done) {
138                         DEBUG(0,("WARNING: dfree is broken on this system\n"));
139                         done=1;
140                 }
141                 *dsize = 20*1024*1024/(*bsize);
142                 *dfree = MAX(1,*dfree);
143         }
144
145         disk_norm(small_query,bsize,dfree,dsize);
146
147         if ((*bsize) < 1024) {
148                 dfree_retval = (*dfree)/(1024/(*bsize));
149         } else {
150                 dfree_retval = ((*bsize)/1024)*(*dfree);
151         }
152
153         return(dfree_retval);
154 }
155
156
157 /****************************************************************************
158 wrap it to get filenames right
159 ****************************************************************************/
160 SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query, 
161                            SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
162 {
163         return disk_free(path,small_query, bsize,dfree,dsize);
164 }