s3:smbd: move pending_auth_data list to struct smbd_server_connection
[kai/samba.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 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)
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, 
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,
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 }