/src/samba/lib/util/fsusage.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | functions to calculate the free disk space |
4 | | Copyright (C) Andrew Tridgell 1998-2000 |
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 "replace.h" |
21 | | #include "lib/util/samba_util.h" |
22 | | #include "system/filesys.h" |
23 | | |
24 | | /** |
25 | | * @file |
26 | | * @brief Utility functions for getting the amount of free disk space |
27 | | */ |
28 | | |
29 | | /* Return the number of TOSIZE-byte blocks used by |
30 | | BLOCKS FROMSIZE-byte blocks, rounding away from zero. |
31 | | */ |
32 | | static uint64_t adjust_blocks(uint64_t blocks, uint64_t fromsize, uint64_t tosize) |
33 | 0 | { |
34 | 0 | if (fromsize == tosize) { /* e.g., from 512 to 512 */ |
35 | 0 | return blocks; |
36 | 0 | } |
37 | | |
38 | 0 | if (fromsize > tosize) { /* e.g., from 2048 to 512 */ |
39 | 0 | return blocks * (fromsize / tosize); |
40 | 0 | } |
41 | | |
42 | | /* e.g., from 256 to 512 */ |
43 | | /* Protect against broken filesystems... */ |
44 | | |
45 | 0 | if (fromsize == 0) { |
46 | 0 | fromsize = tosize; |
47 | 0 | } |
48 | |
|
49 | 0 | return (blocks + 1) / (tosize / fromsize); |
50 | 0 | } |
51 | | |
52 | | /** |
53 | | * Retrieve amount of free disk space. |
54 | | * this does all of the system specific guff to get the free disk space. |
55 | | * It is derived from code in the GNU fileutils package, but has been |
56 | | * considerably mangled for use here |
57 | | * |
58 | | * results are returned in *dfree and *dsize, in 512 byte units |
59 | | */ |
60 | | _PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize) |
61 | 0 | { |
62 | | #ifdef STAT_STATFS3_OSF1 |
63 | | #define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512) |
64 | | struct statfs fsd; |
65 | | |
66 | | if (statfs (path, &fsd, sizeof (struct statfs)) != 0) |
67 | | return -1; |
68 | | #endif /* STAT_STATFS3_OSF1 */ |
69 | |
|
70 | | #ifdef STAT_STATFS2_FS_DATA /* Ultrix */ |
71 | | #define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)1024, (uint64_t)512) |
72 | | struct fs_data fsd; |
73 | | |
74 | | if (statfs (path, &fsd) != 1) |
75 | | return -1; |
76 | | |
77 | | (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot); |
78 | | (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen); |
79 | | #endif /* STAT_STATFS2_FS_DATA */ |
80 | |
|
81 | | #ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */ |
82 | | #define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512) |
83 | | struct statfs fsd; |
84 | | |
85 | | if (statfs (path, &fsd) < 0) |
86 | | return -1; |
87 | | |
88 | | #ifdef STATFS_TRUNCATES_BLOCK_COUNTS |
89 | | /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the |
90 | | struct statfs are truncated to 2GB. These conditions detect that |
91 | | truncation, presumably without botching the 4.1.1 case, in which |
92 | | the values are not truncated. The correct counts are stored in |
93 | | undocumented spare fields. */ |
94 | | if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) { |
95 | | fsd.f_blocks = fsd.f_spare[0]; |
96 | | fsd.f_bfree = fsd.f_spare[1]; |
97 | | fsd.f_bavail = fsd.f_spare[2]; |
98 | | } |
99 | | #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */ |
100 | | #endif /* STAT_STATFS2_BSIZE */ |
101 | | |
102 | |
|
103 | | #ifdef STAT_STATFS2_FSIZE /* 4.4BSD */ |
104 | | #define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512) |
105 | | |
106 | | struct statfs fsd; |
107 | | |
108 | | if (statfs (path, &fsd) < 0) |
109 | | return -1; |
110 | | #endif /* STAT_STATFS2_FSIZE */ |
111 | |
|
112 | | #ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */ |
113 | | # if _AIX || defined(_CRAY) |
114 | | # define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512) |
115 | | # ifdef _CRAY |
116 | | # define f_bavail f_bfree |
117 | | # endif |
118 | | # else |
119 | | # define CONVERT_BLOCKS(B) ((uint64_t)B) |
120 | | # ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */ |
121 | | # ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */ |
122 | | # define f_bavail f_bfree |
123 | | # endif |
124 | | # endif |
125 | | # endif |
126 | | |
127 | | struct statfs fsd; |
128 | | |
129 | | if (statfs (path, &fsd, sizeof fsd, 0) < 0) |
130 | | return -1; |
131 | | /* Empirically, the block counts on most SVR3 and SVR3-derived |
132 | | systems seem to always be in terms of 512-byte blocks, |
133 | | no matter what value f_bsize has. */ |
134 | | |
135 | | #endif /* STAT_STATFS4 */ |
136 | |
|
137 | 0 | #if defined(STAT_STATVFS) /* SVR4 */ |
138 | 0 | #ifdef HAVE_FRSIZE |
139 | 0 | # define CONVERT_BLOCKS(B) \ |
140 | 0 | adjust_blocks ((uint64_t)(B), fsd.f_frsize ? (uint64_t)fsd.f_frsize : (uint64_t)fsd.f_bsize, (uint64_t)512) |
141 | | #else |
142 | | # define CONVERT_BLOCKS(B) \ |
143 | | adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512) |
144 | | #endif |
145 | |
|
146 | 0 | struct statvfs fsd; |
147 | 0 | if (statvfs(path, &fsd) < 0) return -1; |
148 | | |
149 | | /* f_frsize isn't guaranteed to be supported. */ |
150 | | |
151 | 0 | #endif /* STAT_STATVFS */ |
152 | | |
153 | | #ifndef CONVERT_BLOCKS |
154 | | /* we don't have any dfree code! */ |
155 | | return -1; |
156 | | #else |
157 | 0 | #if !defined(STAT_STATFS2_FS_DATA) |
158 | | /* !Ultrix */ |
159 | 0 | (*dsize) = CONVERT_BLOCKS (fsd.f_blocks); |
160 | 0 | (*dfree) = CONVERT_BLOCKS (fsd.f_bavail); |
161 | 0 | #endif /* not STAT_STATFS2_FS_DATA */ |
162 | 0 | #endif |
163 | |
|
164 | 0 | return 0; |
165 | 0 | } |