unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
@ 2017-09-29  4:01 YAMAMOTO Mitsuharu
  2017-09-29 17:11 ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: YAMAMOTO Mitsuharu @ 2017-09-29  4:01 UTC (permalink / raw)
  To: 28639

The function `get-free-disk-space' in files.el gives free inode count
rather than free data block space on OS X 10.8 and later.  This is
because it relies on the "df" command and parse the output as follows:

	    ;; Assume that the "available" column is before the
	    ;; "capacity" column.  Find the "%" and scan backward.
	    (goto-char (point-min))
	    (forward-line 1)
	    (when (re-search-forward
		   "[[:space:]]+[^[:space:]]+%[^%]*$"
		   (line-end-position) t)
	      (goto-char (match-beginning 0))
	      (let ((endpt (point)))
		(skip-chars-backward "^[:space:]")
		(buffer-substring-no-properties (point) endpt)))))))))

The output on OS X 10.8 looks like this:

Filesystem    512-blocks      Used  Available Capacity iused      ifree %iused  Mounted on
/dev/disk2    1996082176 172984304 1822585872     9% 2508930 4292458349    0%   /
devfs                371       371          0   100%     642          0  100%   /dev
map -hosts             0         0          0   100%       0          0  100%   /net
map auto_home          0         0          0   100%       0          0  100%   /home

So, `get-free-disk-space' adopts the "ifree" column rather than the
"Available" column.

One could use the "-P" option to suppress the inode columns.  But this
doesn't seem to be smart (cf. Bug#6995).

Some platforms rely on the primitive function `file-system-info'
instead of the "df" output to get free space.  How about implementing
`file-system-info' also for other platforms using the fsusage module
in Gnulib?

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

In GNU Emacs 26.0.60 (build 1, x86_64-apple-darwin16.7.0, X toolkit, Xaw3d scroll bars)
 of 2017-09-29 built on YAMAMOTO-no-iMac-5K.local
Repository revision: af130f900fc499f71ea22f10ba055a75ce35ed4e
Windowing system distributor 'The X.Org Foundation', version 11.0.11804000
Recent messages:
Loading /usr/local/pkg/ProofGeneral/generic/proof-site.el (source)...done
For information about GNU Emacs and the GNU system, type C-h C-a.

Configured using:
 'configure --without-ns --with-jpeg=no --with-gif=no --with-tiff=no
 --with-gnutls=no PKG_CONFIG=/opt/local/bin/pkg-config
 PKG_CONFIG_PATH=/usr/lib/pkgconfig:/opt/X11/lib/pkgconfig:/usr/local/lib/pkgconfig
 PKG_CONFIG_LIBDIR='

Configured features:
XAW3D XPM PNG NOTIFY ACL LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB
TOOLKIT_SCROLL_BARS LUCID X11

Important settings:
  value of $LANG: ja_JP.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Fundamental

Minor modes in effect:
  TeX-PDF-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  buffer-read-only: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug message subr-x puny dired dired-loaddefs
format-spec rfc822 mml mml-sec epa derived epg gnus-util rmail
rmail-loaddefs mm-decode mm-bodies mm-encode mail-parse rfc2231
mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums
mm-util mail-prsvr mail-utils elec-pair ccc proof-site proof-autoloads
pg-vars finder-inf info package epg-config url-handlers url-parse
auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs
password-cache url-vars seq byte-opt gv bytecomp byte-compile cconv
preview prv-emacs tex-buf latex easy-mmode edmacro kmacro cl-loaddefs
cl-lib tex-style tex crm advice easymenu tex-site auto-loads time-date
mule-util japan-util tooltip eldoc electric uniquify ediff-hook vc-hooks
lisp-float-type mwheel term/x-win x-win term/common-win x-dnd tool-bar
dnd fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode elisp-mode lisp-mode prog-mode register page menu-bar
rfn-eshadow isearch timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core term/tty-colors frame cl-generic cham georgian
utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european
ethiopic indian cyrillic chinese composite charscript charprop
case-table epa-hook jka-cmpr-hook help simple abbrev obarray minibuffer
cl-preloaded nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote kqueue dynamic-setting
font-render-setting x-toolkit x multi-tty make-network-process emacs)

Memory information:
((conses 16 156179 7929)
 (symbols 48 25864 2)
 (miscs 40 82 79)
 (strings 32 46730 1878)
 (string-bytes 1 1235094)
 (vectors 16 20402)
 (vector-slots 8 629738 10352)
 (floats 8 77 67)
 (intervals 56 197 0)
 (buffers 992 13))





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-09-29  4:01 bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later YAMAMOTO Mitsuharu
@ 2017-09-29 17:11 ` Eli Zaretskii
  2017-09-29 19:38   ` Paul Eggert
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2017-09-29 17:11 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu, Paul Eggert; +Cc: 28639

> Date: Fri, 29 Sep 2017 13:01:40 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> 
> Some platforms rely on the primitive function `file-system-info'
> instead of the "df" output to get free space.  How about implementing
> `file-system-info' also for other platforms using the fsusage module
> in Gnulib?

That'd be fine with me, assuming that the Gnulib module is good enough
for us.  Paul?





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-09-29 17:11 ` Eli Zaretskii
@ 2017-09-29 19:38   ` Paul Eggert
  2017-09-29 20:11     ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Paul Eggert @ 2017-09-29 19:38 UTC (permalink / raw)
  To: Eli Zaretskii, YAMAMOTO Mitsuharu; +Cc: 28639

On 09/29/2017 10:11 AM, Eli Zaretskii wrote:
>> Date: Fri, 29 Sep 2017 13:01:40 +0900
>> From: YAMAMOTO Mitsuharu<mituharu@math.s.chiba-u.ac.jp>
>>
>> How about implementing
>> `file-system-info' also for other platforms using the fsusage module
>> in Gnulib?
> That'd be fine with me, assuming that the Gnulib module is good enough
> for us.  Paul?

Should be doable. I assume this would be for 'master', not 'emacs-26'?





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-09-29 19:38   ` Paul Eggert
@ 2017-09-29 20:11     ` Eli Zaretskii
  2017-10-02  5:50       ` Paul Eggert
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2017-09-29 20:11 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 28639

