2 Unix SMB/CIFS implementation.
3 functions to calculate the free disk space
4 Copyright (C) Andrew Tridgell 1998
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.
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.
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/>.
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "lib/util_file.h"
25 /****************************************************************************
26 Normalise for DOS usage.
27 ****************************************************************************/
29 static void disk_norm(uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
31 /* check if the disk is beyond the max disk size */
32 uint64_t maxdisksize
= lp_max_disk_size();
34 /* convert to blocks - and don't overflow */
35 maxdisksize
= ((maxdisksize
*1024)/(*bsize
))*1024;
36 if (*dsize
> maxdisksize
) {
39 if (*dfree
> maxdisksize
) {
40 *dfree
= maxdisksize
- 1;
42 /* the -1 should stop applications getting div by 0
49 /****************************************************************************
50 Return number of 1K blocks available on a path and total number.
51 ****************************************************************************/
53 uint64_t sys_disk_free(connection_struct
*conn
, struct smb_filename
*fname
,
54 uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
56 uint64_t dfree_retval
;
60 const char *dfree_command
;
61 static bool dfree_broken
= false;
62 const char *path
= fname
->base_name
;
64 (*dfree
) = (*dsize
) = 0;
68 * If external disk calculation specified, use it.
71 dfree_command
= lp_dfree_command(talloc_tos(), SNUM(conn
));
72 if (dfree_command
&& *dfree_command
) {
77 syscmd
= talloc_asprintf(talloc_tos(),
86 DEBUG (3, ("disk_free: Running command '%s'\n", syscmd
));
88 lines
= file_lines_pload(talloc_tos(), syscmd
, NULL
);
90 char *line
= lines
[0];
92 DEBUG (3, ("Read input from dfree, \"%s\"\n", line
));
94 *dsize
= STR_TO_SMB_BIG_UINT(line
, &p
);
95 while (p
&& *p
&& isspace(*p
))
98 *dfree
= STR_TO_SMB_BIG_UINT(p
, &p
);
99 while (p
&& *p
&& isspace(*p
))
102 *bsize
= STR_TO_SMB_BIG_UINT(p
, NULL
);
106 DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
107 (unsigned int)*dsize
, (unsigned int)*dfree
, (unsigned int)*bsize
));
116 DEBUG (0, ("disk_free: file_lines_load() failed for "
117 "command '%s'. Error was : %s\n",
118 syscmd
, strerror(errno
) ));
121 if (SMB_VFS_DISK_FREE(conn
, path
, bsize
, dfree
, dsize
) ==
123 DBG_ERR("VFS disk_free failed. Error was : %s\n",
128 if (disk_quotas(conn
, fname
, &bsize_q
, &dfree_q
, &dsize_q
)) {
129 uint64_t min_bsize
= MIN(*bsize
, bsize_q
);
131 (*dfree
) = (*dfree
) * (*bsize
) / min_bsize
;
132 (*dsize
) = (*dsize
) * (*bsize
) / min_bsize
;
133 dfree_q
= dfree_q
* bsize_q
/ min_bsize
;
134 dsize_q
= dsize_q
* bsize_q
/ min_bsize
;
136 (*bsize
) = min_bsize
;
137 (*dfree
) = MIN(*dfree
,dfree_q
);
138 (*dsize
) = MIN(*dsize
,dsize_q
);
141 /* FIXME : Any reason for this assumption ? */
143 DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize
));
149 DEBUG(0,("WARNING: dfree is broken on this system\n"));
152 *dsize
= 20*1024*1024/(*bsize
);
153 *dfree
= MAX(1,*dfree
);
157 disk_norm(bsize
, dfree
, dsize
);
159 if ((*bsize
) < 1024) {
160 dfree_retval
= (*dfree
)/(1024/(*bsize
));
162 dfree_retval
= ((*bsize
)/1024)*(*dfree
);
165 return(dfree_retval
);
168 /****************************************************************************
169 Potentially returned cached dfree info.
170 ****************************************************************************/
172 uint64_t get_dfree_info(connection_struct
*conn
, struct smb_filename
*fname
,
173 uint64_t *bsize
, uint64_t *dfree
, uint64_t *dsize
)
175 int dfree_cache_time
= lp_dfree_cache_time(SNUM(conn
));
176 struct dfree_cached_info
*dfc
= conn
->dfree_info
;
179 if (!dfree_cache_time
) {
180 return sys_disk_free(conn
, fname
, bsize
, dfree
, dsize
);
183 if (dfc
&& (conn
->lastused
- dfc
->last_dfree_time
< dfree_cache_time
)) {
184 /* Return cached info. */
188 return dfc
->dfree_ret
;
191 dfree_ret
= sys_disk_free(conn
, fname
, bsize
, dfree
, dsize
);
193 if (dfree_ret
== (uint64_t)-1) {
194 /* Don't cache bad data. */
198 /* No cached info or time to refresh. */
200 dfc
= talloc(conn
, struct dfree_cached_info
);
204 conn
->dfree_info
= dfc
;
210 dfc
->dfree_ret
= dfree_ret
;
211 dfc
->last_dfree_time
= conn
->lastused
;