aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert2017-10-01 22:31:39 -0700
committerPaul Eggert2017-10-01 22:33:20 -0700
commit135bca574c31b7bf6df6c63d28f180956928dde7 (patch)
tree1259c514b5304e7b1dbb8a9098f0a6dd63e00003 /lib
parent4829a3b033b119b088947d14b73efc197b2547fa (diff)
downloademacs-135bca574c31b7bf6df6c63d28f180956928dde7.tar.gz
emacs-135bca574c31b7bf6df6c63d28f180956928dde7.zip
Port file-system-info to non-Microsoft
* admin/merge-gnulib (GNULIB_MODULES): Add fsusage. * doc/emacs/files.texi (Directories): Remove documentation of now-obsolete directory-free-space-program and directory-free-space-args. * etc/NEWS: Mention change. * etc/PROBLEMS: Slow df is no longer a problem. * lib/fsusage.c, lib/fsusage.h, m4/fsusage.m4: New files, copied from Gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lisp/dired.el (dired-free-space-program) (dired-free-space-args): These aliases are now obsolete. * lisp/files.el (directory-free-space-program) (directory-free-space-args): Now obsolete. (get-free-disk-space): Just call file-system-info instead of the now-obsolete directory-free-space-program. * nt/gnulib-cfg.mk (OMIT_GNULIB_MODULE_fsusage): New macro. * src/fileio.c: Include fsusage.h. (blocks_to_bytes, Ffile_system_info) [!DOS_NT]: New functions. (syms_of_fileio) [!DOS_NT]: Defsubr file-system-info.
Diffstat (limited to 'lib')
-rw-r--r--lib/fsusage.c288
-rw-r--r--lib/fsusage.h40
-rw-r--r--lib/gnulib.mk.in13
3 files changed, 340 insertions, 1 deletions
diff --git a/lib/fsusage.c b/lib/fsusage.c
new file mode 100644
index 00000000000..a0f763be05f
--- /dev/null
+++ b/lib/fsusage.c
@@ -0,0 +1,288 @@
1/* fsusage.c -- return space usage of mounted file systems
2
3 Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2017 Free Software
4 Foundation, Inc.
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 <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include "fsusage.h"
22
23#include <limits.h>
24#include <sys/types.h>
25
26#if STAT_STATVFS || STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
27# include <sys/statvfs.h>
28#else
29/* Don't include backward-compatibility files unless they're needed.
30 Eventually we'd like to remove all this cruft. */
31# include <fcntl.h>
32# include <unistd.h>
33# include <sys/stat.h>
34#if HAVE_SYS_PARAM_H
35# include <sys/param.h>
36#endif
37#if HAVE_SYS_MOUNT_H
38# include <sys/mount.h>
39#endif
40#if HAVE_SYS_VFS_H
41# include <sys/vfs.h>
42#endif
43# if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
44# include <sys/fs/s5param.h>
45# endif
46# if HAVE_SYS_STATFS_H
47# include <sys/statfs.h>
48# endif
49# if HAVE_DUSTAT_H /* AIX PS/2 */
50# include <sys/dustat.h>
51# endif
52# include "full-read.h"
53#endif
54
55/* Many space usage primitives use all 1 bits to denote a value that is
56 not applicable or unknown. Propagate this information by returning
57 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
58 is unsigned and narrower than uintmax_t. */
59#define PROPAGATE_ALL_ONES(x) \
60 ((sizeof (x) < sizeof (uintmax_t) \
61 && (~ (x) == (sizeof (x) < sizeof (int) \
62 ? - (1 << (sizeof (x) * CHAR_BIT)) \
63 : 0))) \
64 ? UINTMAX_MAX : (uintmax_t) (x))
65
66/* Extract the top bit of X as an uintmax_t value. */
67#define EXTRACT_TOP_BIT(x) ((x) \
68 & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
69
70/* If a value is negative, many space usage primitives store it into an
71 integer variable by assignment, even if the variable's type is unsigned.
72 So, if a space usage variable X's top bit is set, convert X to the
73 uintmax_t value V such that (- (uintmax_t) V) is the negative of
74 the original value. If X's top bit is clear, just yield X.
75 Use PROPAGATE_TOP_BIT if the original value might be negative;
76 otherwise, use PROPAGATE_ALL_ONES. */
77#define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
78
79#ifdef STAT_STATVFS
80/* Return true if statvfs works. This is false for statvfs on systems
81 with GNU libc on Linux kernels before 2.6.36, which stats all
82 preceding entries in /proc/mounts; that makes df hang if even one
83 of the corresponding file systems is hard-mounted but not available. */
84# if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
85/* The FRSIZE fallback is not required in this case. */
86# undef STAT_STATFS2_FRSIZE
87static int statvfs_works (void) { return 1; }
88# else
89# include <string.h> /* for strverscmp */
90# include <sys/utsname.h>
91# include <sys/statfs.h>
92# define STAT_STATFS2_BSIZE 1
93
94static int
95statvfs_works (void)
96{
97 static int statvfs_works_cache = -1;
98 struct utsname name;
99 if (statvfs_works_cache < 0)
100 statvfs_works_cache = (uname (&name) == 0
101 && 0 <= strverscmp (name.release, "2.6.36"));
102 return statvfs_works_cache;
103}
104# endif
105#endif
106
107
108/* Fill in the fields of FSP with information about space usage for
109 the file system on which FILE resides.
110 DISK is the device on which FILE is mounted, for space-getting
111 methods that need to know it.
112 Return 0 if successful, -1 if not. When returning -1, ensure that
113 ERRNO is either a system error value, or zero if DISK is NULL
114 on a system that requires a non-NULL value. */
115int
116get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
117{
118#ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
119
120 if (statvfs_works ())
121 {
122 struct statvfs vfsd;
123
124 if (statvfs (file, &vfsd) < 0)
125 return -1;
126
127 /* f_frsize isn't guaranteed to be supported. */
128 fsp->fsu_blocksize = (vfsd.f_frsize
129 ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
130 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
131
132 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
133 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
134 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
135 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
136 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
137 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
138 return 0;
139 }
140
141#endif
142
143#if defined STAT_STATVFS64 /* AIX */
144
145 struct statvfs64 fsd;
146
147 if (statvfs64 (file, &fsd) < 0)
148 return -1;
149
150 /* f_frsize isn't guaranteed to be supported. */
151 fsp->fsu_blocksize = (fsd.f_frsize
152 ? PROPAGATE_ALL_ONES (fsd.f_frsize)
153 : PROPAGATE_ALL_ONES (fsd.f_bsize));
154
155#elif defined STAT_STATFS2_FS_DATA /* Ultrix */
156
157 struct fs_data fsd;
158
159 if (statfs (file, &fsd) != 1)
160 return -1;
161
162 fsp->fsu_blocksize = 1024;
163 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
164 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
165 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
166 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
167 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
168 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
169
170#elif defined STAT_STATFS3_OSF1 /* OSF/1 */
171
172 struct statfs fsd;
173
174 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
175 return -1;
176
177 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
178
179#elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
180
181 struct statfs fsd;
182
183 if (statfs (file, &fsd) < 0)
184 return -1;
185
186 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
187
188#elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
189 Mac OS X < 10.4, FreeBSD < 5.0, \
190 NetBSD < 3.0, OpenBSD < 4.4 */
191
192 struct statfs fsd;
193
194 if (statfs (file, &fsd) < 0)
195 return -1;
196
197 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
198
199# ifdef STATFS_TRUNCATES_BLOCK_COUNTS
200
201 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
202 struct statfs are truncated to 2GB. These conditions detect that
203 truncation, presumably without botching the 4.1.1 case, in which
204 the values are not truncated. The correct counts are stored in
205 undocumented spare fields. */
206 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
207 {
208 fsd.f_blocks = fsd.f_spare[0];
209 fsd.f_bfree = fsd.f_spare[1];
210 fsd.f_bavail = fsd.f_spare[2];
211 }
212# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
213
214#elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
215
216 struct statfs fsd;
217
218 if (statfs (file, &fsd) < 0)
219 return -1;
220
221 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
222
223#elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
224 Dolphin */
225
226# if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
227# define f_bavail f_bfree
228# endif
229
230 struct statfs fsd;
231
232 if (statfs (file, &fsd, sizeof fsd, 0) < 0)
233 return -1;
234
235 /* Empirically, the block counts on most SVR3 and SVR3-derived
236 systems seem to always be in terms of 512-byte blocks,
237 no matter what value f_bsize has. */
238# if _AIX || defined _CRAY
239 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
240# else
241 fsp->fsu_blocksize = 512;
242# endif
243
244#endif
245
246#if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
247 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
248 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
249
250 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
251 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
252 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
253 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
254 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
255 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
256
257#endif
258
259 (void) disk; /* avoid argument-unused warning */
260 return 0;
261}
262
263#if defined _AIX && defined _I386
264/* AIX PS/2 does not supply statfs. */
265
266int
267statfs (char *file, struct statfs *fsb)
268{
269 struct stat stats;
270 struct dustat fsd;
271
272 if (stat (file, &stats) != 0)
273 return -1;
274 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
275 return -1;
276 fsb->f_type = 0;
277 fsb->f_bsize = fsd.du_bsize;
278 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
279 fsb->f_bfree = fsd.du_tfree;
280 fsb->f_bavail = fsd.du_tfree;
281 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
282 fsb->f_ffree = fsd.du_tinode;
283 fsb->f_fsid.val[0] = fsd.du_site;
284 fsb->f_fsid.val[1] = fsd.du_pckno;
285 return 0;
286}
287
288#endif /* _AIX && _I386 */
diff --git a/lib/fsusage.h b/lib/fsusage.h
new file mode 100644
index 00000000000..f78edc6a0cb
--- /dev/null
+++ b/lib/fsusage.h
@@ -0,0 +1,40 @@
1/* fsusage.h -- declarations for file system space usage info
2
3 Copyright (C) 1991-1992, 1997, 2003-2006, 2009-2017 Free Software
4 Foundation, Inc.
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 <https://www.gnu.org/licenses/>. */
18
19/* Space usage statistics for a file system. Blocks are 512-byte. */
20
21#if !defined FSUSAGE_H_
22# define FSUSAGE_H_
23
24# include <stdint.h>
25# include <stdbool.h>
26
27struct fs_usage
28{
29 uintmax_t fsu_blocksize; /* Size of a block. */
30 uintmax_t fsu_blocks; /* Total blocks. */
31 uintmax_t fsu_bfree; /* Free blocks available to superuser. */
32 uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
33 bool fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
34 uintmax_t fsu_files; /* Total file nodes. */
35 uintmax_t fsu_ffree; /* Free file nodes. */
36};
37
38int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp);
39
40#endif
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 0f795b3d820..e9358a6855d 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -21,7 +21,7 @@
21# the same distribution terms as the rest of that program. 21# the same distribution terms as the rest of that program.
22# 22#
23# Generated by gnulib-tool. 23# Generated by gnulib-tool.
24# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 d-type diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time tempname time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings 24# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 d-type diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsusage fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time tempname time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings
25 25
26 26
27MOSTLYCLEANFILES += core *.stackdump 27MOSTLYCLEANFILES += core *.stackdump
@@ -1516,6 +1516,17 @@ EXTRA_libgnu_a_SOURCES += at-func.c fstatat.c
1516endif 1516endif
1517## end gnulib module fstatat 1517## end gnulib module fstatat
1518 1518
1519## begin gnulib module fsusage
1520ifeq (,$(OMIT_GNULIB_MODULE_fsusage))
1521
1522
1523EXTRA_DIST += fsusage.c fsusage.h
1524
1525EXTRA_libgnu_a_SOURCES += fsusage.c
1526
1527endif
1528## end gnulib module fsusage
1529
1519## begin gnulib module fsync 1530## begin gnulib module fsync
1520ifeq (,$(OMIT_GNULIB_MODULE_fsync)) 1531ifeq (,$(OMIT_GNULIB_MODULE_fsync))
1521 1532