> Cc: 28639@debbugs.gnu.org
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Fri, 29 Sep 2017 12:38:34 -0700
> 
> On 09/29/2017 10:11 AM, Eli Zaretskii wrote:
> >> Date: Fri, 29 Sep 2017 13:01:40 +0900
> >> From: YAMAMOTO Mitsuharu<mituharu@math.s.chiba-u.ac.jp>
> >>
> >> How about implementing
> >> `file-system-info' also for other platforms using the fsusage module
> >> in Gnulib?
> > That'd be fine with me, assuming that the Gnulib module is good enough
> > for us.  Paul?
> 
> Should be doable. I assume this would be for 'master', not 'emacs-26'?

Yes, I think so.  Unless the original bug is extremely annoying and
cannot wait, that is.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-09-29 20:11     ` Eli Zaretskii
@ 2017-10-02  5:50       ` Paul Eggert
  2017-10-02  8:34         ` Michael Albinus
  2017-10-02 15:57         ` Eli Zaretskii
  0 siblings, 2 replies; 12+ messages in thread
From: Paul Eggert @ 2017-10-02  5:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 28639-done

[-- Attachment #1: Type: text/plain, Size: 644 bytes --]

Eli Zaretskii wrote:
>> Should be doable. I assume this would be for 'master', not 'emacs-26'?
> Yes, I think so.  Unless the original bug is extremely annoying and
> cannot wait, that is.

I installed the attached into master, as I guess the original bug is merely 
mildly annoying. We can backport it to emacs-26 if I guessed wrong. As this 
should fix the bug I'm boldly marking it as done.

It strikes me that Emacs's support for fsusage on Microsoft platforms should be 
migrated into Gnulib, so that the support could benefit non-Emacs programs like 
GNU 'df' (and also simplify Emacs proper). That is lower priority, though.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Port-file-system-info-to-non-Microsoft.patch --]
[-- Type: text/x-patch; name="0001-Port-file-system-info-to-non-Microsoft.patch", Size: 39247 bytes --]

From 135bca574c31b7bf6df6c63d28f180956928dde7 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun, 1 Oct 2017 22:31:39 -0700
Subject: [PATCH] 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.
---
 admin/merge-gnulib   |   2 +-
 doc/emacs/files.texi |   7 +-
 etc/NEWS             |   4 +
 etc/PROBLEMS         |  10 +-
 lib/fsusage.c        | 288 +++++++++++++++++++++++++++++++++++++++++++
 lib/fsusage.h        |  40 ++++++
 lib/gnulib.mk.in     |  13 +-
 lisp/dired.el        |   6 +-
 lisp/files.el        |  49 ++------
 m4/fsusage.m4        | 336 +++++++++++++++++++++++++++++++++++++++++++++++++++
 m4/gnulib-comp.m4    |   9 ++
 nt/gnulib-cfg.mk     |   1 +
 src/fileio.c         |  39 ++++++
 13 files changed, 750 insertions(+), 54 deletions(-)
 create mode 100644 lib/fsusage.c
 create mode 100644 lib/fsusage.h
 create mode 100644 m4/fsusage.m4

diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 60104e8..4b1dc59 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -33,7 +33,7 @@ GNULIB_MODULES=
   d-type diffseq dtoastr dtotimespec dup2
   environ execinfo explicit_bzero faccessat
   fcntl fcntl-h fdatasync fdopendir
-  filemode filevercmp flexmember fstatat fsync
+  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
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 18f1c28..2c4a0ca 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -1279,13 +1279,8 @@ Directories
 giving the switches to use in a verbose listing (@code{"-l"} by
 default).
 
-@vindex directory-free-space-program
-@vindex directory-free-space-args
   In verbose directory listings, Emacs adds information about the
-amount of free space on the disk that contains the directory.  To do
-this, it runs the program specified by
-@code{directory-free-space-program} with arguments
-@code{directory-free-space-args}.
+amount of free space on the disk that contains the directory.
 
   The command @kbd{M-x delete-directory} prompts for a directory's name
 using the minibuffer, and deletes the directory if it is empty.  If
diff --git a/etc/NEWS b/etc/NEWS
index 42c1b04..28789a9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -73,6 +73,10 @@ calling 'eldoc-message' directly.
 \f
 * Lisp Changes in Emacs 27.1
 
+** The 'file-system-info' function is now available on all platforms.
+instead of just Microsoft platforms.  This fixes a get-free-disk-space
+bug on OS X 10.8 and later (Bug#28639).
+
 \f
 * Changes in Emacs 27.1 on Non-Free Operating Systems
 
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 94c78b6..2da9932 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -557,7 +557,7 @@ and then choose /usr/bin/netkit-ftp.
 
 *** Dired is very slow.
 
-This could happen if invocation of the 'df' program takes a long
+This could happen if getting a file system's status takes a long
 time.  Possible reasons for this include:
 
   - ClearCase mounted filesystems (VOBs) that sometimes make 'df'
@@ -565,12 +565,8 @@ time.  Possible reasons for this include:
 
   - slow automounters on some old versions of Unix;
 
-  - slow operation of some versions of 'df'.
-
-To work around the problem, you could either (a) set the variable
-'directory-free-space-program' to nil, and thus prevent Emacs from
-invoking 'df'; (b) use 'df' from the GNU Coreutils package; or
-(c) use CVS, which is Free Software, instead of ClearCase.
+To work around the problem, you could use Git or some other
+free-software program, instead of ClearCase.
 
 *** ps-print commands fail to find prologue files ps-prin*.ps.
 
diff --git a/lib/fsusage.c b/lib/fsusage.c
new file mode 100644
index 0000000..a0f763b
--- /dev/null
+++ b/lib/fsusage.c
@@ -0,0 +1,288 @@
+/* fsusage.c -- return space usage of mounted file systems
+
+   Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2017 Free Software
+   Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include "fsusage.h"
+
+#include <limits.h>
+#include <sys/types.h>
+
+#if STAT_STATVFS || STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
+# include <sys/statvfs.h>
+#else
+/* Don't include backward-compatibility files unless they're needed.
+   Eventually we'd like to remove all this cruft.  */
+# include <fcntl.h>
+# include <unistd.h>
+# include <sys/stat.h>
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#if HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
+#if HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+# if HAVE_SYS_FS_S5PARAM_H      /* Fujitsu UXP/V */
+#  include <sys/fs/s5param.h>
+# endif
+# if HAVE_SYS_STATFS_H
+#  include <sys/statfs.h>
+# endif
+# if HAVE_DUSTAT_H              /* AIX PS/2 */
+#  include <sys/dustat.h>
+# endif
+# include "full-read.h"
+#endif
+
+/* Many space usage primitives use all 1 bits to denote a value that is
+   not applicable or unknown.  Propagate this information by returning
+   a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
+   is unsigned and narrower than uintmax_t.  */
+#define PROPAGATE_ALL_ONES(x) \
+  ((sizeof (x) < sizeof (uintmax_t) \
+    && (~ (x) == (sizeof (x) < sizeof (int) \
+                  ? - (1 << (sizeof (x) * CHAR_BIT)) \
+                  : 0))) \
+   ? UINTMAX_MAX : (uintmax_t) (x))
+
+/* Extract the top bit of X as an uintmax_t value.  */
+#define EXTRACT_TOP_BIT(x) ((x) \
+                            & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
+
+/* If a value is negative, many space usage primitives store it into an
+   integer variable by assignment, even if the variable's type is unsigned.
+   So, if a space usage variable X's top bit is set, convert X to the
+   uintmax_t value V such that (- (uintmax_t) V) is the negative of
+   the original value.  If X's top bit is clear, just yield X.
+   Use PROPAGATE_TOP_BIT if the original value might be negative;
+   otherwise, use PROPAGATE_ALL_ONES.  */
+#define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
+
+#ifdef STAT_STATVFS
+/* Return true if statvfs works.  This is false for statvfs on systems
+   with GNU libc on Linux kernels before 2.6.36, which stats all
+   preceding entries in /proc/mounts; that makes df hang if even one
+   of the corresponding file systems is hard-mounted but not available.  */
+# if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
+/* The FRSIZE fallback is not required in this case.  */
+#  undef STAT_STATFS2_FRSIZE
+static int statvfs_works (void) { return 1; }
+# else
+#  include <string.h> /* for strverscmp */
+#  include <sys/utsname.h>
+#  include <sys/statfs.h>
+#  define STAT_STATFS2_BSIZE 1
+
+static int
+statvfs_works (void)
+{
+  static int statvfs_works_cache = -1;
+  struct utsname name;
+  if (statvfs_works_cache < 0)
+    statvfs_works_cache = (uname (&name) == 0
+                           && 0 <= strverscmp (name.release, "2.6.36"));
+  return statvfs_works_cache;
+}
+# endif
+#endif
+
+
+/* Fill in the fields of FSP with information about space usage for
+   the file system on which FILE resides.
+   DISK is the device on which FILE is mounted, for space-getting
+   methods that need to know it.
+   Return 0 if successful, -1 if not.  When returning -1, ensure that
+   ERRNO is either a system error value, or zero if DISK is NULL
+   on a system that requires a non-NULL value.  */
+int
+get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
+{
+#ifdef STAT_STATVFS     /* POSIX, except pre-2.6.36 glibc/Linux */
+
+  if (statvfs_works ())
+    {
+      struct statvfs vfsd;
+
+      if (statvfs (file, &vfsd) < 0)
+        return -1;
+
+      /* f_frsize isn't guaranteed to be supported.  */
+      fsp->fsu_blocksize = (vfsd.f_frsize
+                            ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
+                            : PROPAGATE_ALL_ONES (vfsd.f_bsize));
+
+      fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
+      fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
+      fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
+      fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
+      fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
+      fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
+      return 0;
+    }
+
+#endif
+
+#if defined STAT_STATVFS64            /* AIX */
+
+  struct statvfs64 fsd;
+
+  if (statvfs64 (file, &fsd) < 0)
+    return -1;
+
+  /* f_frsize isn't guaranteed to be supported.  */
+  fsp->fsu_blocksize = (fsd.f_frsize
+                        ? PROPAGATE_ALL_ONES (fsd.f_frsize)
+                        : PROPAGATE_ALL_ONES (fsd.f_bsize));
+
+#elif defined STAT_STATFS2_FS_DATA      /* Ultrix */
+
+  struct fs_data fsd;
+
+  if (statfs (file, &fsd) != 1)
+    return -1;
+
+  fsp->fsu_blocksize = 1024;
+  fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
+  fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
+  fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
+  fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
+  fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
+  fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
+
+#elif defined STAT_STATFS3_OSF1         /* OSF/1 */
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
+
+#elif defined STAT_STATFS2_FRSIZE        /* 2.6 < glibc/Linux < 2.6.36 */
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd) < 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
+
+#elif defined STAT_STATFS2_BSIZE        /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
+                                           Mac OS X < 10.4, FreeBSD < 5.0, \
+                                           NetBSD < 3.0, OpenBSD < 4.4 */
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd) < 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
+
+# ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+
+  /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+     struct statfs are truncated to 2GB.  These conditions detect that
+     truncation, presumably without botching the 4.1.1 case, in which
+     the values are not truncated.  The correct counts are stored in
+     undocumented spare fields.  */
+  if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
+    {
+      fsd.f_blocks = fsd.f_spare[0];
+      fsd.f_bfree = fsd.f_spare[1];
+      fsd.f_bavail = fsd.f_spare[2];
+    }
+# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+
+#elif defined STAT_STATFS2_FSIZE        /* 4.4BSD and older NetBSD */
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd) < 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
+
+#elif defined STAT_STATFS4              /* SVR3, Dynix, old Irix, old AIX, \
+                                           Dolphin */
+
+# if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
+#  define f_bavail f_bfree
+# endif
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd, sizeof fsd, 0) < 0)
+    return -1;
+
+  /* Empirically, the block counts on most SVR3 and SVR3-derived
+     systems seem to always be in terms of 512-byte blocks,
+     no matter what value f_bsize has.  */
+# if _AIX || defined _CRAY
+   fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
+# else
+   fsp->fsu_blocksize = 512;
+# endif
+
+#endif
+
+#if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1                \
+     || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE       \
+     || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
+
+  fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
+  fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
+  fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
+  fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
+  fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
+  fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
+
+#endif
+
+  (void) disk;  /* avoid argument-unused warning */
+  return 0;
+}
+
+#if defined _AIX && defined _I386
+/* AIX PS/2 does not supply statfs.  */
+
+int
+statfs (char *file, struct statfs *fsb)
+{
+  struct stat stats;
+  struct dustat fsd;
+
+  if (stat (file, &stats) != 0)
+    return -1;
+  if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+    return -1;
+  fsb->f_type   = 0;
+  fsb->f_bsize  = fsd.du_bsize;
+  fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+  fsb->f_bfree  = fsd.du_tfree;
+  fsb->f_bavail = fsd.du_tfree;
+  fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
+  fsb->f_ffree  = fsd.du_tinode;
+  fsb->f_fsid.val[0] = fsd.du_site;
+  fsb->f_fsid.val[1] = fsd.du_pckno;
+  return 0;
+}
+
+#endif /* _AIX && _I386 */
diff --git a/lib/fsusage.h b/lib/fsusage.h
new file mode 100644
index 0000000..f78edc6
--- /dev/null
+++ b/lib/fsusage.h
@@ -0,0 +1,40 @@
+/* fsusage.h -- declarations for file system space usage info
+
+   Copyright (C) 1991-1992, 1997, 2003-2006, 2009-2017 Free Software
+   Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Space usage statistics for a file system.  Blocks are 512-byte. */
+
+#if !defined FSUSAGE_H_
+# define FSUSAGE_H_
+
+# include <stdint.h>
+# include <stdbool.h>
+
+struct fs_usage
+{
+  uintmax_t fsu_blocksize;      /* Size of a block.  */
+  uintmax_t fsu_blocks;         /* Total blocks. */
+  uintmax_t fsu_bfree;          /* Free blocks available to superuser. */
+  uintmax_t fsu_bavail;         /* Free blocks available to non-superuser. */
+  bool fsu_bavail_top_bit_set;  /* 1 if fsu_bavail represents a value < 0.  */
+  uintmax_t fsu_files;          /* Total file nodes. */
+  uintmax_t fsu_ffree;          /* Free file nodes. */
+};
+
+int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp);
+
+#endif
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 0f795b3..e9358a6 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# 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
+# 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
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -1516,6 +1516,17 @@ EXTRA_libgnu_a_SOURCES += at-func.c fstatat.c
 endif
 ## end   gnulib module fstatat
 
+## begin gnulib module fsusage
+ifeq (,$(OMIT_GNULIB_MODULE_fsusage))
+
+
+EXTRA_DIST += fsusage.c fsusage.h
+
+EXTRA_libgnu_a_SOURCES += fsusage.c
+
+endif
+## end   gnulib module fsusage
+
 ## begin gnulib module fsync
 ifeq (,$(OMIT_GNULIB_MODULE_fsync))
 
diff --git a/lisp/dired.el b/lisp/dired.el
index 9e09d34..1ec3ac4 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -198,8 +198,10 @@ dired-copy-preserve-time
 
 ; These variables were deleted and the replacements are on files.el.
 ; We leave aliases behind for back-compatibility.
-(defvaralias 'dired-free-space-program 'directory-free-space-program)
-(defvaralias 'dired-free-space-args 'directory-free-space-args)
+(define-obsolete-variable-alias 'dired-free-space-program
+  'directory-free-space-program "27.1")
+(define-obsolete-variable-alias 'dired-free-space-args
+  'directory-free-space-args "27.1")
 
 ;;; Hook variables
 
diff --git a/lisp/files.el b/lisp/files.el
index 336bbc8..194c87a 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -6386,58 +6386,33 @@ directory-free-space-program
 
 A value of nil disables this feature.
 
-If the function `file-system-info' is defined, it is always used in
-preference to the program given by this variable."
+This variable is obsolete; Emacs no longer uses it."
   :type '(choice (string :tag "Program") (const :tag "None" nil))
   :group 'dired)
