From b761434c6b7be1c6bcbe6eb0a179b7fb897272cc Mon Sep 17 00:00:00 2001 From: Maxime Devos Date: Fri, 12 Mar 2021 19:10:34 +0100 Subject: [PATCH 12/17] =?UTF-8?q?Define=20a=20Scheme=20binding=20to=20?= =?UTF-8?q?=E2=80=98fstatat=E2=80=99=20when=20available.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * configure.ac: Detect if ‘fstatat’ is defined. * libguile/filesys.c (scm_statat): Define a Scheme binding to ‘fstatat’. * libguile/filesys.h (scm_statat): Make it part of the C API. * doc/ref/posix.texi (File System): Document it. * libguile/syscalls.h (fstatat_or_fstatat64): Choose between ‘fstatat’ and ‘fstatat64’. --- configure.ac | 4 ++-- doc/ref/posix.texi | 12 ++++++++++++ libguile/filesys.c | 42 ++++++++++++++++++++++++++++++++++++++++++ libguile/filesys.h | 1 + libguile/syscalls.h | 1 + 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5f8389b82..22cdffdf8 100644 --- a/configure.ac +++ b/configure.ac @@ -482,8 +482,8 @@ AC_CHECK_HEADERS([assert.h crt_externs.h]) # AC_CHECK_FUNCS([DINFINITY DQNAN cexp chsize clog clog10 ctermid \ fesetround ftime ftruncate fchown fchmod fchdir readlinkat \ - symlinkat mkdirat renameat fchmodat unlinkat fchownat \ - getcwd geteuid getsid \ + symlinkat mkdirat renameat fchmodat unlinkat fchownat fstatat \ + getcwd geteuid getsid \ gettimeofday getuid getgid gmtime_r ioctl lstat mkdir mkdtemp mknod \ nice readlink rename rmdir setegid seteuid \ setlocale setuid setgid setpgid setsid sigaction siginterrupt stat64 \ diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi index 077ba8c79..b595fa44d 100644 --- a/doc/ref/posix.texi +++ b/doc/ref/posix.texi @@ -792,6 +792,18 @@ it will return information about a symbolic link itself, not the file it points to. @var{path} must be a string. @end deffn +@deffn {Scheme Procedure} statat dir filename [flags] +@deffnx {C Function} scm_statat (dir, filename, flags) +Similar to @code{stat}, but consider the file +named @var{filename} in the directory referred to by the file +port @var{dir} instead. + +The optional argument @var{flags} is a bitmask. If it +contains @code{AT_SYMLINK_NOFOLLOW}, @var{filename} will not be +dereferenced even if it is a symbolic link, i.e., act as +@code{lstat} instead of @code{stat}. +@end deffn + @deffn {Scheme Procedure} readlink path @deffnx {C Function} scm_readlink (path) Return the value of the symbolic link named by @var{path} (a diff --git a/libguile/filesys.c b/libguile/filesys.c index a319d9794..454ce228e 100644 --- a/libguile/filesys.c +++ b/libguile/filesys.c @@ -637,6 +637,48 @@ SCM_DEFINE (scm_stat, "stat", 1, 1, 0, } #undef FUNC_NAME +#ifdef HAVE_FSTATAT +SCM_DEFINE (scm_statat, "statat", 2, 1, 0, + (SCM dir, SCM filename, SCM flags), + "Similar to @code{stat}, but consider the file named\n" + "@var{filename} in the directory referred to by the file\n" + "port @var{dir} instead.\n\n" + "The optional argument @var{flags} is a bitmask. If it\n" + "contains @code{AT_SYMLINK_NOFOLLOW}, @var{filename} will not be\n" + "dereferenced even if it is a symbolic link, i.e., act as\n" + "@code{lstat} instead of @code{stat}.") +#define FUNC_NAME s_scm_statat +{ + int rv; + int dir_fdes; + int c_flags; + struct stat_or_stat64 stat_temp; + + if (SCM_UNBNDP (flags)) + c_flags = 0; + else + c_flags = scm_to_int (flags); + + SCM_VALIDATE_OPFPORT (SCM_ARG1, dir); + dir_fdes = SCM_FPORT_FDES (dir); + + STRING_SYSCALL (filename, c_filename, + rv = fstatat_or_fstatat64 (dir_fdes, c_filename, + &stat_temp, c_flags)); + scm_remember_upto_here_1 (dir); + + if (rv != 0) + { + int en = errno; + SCM_SYSERROR_MSG ("~A: ~S", + scm_list_2 (scm_strerror (scm_from_int (en)), filename), + en); + } + return scm_stat2scm (&stat_temp); +} +#undef FUNC_NAME +#endif /* HAVE_FSTATAT */ + SCM_DEFINE (scm_lstat, "lstat", 1, 0, 0, (SCM str), "Similar to @code{stat}, but does not follow symbolic links, i.e.,\n" diff --git a/libguile/filesys.h b/libguile/filesys.h index 7673c8051..8af0f989a 100644 --- a/libguile/filesys.h +++ b/libguile/filesys.h @@ -48,6 +48,7 @@ SCM_API SCM scm_open (SCM path, SCM flags, SCM mode); SCM_API SCM scm_close (SCM fd_or_port); SCM_API SCM scm_close_fdes (SCM fd); SCM_API SCM scm_stat (SCM object, SCM exception_on_error); +SCM_API SCM scm_statat (SCM dir, SCM filename, SCM flags); SCM_API SCM scm_link (SCM oldpath, SCM newpath); SCM_API SCM scm_rename (SCM oldname, SCM newname); SCM_API SCM scm_renameat (SCM olddir, SCM oldname, SCM newdir, SCM newname); diff --git a/libguile/syscalls.h b/libguile/syscalls.h index 30b99c193..37d532e60 100644 --- a/libguile/syscalls.h +++ b/libguile/syscalls.h @@ -65,6 +65,7 @@ # define readdir_r_or_readdir64_r readdir_r #endif #define stat_or_stat64 CHOOSE_LARGEFILE(stat,stat64) +#define fstatat_or_fstatat64 CHOOSE_LARGEFILE(fstatat,fstatat64) #define truncate_or_truncate64 CHOOSE_LARGEFILE(truncate,truncate64) #define scm_from_off_t_or_off64_t CHOOSE_LARGEFILE(scm_from_off_t,scm_from_int64) #define scm_from_ino_t_or_ino64_t CHOOSE_LARGEFILE(scm_from_ulong,scm_from_uint64) -- 2.30.2