~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/smbd/dfree.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}