+(make-obsolete-variable 'directory-free-space-program
+			"ignored, as Emacs uses `file-system-info' instead"
+			"27.1")
 
 (defcustom directory-free-space-args
   (purecopy (if (eq system-type 'darwin) "-k" "-Pk"))
   "Options to use when running `directory-free-space-program'."
   :type 'string
   :group 'dired)
+(make-obsolete-variable 'directory-free-space-args
+			"ignored, as Emacs uses `file-system-info' instead"
+			"27.1")
 
 (defun get-free-disk-space (dir)
   "Return the amount of free space on directory DIR's file system.
 The return value is a string describing the amount of free
 space (normally, the number of free 1KB blocks).
 
-This function calls `file-system-info' if it is available, or
-invokes the program specified by `directory-free-space-program'
-and `directory-free-space-args'.  If the system call or program
-is unsuccessful, or if DIR is a remote directory, this function
-returns nil."
+If DIR's free space cannot be obtained, or if DIR is a remote
+directory, this function returns nil."
   (unless (file-remote-p (expand-file-name dir))
-    ;; Try to find the number of free blocks.  Non-Posix systems don't
-    ;; always have df, but might have an equivalent system call.
-    (if (fboundp 'file-system-info)
-	(let ((fsinfo (file-system-info dir)))
-	  (if fsinfo
-	      (format "%.0f" (/ (nth 2 fsinfo) 1024))))
-      (setq dir (expand-file-name dir))
-      (save-match-data
-	(with-temp-buffer
-	  (when (and directory-free-space-program
-		     ;; Avoid failure if the default directory does
-		     ;; not exist (Bug#2631, Bug#3911).
-                     (let ((default-directory
-                             (locate-dominating-file dir 'file-directory-p)))
-                       (eq (process-file directory-free-space-program
-					 nil t nil
-					 directory-free-space-args
-                                         (file-relative-name dir))
-			   0)))
-	    ;; Assume that the "available" column is before the
-	    ;; "capacity" column.  Find the "%" and scan backward.
-	    (goto-char (point-min))
-	    (forward-line 1)
-	    (when (re-search-forward
-		   "[[:space:]]+[^[:space:]]+%[^%]*$"
-		   (line-end-position) t)
-	      (goto-char (match-beginning 0))
-	      (let ((endpt (point)))
-		(skip-chars-backward "^[:space:]")
-		(buffer-substring-no-properties (point) endpt)))))))))
+    (let ((avail (nth 2 (file-system-info dir))))
+      (if avail
+	  (format "%.0f" (/ avail 1024))))))
 
 ;; The following expression replaces `dired-move-to-filename-regexp'.
 (defvar directory-listing-before-filename-regexp
diff --git a/m4/fsusage.m4 b/m4/fsusage.m4
new file mode 100644
index 0000000..1d6ad41
--- /dev/null
+++ b/m4/fsusage.m4
@@ -0,0 +1,336 @@
+# serial 32
+# Obtaining file system usage information.
+
+# Copyright (C) 1997-1998, 2000-2001, 2003-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Jim Meyering.
+
+AC_DEFUN([gl_FSUSAGE],
+[
+  AC_CHECK_HEADERS_ONCE([sys/param.h])
+  AC_CHECK_HEADERS_ONCE([sys/vfs.h sys/fs_types.h])
+  AC_CHECK_HEADERS([sys/mount.h], [], [],
+    [AC_INCLUDES_DEFAULT
+     [#if HAVE_SYS_PARAM_H
+       #include <sys/param.h>
+      #endif]])
+  gl_FILE_SYSTEM_USAGE([gl_cv_fs_space=yes], [gl_cv_fs_space=no])
+])
+
+# Try to determine how a program can obtain file system usage information.
+# If successful, define the appropriate symbol (see fsusage.c) and
+# execute ACTION-IF-FOUND.  Otherwise, execute ACTION-IF-NOT-FOUND.
+#
+# gl_FILE_SYSTEM_USAGE([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+
+AC_DEFUN([gl_FILE_SYSTEM_USAGE],
+[
+dnl Enable large-file support. This has the effect of changing the size
+dnl of field f_blocks in 'struct statvfs' from 32 bit to 64 bit on
+dnl glibc/Hurd, HP-UX 11, Solaris (32-bit mode). It also changes the size
+dnl of field f_blocks in 'struct statfs' from 32 bit to 64 bit on
+dnl Mac OS X >= 10.5 (32-bit mode).
+AC_REQUIRE([AC_SYS_LARGEFILE])
+
+AC_MSG_CHECKING([how to get file system space usage])
+ac_fsusage_space=no
+
+# Perform only the link test since it seems there are no variants of the
+# statvfs function.  This check is more than just AC_CHECK_FUNCS([statvfs])
+# because that got a false positive on SCO OSR5.  Adding the declaration
+# of a 'struct statvfs' causes this test to fail (as it should) on such
+# systems.  That system is reported to work fine with STAT_STATFS4 which
+# is what it gets when this test fails.
+if test $ac_fsusage_space = no; then
+  # glibc/{Hurd,kFreeBSD}, FreeBSD >= 5.0, NetBSD >= 3.0,
+  # OpenBSD >= 4.4, AIX, HP-UX, IRIX, Solaris, Cygwin, Interix, BeOS.
+  AC_CACHE_CHECK([for statvfs function (SVR4)], [fu_cv_sys_stat_statvfs],
+                 [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#ifdef __osf__
+"Do not use Tru64's statvfs implementation"
+#endif
+
+#include <sys/statvfs.h>
+
+struct statvfs fsd;
+
+#if defined __APPLE__ && defined __MACH__
+#include <limits.h>
+/* On Mac OS X >= 10.5, f_blocks in 'struct statvfs' is a 32-bit quantity;
+   that commonly limits file systems to 4 TiB.  Whereas f_blocks in
+   'struct statfs' is a 64-bit type, thanks to the large-file support
+   that was enabled above.  In this case, don't use statvfs(); use statfs()
+   instead.  */
+int check_f_blocks_size[sizeof fsd.f_blocks * CHAR_BIT <= 32 ? -1 : 1];
+#endif
+]],
+                                    [[statvfs (0, &fsd);]])],
+                                 [fu_cv_sys_stat_statvfs=yes],
+                                 [fu_cv_sys_stat_statvfs=no])])
+  if test $fu_cv_sys_stat_statvfs = yes; then
+    ac_fsusage_space=yes
+    # AIX >= 5.2 has statvfs64 that has a wider f_blocks field than statvfs.
+    # glibc, HP-UX, IRIX, Solaris have statvfs64 as well, but on these systems
+    # statvfs with large-file support is already equivalent to statvfs64.
+    AC_CACHE_CHECK([whether to use statvfs64],
+      [fu_cv_sys_stat_statvfs64],
+      [AC_LINK_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <sys/types.h>
+              #include <sys/statvfs.h>
+              struct statvfs64 fsd;
+              int check_f_blocks_larger_in_statvfs64
+                [sizeof (((struct statvfs64 *) 0)->f_blocks)
+                 > sizeof (((struct statvfs *) 0)->f_blocks)
+                 ? 1 : -1];
+            ]],
+            [[statvfs64 (0, &fsd);]])],
+         [fu_cv_sys_stat_statvfs64=yes],
+         [fu_cv_sys_stat_statvfs64=no])
+      ])
+    if test $fu_cv_sys_stat_statvfs64 = yes; then
+      AC_DEFINE([STAT_STATVFS64], [1],
+                [  Define if statvfs64 should be preferred over statvfs.])
+    else
+      AC_DEFINE([STAT_STATVFS], [1],
+                [  Define if there is a function named statvfs.  (SVR4)])
+    fi
+  fi
+fi
+
+# Check for this unconditionally so we have a
+# good fallback on glibc/Linux > 2.6 < 2.6.36
+AC_MSG_CHECKING([for two-argument statfs with statfs.f_frsize member])
+AC_CACHE_VAL([fu_cv_sys_stat_statfs2_frsize],
+[AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+  int
+  main ()
+  {
+  struct statfs fsd;
+  fsd.f_frsize = 0;
+  return statfs (".", &fsd) != 0;
+  }]])],
+  [fu_cv_sys_stat_statfs2_frsize=yes],
+  [fu_cv_sys_stat_statfs2_frsize=no],
+  [fu_cv_sys_stat_statfs2_frsize=no])])
+AC_MSG_RESULT([$fu_cv_sys_stat_statfs2_frsize])
+if test $fu_cv_sys_stat_statfs2_frsize = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE([STAT_STATFS2_FRSIZE], [1],
+[  Define if statfs takes 2 args and struct statfs has a field named f_frsize.
+   (glibc/Linux > 2.6)])
+fi
+
+if test $ac_fsusage_space = no; then
+  # DEC Alpha running OSF/1
+  AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)])
+  AC_CACHE_VAL([fu_cv_sys_stat_statfs3_osf1],
+  [AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+  int
+  main ()
+  {
+    struct statfs fsd;
+    fsd.f_fsize = 0;
+    return statfs (".", &fsd, sizeof (struct statfs)) != 0;
+  }]])],
+    [fu_cv_sys_stat_statfs3_osf1=yes],
+    [fu_cv_sys_stat_statfs3_osf1=no],
+    [fu_cv_sys_stat_statfs3_osf1=no])])
+  AC_MSG_RESULT([$fu_cv_sys_stat_statfs3_osf1])
+  if test $fu_cv_sys_stat_statfs3_osf1 = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE([STAT_STATFS3_OSF1], [1],
+              [   Define if  statfs takes 3 args.  (DEC Alpha running OSF/1)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # glibc/Linux, Mac OS X, FreeBSD < 5.0, NetBSD < 3.0, OpenBSD < 4.4.
+  # (glibc/{Hurd,kFreeBSD}, FreeBSD >= 5.0, NetBSD >= 3.0,
+  # OpenBSD >= 4.4, AIX, HP-UX, OSF/1, Cygwin already handled above.)
+  # (On IRIX you need to include <sys/statfs.h>, not only <sys/mount.h> and
+  # <sys/vfs.h>.)
+  # (On Solaris, statfs has 4 arguments.)
+  AC_MSG_CHECKING([for two-argument statfs with statfs.f_bsize dnl
+member (AIX, 4.3BSD)])
+  AC_CACHE_VAL([fu_cv_sys_stat_statfs2_bsize],
+  [AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+  int
+  main ()
+  {
+  struct statfs fsd;
+  fsd.f_bsize = 0;
+  return statfs (".", &fsd) != 0;
+  }]])],
+    [fu_cv_sys_stat_statfs2_bsize=yes],
+    [fu_cv_sys_stat_statfs2_bsize=no],
+    [fu_cv_sys_stat_statfs2_bsize=no])])
+  AC_MSG_RESULT([$fu_cv_sys_stat_statfs2_bsize])
+  if test $fu_cv_sys_stat_statfs2_bsize = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE([STAT_STATFS2_BSIZE], [1],
+[  Define if statfs takes 2 args and struct statfs has a field named f_bsize.
+   (4.3BSD, SunOS 4, HP-UX, AIX PS/2)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # SVR3
+  # (Solaris already handled above.)
+  AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)])
+  AC_CACHE_VAL([fu_cv_sys_stat_statfs4],
+  [AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <sys/types.h>
+#include <sys/statfs.h>
+  int
+  main ()
+  {
+  struct statfs fsd;
+  return statfs (".", &fsd, sizeof fsd, 0) != 0;
+  }]])],
+    [fu_cv_sys_stat_statfs4=yes],
+    [fu_cv_sys_stat_statfs4=no],
+    [fu_cv_sys_stat_statfs4=no])])
+  AC_MSG_RESULT([$fu_cv_sys_stat_statfs4])
+  if test $fu_cv_sys_stat_statfs4 = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE([STAT_STATFS4], [1],
+      [  Define if statfs takes 4 args.  (SVR3, Dynix, old Irix, old AIX, Dolphin)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # 4.4BSD and older NetBSD
+  # (OSF/1 already handled above.)
+  # (On AIX, you need to include <sys/statfs.h>, not only <sys/mount.h>.)
+  # (On Solaris, statfs has 4 arguments and 'struct statfs' is not declared in
+  # <sys/mount.h>.)
+  AC_MSG_CHECKING([for two-argument statfs with statfs.f_fsize dnl
+member (4.4BSD and NetBSD)])
+  AC_CACHE_VAL([fu_cv_sys_stat_statfs2_fsize],
+  [AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+  int
+  main ()
+  {
+  struct statfs fsd;
+  fsd.f_fsize = 0;
+  return statfs (".", &fsd) != 0;
+  }]])],
+    [fu_cv_sys_stat_statfs2_fsize=yes],
+    [fu_cv_sys_stat_statfs2_fsize=no],
+    [fu_cv_sys_stat_statfs2_fsize=no])])
+  AC_MSG_RESULT([$fu_cv_sys_stat_statfs2_fsize])
+  if test $fu_cv_sys_stat_statfs2_fsize = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE([STAT_STATFS2_FSIZE], [1],
+[  Define if statfs takes 2 args and struct statfs has a field named f_fsize.
+   (4.4BSD, NetBSD)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # Ultrix
+  AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)])
+  AC_CACHE_VAL([fu_cv_sys_stat_fs_data],
+  [AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_FS_TYPES_H
+#include <sys/fs_types.h>
+#endif
+  int
+  main ()
+  {
+  struct fs_data fsd;
+  /* Ultrix's statfs returns 1 for success,
+     0 for not mounted, -1 for failure.  */
+  return statfs (".", &fsd) != 1;
+  }]])],
+    [fu_cv_sys_stat_fs_data=yes],
+    [fu_cv_sys_stat_fs_data=no],
+    [fu_cv_sys_stat_fs_data=no])])
+  AC_MSG_RESULT([$fu_cv_sys_stat_fs_data])
+  if test $fu_cv_sys_stat_fs_data = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE([STAT_STATFS2_FS_DATA], [1],
+[  Define if statfs takes 2 args and the second argument has
+   type struct fs_data.  (Ultrix)])
+  fi
+fi
+
+AS_IF([test $ac_fsusage_space = yes], [$1], [$2])
+
+])
+
+
+# Check for SunOS statfs brokenness wrt partitions 2GB and larger.
+# If <sys/vfs.h> exists and struct statfs has a member named f_spare,
+# enable the work-around code in fsusage.c.
+AC_DEFUN([gl_STATFS_TRUNCATES],
+[
+  AC_MSG_CHECKING([for statfs that truncates block counts])
+  AC_CACHE_VAL([fu_cv_sys_truncating_statfs],
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if !defined(sun) && !defined(__sun)
+choke -- this is a workaround for a Sun-specific problem
+#endif
+#include <sys/types.h>
+#include <sys/vfs.h>]],
+      [[struct statfs t; long c = *(t.f_spare);
+        if (c) return 0;]])],
+    [fu_cv_sys_truncating_statfs=yes],
+    [fu_cv_sys_truncating_statfs=no])])
+  if test $fu_cv_sys_truncating_statfs = yes; then
+    AC_DEFINE([STATFS_TRUNCATES_BLOCK_COUNTS], [1],
+      [Define if the block counts reported by statfs may be truncated to 2GB
+       and the correct values may be stored in the f_spare array.
+       (SunOS 4.1.2, 4.1.3, and 4.1.3_U1 are reported to have this problem.
+       SunOS 4.1.1 seems not to be affected.)])
+  fi
+  AC_MSG_RESULT([$fu_cv_sys_truncating_statfs])
+])
+
+
+# Prerequisites of lib/fsusage.c not done by gl_FILE_SYSTEM_USAGE.
+AC_DEFUN([gl_PREREQ_FSUSAGE_EXTRA],
+[
+  AC_CHECK_HEADERS([dustat.h sys/fs/s5param.h sys/statfs.h])
+  gl_STATFS_TRUNCATES
+])
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index c551752..cb255fc 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -87,6 +87,7 @@ AC_DEFUN
   # Code from module flexmember:
   # Code from module fpending:
   # Code from module fstatat:
