Commit 135bca57 authored by Paul Eggert's avatar Paul Eggert

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.
parent 4829a3b0
...@@ -33,7 +33,7 @@ GNULIB_MODULES=' ...@@ -33,7 +33,7 @@ GNULIB_MODULES='
d-type diffseq dtoastr dtotimespec dup2 d-type diffseq dtoastr dtotimespec dup2
environ execinfo explicit_bzero faccessat environ execinfo explicit_bzero faccessat
fcntl fcntl-h fdatasync fdopendir fcntl fcntl-h fdatasync fdopendir
filemode filevercmp flexmember fstatat fsync filemode filevercmp flexmember fstatat fsusage fsync
getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
ignore-value intprops largefile lstat ignore-value intprops largefile lstat
manywarnings memrchr minmax mkostemp mktime nstrftime manywarnings memrchr minmax mkostemp mktime nstrftime
......
...@@ -1279,13 +1279,8 @@ default), and @code{list-directory-verbose-switches} is a string ...@@ -1279,13 +1279,8 @@ default), and @code{list-directory-verbose-switches} is a string
giving the switches to use in a verbose listing (@code{"-l"} by giving the switches to use in a verbose listing (@code{"-l"} by
default). default).
@vindex directory-free-space-program
@vindex directory-free-space-args
In verbose directory listings, Emacs adds information about the In verbose directory listings, Emacs adds information about the
amount of free space on the disk that contains the directory. To do amount of free space on the disk that contains the directory.
this, it runs the program specified by
@code{directory-free-space-program} with arguments
@code{directory-free-space-args}.
The command @kbd{M-x delete-directory} prompts for a directory's name 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 using the minibuffer, and deletes the directory if it is empty. If
......
...@@ -73,6 +73,10 @@ calling 'eldoc-message' directly. ...@@ -73,6 +73,10 @@ calling 'eldoc-message' directly.
* Lisp Changes in Emacs 27.1 * 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).
* Changes in Emacs 27.1 on Non-Free Operating Systems * Changes in Emacs 27.1 on Non-Free Operating Systems
......
...@@ -557,7 +557,7 @@ and then choose /usr/bin/netkit-ftp. ...@@ -557,7 +557,7 @@ and then choose /usr/bin/netkit-ftp.
*** Dired is very slow. *** 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: time. Possible reasons for this include:
- ClearCase mounted filesystems (VOBs) that sometimes make 'df' - ClearCase mounted filesystems (VOBs) that sometimes make 'df'
...@@ -565,12 +565,8 @@ time. Possible reasons for this include: ...@@ -565,12 +565,8 @@ time. Possible reasons for this include:
- slow automounters on some old versions of Unix; - slow automounters on some old versions of Unix;
- slow operation of some versions of 'df'. To work around the problem, you could use Git or some other
free-software program, instead of ClearCase.
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.
*** ps-print commands fail to find prologue files ps-prin*.ps. *** ps-print commands fail to find prologue files ps-prin*.ps.
......
/* 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 */
/* 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
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program. # the same distribution terms as the rest of that program.
# #
# Generated by gnulib-tool. # 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 MOSTLYCLEANFILES += core *.stackdump
...@@ -1516,6 +1516,17 @@ EXTRA_libgnu_a_SOURCES += at-func.c fstatat.c ...@@ -1516,6 +1516,17 @@ EXTRA_libgnu_a_SOURCES += at-func.c fstatat.c
endif endif
## end gnulib module fstatat ## 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 ## begin gnulib module fsync
ifeq (,$(OMIT_GNULIB_MODULE_fsync)) ifeq (,$(OMIT_GNULIB_MODULE_fsync))
......
...@@ -198,8 +198,10 @@ The target is used in the prompt for file copy, rename etc." ...@@ -198,8 +198,10 @@ The target is used in the prompt for file copy, rename etc."
; These variables were deleted and the replacements are on files.el. ; These variables were deleted and the replacements are on files.el.
; We leave aliases behind for back-compatibility. ; We leave aliases behind for back-compatibility.
(defvaralias 'dired-free-space-program 'directory-free-space-program) (define-obsolete-variable-alias 'dired-free-space-program
(defvaralias 'dired-free-space-args 'directory-free-space-args) 'directory-free-space-program "27.1")
(define-obsolete-variable-alias 'dired-free-space-args
'directory-free-space-args "27.1")
;;; Hook variables ;;; Hook variables
......
...@@ -6386,58 +6386,33 @@ if you want to specify options, use `directory-free-space-args'. ...@@ -6386,58 +6386,33 @@ if you want to specify options, use `directory-free-space-args'.
A value of nil disables this feature. A value of nil disables this feature.
If the function `file-system-info' is defined, it is always used in This variable is obsolete; Emacs no longer uses it."
preference to the program given by this variable."
:type '(choice (string :tag "Program") (const :tag "None" nil)) :type '(choice (string :tag "Program") (const :tag "None" nil))
:group 'dired) :group 'dired)
(make-obsolete-variable 'directory-free-space-program
"ignored, as Emacs uses `file-system-info' instead"
"27.1")
(defcustom directory-free-space-args (defcustom directory-free-space-args
(purecopy (if (eq system-type 'darwin) "-k" "-Pk")) (purecopy (if (eq system-type 'darwin) "-k" "-Pk"))
"Options to use when running `directory-free-space-program'." "Options to use when running `directory-free-space-program'."
:type 'string :type 'string
:group 'dired) :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) (defun get-free-disk-space (dir)
"Return the amount of free space on directory DIR's file system. "Return the amount of free space on directory DIR's file system.
The return value is a string describing the amount of free The return value is a string describing the amount of free
space (normally, the number of free 1KB blocks). space (normally, the number of free 1KB blocks).
This function calls `file-system-info' if it is available, or If DIR's free space cannot be obtained, or if DIR is a remote
invokes the program specified by `directory-free-space-program' directory, this function returns nil."
and `directory-free-space-args'. If the system call or program
is unsuccessful, or if DIR is a remote directory, this function
returns nil."
(unless (file-remote-p (expand-file-name dir)) (unless (file-remote-p (expand-file-name dir))
;; Try to find the number of free blocks. Non-Posix systems don't (let ((avail (nth 2 (file-system-info dir))))
;; always have df, but might have an equivalent system call. (if avail
(if (fboundp 'file-system-info) (format "%.0f" (/ avail 1024))))))
(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)))))))))
;; The following expression replaces `dired-move-to-filename-regexp'. ;; The following expression replaces `dired-move-to-filename-regexp'.
(defvar directory-listing-before-filename-regexp (defvar directory-listing-before-filename-regexp
......
This diff is collapsed.
...@@ -87,6 +87,7 @@ AC_DEFUN([gl_EARLY], ...@@ -87,6 +87,7 @@ AC_DEFUN([gl_EARLY],
# Code from module flexmember: # Code from module flexmember:
# Code from module fpending: # Code from module fpending:
# Code from module fstatat: # Code from module fstatat:
# Code from module fsusage:
# Code from module fsync: # Code from module fsync:
# Code from module getdtablesize: # Code from module getdtablesize:
# Code from module getgroups: # Code from module getgroups:
...@@ -256,6 +257,11 @@ AC_DEFUN([gl_INIT], ...@@ -256,6 +257,11 @@ AC_DEFUN([gl_INIT],
AC_LIBOBJ([fstatat]) AC_LIBOBJ([fstatat])
fi fi
gl_SYS_STAT_MODULE_INDICATOR([fstatat]) 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 gl_FUNC_FSYNC
if test $HAVE_FSYNC = 0; then if test $HAVE_FSYNC = 0; then
AC_LIBOBJ([fsync]) AC_LIBOBJ([fsync])
...@@ -864,6 +870,8 @@ AC_DEFUN([gl_FILE_LIST], [ ...@@ -864,6 +870,8 @@ AC_DEFUN([gl_FILE_LIST], [
lib/fpending.c lib/fpending.c
lib/fpending.h lib/fpending.h
lib/fstatat.c lib/fstatat.c
lib/fsusage.c
lib/fsusage.h
lib/fsync.c lib/fsync.c
lib/ftoastr.c lib/ftoastr.c
lib/ftoastr.h lib/ftoastr.h
...@@ -995,6 +1003,7 @@ AC_DEFUN([gl_FILE_LIST], [ ...@@ -995,6 +1003,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/flexmember.m4 m4/flexmember.m4
m4/fpending.m4 m4/fpending.m4
m4/fstatat.m4 m4/fstatat.m4
m4/fsusage.m4
m4/fsync.m4 m4/fsync.m4
m4/getdtablesize.m4 m4/getdtablesize.m4
m4/getgroups.m4 m4/getgroups.m4
......
...@@ -49,6 +49,7 @@ OMIT_GNULIB_MODULE_dirent = true ...@@ -49,6 +49,7 @@ OMIT_GNULIB_MODULE_dirent = true
OMIT_GNULIB_MODULE_dirfd = true OMIT_GNULIB_MODULE_dirfd = true
OMIT_GNULIB_MODULE_fcntl = true OMIT_GNULIB_MODULE_fcntl = true
OMIT_GNULIB_MODULE_fcntl-h = true OMIT_GNULIB_MODULE_fcntl-h = true
OMIT_GNULIB_MODULE_fsusage = true
OMIT_GNULIB_MODULE_inttypes-incomplete = true OMIT_GNULIB_MODULE_inttypes-incomplete = true
OMIT_GNULIB_MODULE_open = true OMIT_GNULIB_MODULE_open = true
OMIT_GNULIB_MODULE_pipe2 = true OMIT_GNULIB_MODULE_pipe2 = true
......
...@@ -96,6 +96,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ ...@@ -96,6 +96,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <acl.h> #include <acl.h>
#include <allocator.h> #include <allocator.h>
#include <careadlinkat.h> #include <careadlinkat.h>
#include <fsusage.h>
#include <stat-time.h> #include <stat-time.h>
#include <tempname.h> #include <tempname.h>
...@@ -5765,6 +5766,40 @@ effect except for flushing STREAM's data. */) ...@@ -5765,6 +5766,40 @@ effect except for flushing STREAM's data. */)
return (set_binary_mode (fileno (fp), binmode) == O_BINARY) ? Qt : Qnil; return (set_binary_mode (fileno (fp), binmode) == O_BINARY) ? Qt : Qnil;
} }
#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 */
void void
init_fileio (void) init_fileio (void)
{ {
...@@ -6115,6 +6150,10 @@ This includes interactive calls to `delete-file' and ...@@ -6115,6 +6150,10 @@ This includes interactive calls to `delete-file' and
defsubr (&Sset_binary_mode); defsubr (&Sset_binary_mode);
#ifndef DOS_NT
defsubr (&Sfile_system_info);
#endif
#ifdef HAVE_SYNC #ifdef HAVE_SYNC
defsubr (&Sunix_sync); defsubr (&Sunix_sync);
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment