From bb3ff1b5fff3c759c7ec4c0d5c9b10060396b055 Mon Sep 17 00:00:00 2001 From: Maxime Devos Date: Fri, 12 Mar 2021 20:26:29 +0100 Subject: [PATCH 13/17] =?UTF-8?q?Define=20a=20Scheme=20binding=20to=20?= =?UTF-8?q?=E2=80=98openat=E2=80=99=20when=20available.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * configure.ac: Detect if ‘openat’ is defined. * libguile/filesys.c (scm_open_fdes_at, scm_openat): Define the Scheme bindings. * libguile/filesys.h (scm_open_fdes_at, scm_openat): Make them part of the API. * doc/ref/posix.texi (File System): Document them. * libguile/syscalls.h (openat_or_openat64): Decide between ‘openat’ and ‘openat64’. --- configure.ac | 2 +- doc/ref/posix.texi | 13 ++++++ libguile/filesys.c | 97 +++++++++++++++++++++++++++++++++++---------- libguile/filesys.h | 2 + libguile/syscalls.h | 1 + 5 files changed, 93 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index 22cdffdf8..85a3a0dac 100644 --- a/configure.ac +++ b/configure.ac @@ -482,7 +482,7 @@ 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 fstatat \ + symlinkat mkdirat renameat fchmodat unlinkat fchownat fstatat openat \ getcwd geteuid getsid \ gettimeofday getuid getgid gmtime_r ioctl lstat mkdir mkdtemp mknod \ nice readlink rename rmdir setegid seteuid \ diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi index b595fa44d..29d9b8d28 100644 --- a/doc/ref/posix.texi +++ b/doc/ref/posix.texi @@ -333,12 +333,25 @@ See @xref{File Status Flags,,,libc,The GNU C Library Reference Manual} or @samp{man 3 strftime}, for additional flags and explanation. @end deffn +@deffn {Scheme Procedure} openat dir path flags [mode] +@deffnx {C Function} scm_openat (dir, path, flags, mode) +Similar to @code{open}, but resolve the file name @var{path} +relative to the directory referred to by the file port @var{dir} +instead. +@end deffn + @deffn {Scheme Procedure} open-fdes path flags [mode] @deffnx {C Function} scm_open_fdes (path, flags, mode) Similar to @code{open} but return a file descriptor instead of a port. @end deffn +@deffn {Scheme Procedure} open-fdes-at dir path flags [mode] +@deffnx {C Function} scm_open_fdes_at (dir, path, flags, mode) +Similar to @code{openat}, but return a file descriptor instead +of a port. +@end deffn + @deffn {Scheme Procedure} close fd_or_port @deffnx {C Function} scm_close (fd_or_port) Similar to @code{close-port} (@pxref{Ports, close-port}), diff --git a/libguile/filesys.c b/libguile/filesys.c index 454ce228e..d0566336a 100644 --- a/libguile/filesys.c +++ b/libguile/filesys.c @@ -249,6 +249,60 @@ SCM_DEFINE (scm_open_fdes, "open-fdes", 2, 1, 0, } #undef FUNC_NAME +#ifdef HAVE_OPENAT +SCM_DEFINE (scm_open_fdes_at, "open-fdes-at", 3, 1, 0, + (SCM dir, SCM path, SCM flags, SCM mode), + "Similar to @code{openat}, but return a file descriptor instead\n" + "of a port.\n") +#define FUNC_NAME s_scm_open_fdes_at +{ + int dir_fdes; + int fd; + int iflags; + int imode; + + iflags = SCM_NUM2INT (SCM_ARG2, flags); + imode = SCM_NUM2INT_DEF (3, mode, 0666); + SCM_VALIDATE_OPFPORT (SCM_ARG1, dir); + dir_fdes = SCM_FPORT_FDES (dir); + + STRING_SYSCALL (path, c_path, + fd = openat_or_openat64 (dir_fdes, c_path, iflags, imode)); + scm_remember_upto_here_1 (dir); + if (fd == -1) + SCM_SYSERROR; + return scm_from_int (fd); +} +#undef FUNC_NAME +#endif /* HAVE_OPENAT */ + +/* A helper function for converting some open flags to + what scm_fdes_to_port expects. */ +static const char * +flags_to_mode (int iflags) +{ + if ((iflags & O_RDWR) == O_RDWR) + { + /* Opened read-write. */ + if (iflags & O_APPEND) + return "a+"; + else if (iflags & O_CREAT) + return "w+"; + else + return "r+"; + } + else + { + /* Opened read-only or write-only. */ + if (iflags & O_APPEND) + return "a"; + else if (iflags & O_WRONLY) + return "w"; + else + return "r"; + } +} + SCM_DEFINE (scm_open, "open", 2, 1, 0, (SCM path, SCM flags, SCM mode), "Open the file named by @var{path} for reading and/or writing.\n" @@ -319,32 +373,33 @@ SCM_DEFINE (scm_open, "open", 2, 1, 0, fd = scm_to_int (scm_open_fdes (path, flags, mode)); iflags = SCM_NUM2INT (2, flags); + port_mode = (char *) flags_to_mode (iflags); + newpt = scm_fdes_to_port (fd, port_mode, path); + return newpt; +} +#undef FUNC_NAME - if ((iflags & O_RDWR) == O_RDWR) - { - /* Opened read-write. */ - if (iflags & O_APPEND) - port_mode = "a+"; - else if (iflags & O_CREAT) - port_mode = "w+"; - else - port_mode = "r+"; - } - else - { - /* Opened read-only or write-only. */ - if (iflags & O_APPEND) - port_mode = "a"; - else if (iflags & O_WRONLY) - port_mode = "w"; - else - port_mode = "r"; - } +#ifdef HAVE_OPENAT +SCM_DEFINE (scm_openat, "openat", 3, 1, 0, + (SCM dir, SCM path, SCM flags, SCM mode), + "Similar to @code{open}, but resolve the file name @var{path}\n" + "relative to the directory referred to by the file port @var{dir}\n" + "instead.") +#define FUNC_NAME s_scm_openat +{ + SCM newpt; + char *port_mode; + int fd; + int iflags; - newpt = scm_fdes_to_port (fd, port_mode, path); + fd = scm_to_int (scm_open_fdes_at (dir, path, flags, mode)); + iflags = SCM_NUM2INT (2, flags); + port_mode = (char *) flags_to_mode (iflags); + newpt = scm_fdes_to_port (fd, (char *) port_mode, path); return newpt; } #undef FUNC_NAME +#endif /* HAVE_OPENAT */ SCM_DEFINE (scm_close, "close", 1, 0, 0, (SCM fd_or_port), diff --git a/libguile/filesys.h b/libguile/filesys.h index 8af0f989a..1ce50d30e 100644 --- a/libguile/filesys.h +++ b/libguile/filesys.h @@ -44,7 +44,9 @@ SCM_API SCM scm_chmod (SCM object, SCM mode); SCM_API SCM scm_chmodat (SCM dir, SCM pathname, SCM mode, SCM flags); SCM_API SCM scm_umask (SCM mode); SCM_API SCM scm_open_fdes (SCM path, SCM flags, SCM mode); +SCM_API SCM scm_open_fdes_at (SCM dir, SCM path, SCM flags, SCM mode); SCM_API SCM scm_open (SCM path, SCM flags, SCM mode); +SCM_API SCM scm_openat (SCM dir, 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); diff --git a/libguile/syscalls.h b/libguile/syscalls.h index 37d532e60..6f4061138 100644 --- a/libguile/syscalls.h +++ b/libguile/syscalls.h @@ -58,6 +58,7 @@ #define lstat_or_lstat64 CHOOSE_LARGEFILE(lstat,lstat64) #define off_t_or_off64_t CHOOSE_LARGEFILE(off_t,off64_t) #define open_or_open64 CHOOSE_LARGEFILE(open,open64) +#define openat_or_openat64 CHOOSE_LARGEFILE(openat,openat64) #define readdir_or_readdir64 CHOOSE_LARGEFILE(readdir,readdir64) #if SCM_HAVE_READDIR64_R == 1 # define readdir_r_or_readdir64_r CHOOSE_LARGEFILE(readdir_r,readdir64_r) -- 2.30.2