+  # Code from module fsusage:
   # Code from module fsync:
   # Code from module getdtablesize:
   # Code from module getgroups:
@@ -256,6 +257,11 @@ AC_DEFUN
     AC_LIBOBJ([fstatat])
   fi
   gl_SYS_STAT_MODULE_INDICATOR([fstatat])
+  gl_FSUSAGE
+  if test $gl_cv_fs_space = yes; then
+    AC_LIBOBJ([fsusage])
+    gl_PREREQ_FSUSAGE_EXTRA
+  fi
   gl_FUNC_FSYNC
   if test $HAVE_FSYNC = 0; then
     AC_LIBOBJ([fsync])
@@ -864,6 +870,8 @@ AC_DEFUN
   lib/fpending.c
   lib/fpending.h
   lib/fstatat.c
+  lib/fsusage.c
+  lib/fsusage.h
   lib/fsync.c
   lib/ftoastr.c
   lib/ftoastr.h
@@ -995,6 +1003,7 @@ AC_DEFUN
   m4/flexmember.m4
   m4/fpending.m4
   m4/fstatat.m4
+  m4/fsusage.m4
   m4/fsync.m4
   m4/getdtablesize.m4
   m4/getgroups.m4
diff --git a/nt/gnulib-cfg.mk b/nt/gnulib-cfg.mk
index 419099e..f621667 100644
--- a/nt/gnulib-cfg.mk
+++ b/nt/gnulib-cfg.mk
@@ -49,6 +49,7 @@ OMIT_GNULIB_MODULE_dirent =
 OMIT_GNULIB_MODULE_dirfd = true
 OMIT_GNULIB_MODULE_fcntl = true
 OMIT_GNULIB_MODULE_fcntl-h = true
+OMIT_GNULIB_MODULE_fsusage = true
 OMIT_GNULIB_MODULE_inttypes-incomplete = true
 OMIT_GNULIB_MODULE_open = true
 OMIT_GNULIB_MODULE_pipe2 = true
diff --git a/src/fileio.c b/src/fileio.c
index adb3534..1137027 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -96,6 +96,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <acl.h>
 #include <allocator.h>
 #include <careadlinkat.h>
+#include <fsusage.h>
 #include <stat-time.h>
 #include <tempname.h>
 
@@ -5765,6 +5766,40 @@ effect except for flushing STREAM's data.  */)
   return (set_binary_mode (fileno (fp), binmode) == O_BINARY) ? Qt : Qnil;
 }
 \f
+#ifndef DOS_NT
+
+/* Yield a Lisp float as close as possible to BLOCKSIZE * BLOCKS, with
+   the result negated if NEGATE.  */
+static Lisp_Object
+blocks_to_bytes (uintmax_t blocksize, uintmax_t blocks, bool negate)
+{
+  /* On typical platforms the following code is accurate to 53 bits,
+     which is close enough.  BLOCKSIZE is invariably a power of 2, so
+     converting it to double does not lose information.  */
+  double bs = blocksize;
+  return make_float (negate ? -bs * -blocks : bs * blocks);
+}
+
+DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
+       doc: /* Return storage information about the file system FILENAME is on.
+Value is a list of numbers (TOTAL FREE AVAIL), where TOTAL is the total
+storage of the file system, FREE is the free storage, and AVAIL is the
+storage available to a non-superuser.  All 3 numbers are in bytes.
+If the underlying system call fails, value is nil.  */)
+  (Lisp_Object filename)
+{
+  Lisp_Object encoded = ENCODE_FILE (Fexpand_file_name (filename, Qnil));
+  struct fs_usage u;
+  if (get_fs_usage (SSDATA (encoded), NULL, &u) != 0)
+    return Qnil;
+  return list3 (blocks_to_bytes (u.fsu_blocksize, u.fsu_blocks, false),
+		blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false),
+		blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail,
+				 u.fsu_bavail_top_bit_set));
+}
+
+#endif /* !DOS_NT */
+\f
 void
 init_fileio (void)
 {
@@ -6115,6 +6150,10 @@ This includes interactive calls to `delete-file' and
 
   defsubr (&Sset_binary_mode);
 
+#ifndef DOS_NT
+  defsubr (&Sfile_system_info);
+#endif
+
 #ifdef HAVE_SYNC
   defsubr (&Sunix_sync);
 #endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02  5:50       ` Paul Eggert
@ 2017-10-02  8:34         ` Michael Albinus
  2017-10-02 15:57           ` Paul Eggert
  2017-10-02 16:03           ` Eli Zaretskii
  2017-10-02 15:57         ` Eli Zaretskii
  1 sibling, 2 replies; 12+ messages in thread
From: Michael Albinus @ 2017-10-02  8:34 UTC (permalink / raw)
  To: 28639; +Cc: eggert

Paul Eggert <eggert@cs.ucla.edu> writes:

> I installed the attached into master, as I guess the original bug is
> merely mildly annoying. We can backport it to emacs-26 if I guessed
> wrong. As this should fix the bug I'm boldly marking it as done.
>
> It strikes me that Emacs's support for fsusage on Microsoft platforms
> should be migrated into Gnulib, so that the support could benefit
> non-Emacs programs like GNU 'df' (and also simplify Emacs
> proper). That is lower priority, though.

Shouldn't we add `file-system-info' to the file name handler operations?
On remote systems running GNU df it would return proper information,
based on "df --block-size=1 --output=size,used,avail <FILE>". Remote
systems accessed via GVFS would react on "gvfs-info --filesystem <FILE>".

Best regards, Michael.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02  5:50       ` Paul Eggert
  2017-10-02  8:34         ` Michael Albinus
@ 2017-10-02 15:57         ` Eli Zaretskii
  1 sibling, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2017-10-02 15:57 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 28639

> Cc: mituharu@math.s.chiba-u.ac.jp, 28639-done@debbugs.gnu.org
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Sun, 1 Oct 2017 22:50:20 -0700
> 
> It strikes me that Emacs's support for fsusage on Microsoft platforms should be 
> migrated into Gnulib, so that the support could benefit non-Emacs programs like 
> GNU 'df' (and also simplify Emacs proper).

Indeed, I was surprised to see that Gnulib didn't support MS-Windows
in that module.

Thanks.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02  8:34         ` Michael Albinus
@ 2017-10-02 15:57           ` Paul Eggert
  2017-10-02 16:11             ` Michael Albinus
  2017-10-02 16:03           ` Eli Zaretskii
  1 sibling, 1 reply; 12+ messages in thread
From: Paul Eggert @ 2017-10-02 15:57 UTC (permalink / raw)
  To: Michael Albinus, 28639

On 10/02/2017 01:34 AM, Michael Albinus wrote:
> Shouldn't we add `file-system-info' to the file name handler operations?

Yes, good point, I hadn't thought of that. Is that something you could do?






^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02  8:34         ` Michael Albinus
  2017-10-02 15:57           ` Paul Eggert
@ 2017-10-02 16:03           ` Eli Zaretskii
  1 sibling, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2017-10-02 16:03 UTC (permalink / raw)
  To: Michael Albinus; +Cc: 28639, eggert

> From: Michael Albinus <michael.albinus@gmx.de>
> Date: Mon, 02 Oct 2017 10:34:49 +0200
> Cc: eggert@cs.ucla.edu
> 
> Shouldn't we add `file-system-info' to the file name handler operations?

I guess we should (on master).

Thanks.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02 15:57           ` Paul Eggert
@ 2017-10-02 16:11             ` Michael Albinus
  2017-10-02 16:40               ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Michael Albinus @ 2017-10-02 16:11 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 28639

Paul Eggert <eggert@cs.ucla.edu> writes:

>> Shouldn't we add `file-system-info' to the file name handler operations?
>
> Yes, good point, I hadn't thought of that. Is that something you could do?

Will do, it's half-baken already :-)

Tonight is BBT time, so I'll finish tomorrow.

One point: I will commit changes in lisp/files.el and src/fileio.c to
the master branch. The changes in Tramp will go to the emacs-26 branch,
because the Tramp version in Emacs 26, 2.3.3, is not released yet, and I
don't want to start with the next release 2.3.4 now. This shouldn't be a
problem, because nobody will call Tramp file name handlers for
`file-system-info' in Emacs 26.

Best regards, Michael.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02 16:11             ` Michael Albinus
@ 2017-10-02 16:40               ` Eli Zaretskii
  2017-10-03 14:18                 ` Michael Albinus
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2017-10-02 16:40 UTC (permalink / raw)
  To: Michael Albinus; +Cc: 28639, eggert

> From: Michael Albinus <michael.albinus@gmx.de>
> Date: Mon, 02 Oct 2017 18:11:08 +0200
> Cc: 28639@debbugs.gnu.org
> 
> One point: I will commit changes in lisp/files.el and src/fileio.c to
> the master branch. The changes in Tramp will go to the emacs-26 branch,
> because the Tramp version in Emacs 26, 2.3.3, is not released yet, and I
> don't want to start with the next release 2.3.4 now. This shouldn't be a
> problem, because nobody will call Tramp file name handlers for
> `file-system-info' in Emacs 26.

That'd be okay, I think.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later
  2017-10-02 16:40               ` Eli Zaretskii
@ 2017-10-03 14:18                 ` Michael Albinus
  0 siblings, 0 replies; 12+ messages in thread
From: Michael Albinus @ 2017-10-03 14:18 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 28639, eggert

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Michael Albinus <michael.albinus@gmx.de>
>> Date: Mon, 02 Oct 2017 18:11:08 +0200
>> Cc: 28639@debbugs.gnu.org
>> 
>> One point: I will commit changes in lisp/files.el and src/fileio.c to
>> the master branch. The changes in Tramp will go to the emacs-26 branch,
>> because the Tramp version in Emacs 26, 2.3.3, is not released yet, and I
>> don't want to start with the next release 2.3.4 now. This shouldn't be a
>> problem, because nobody will call Tramp file name handlers for
>> `file-system-info' in Emacs 26.
>
> That'd be okay, I think.

Committed, as proposed.

Best regards, Michael.





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-10-03 14:18 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-29  4:01 bug#28639: 26.0.60; get-free-disk-space gives wrong number on OS X 10.8 and later YAMAMOTO Mitsuharu
2017-09-29 17:11 ` Eli Zaretskii
2017-09-29 19:38   ` Paul Eggert
2017-09-29 20:11     ` Eli Zaretskii
2017-10-02  5:50       ` Paul Eggert
2017-10-02  8:34         ` Michael Albinus
2017-10-02 15:57           ` Paul Eggert
2017-10-02 16:11             ` Michael Albinus
2017-10-02 16:40               ` Eli Zaretskii
2017-10-03 14:18                 ` Michael Albinus
2017-10-02 16:03           ` Eli Zaretskii
2017-10-02 15:57         ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).