From f6de7e727ed410b5d4ed782c464758c77147a336 Mon Sep 17 00:00:00 2001 From: Lorenzo Beretta Date: Wed, 28 Apr 2021 14:20:53 +0200 Subject: [PATCH] recutils: patch to fix recins not working outside of $TMPDIR Details at https://git.savannah.gnu.org/cgit/recutils.git/commit/utils/recutl.c?id=86f662a8202408134a235572ec60141d3082f975 Will no longer be necessary once 1.9 is released; fixes bug #30546 Thanks to ericonr for all the assistance. note to self: bootstrap.conf is not shipped add *temporary* dependency on automake adding gnulib pieces is a real chore... And then the GNU tools (rightfully) decided that the manpages were out of date, because a file has been modified, and insisted on running help2man - I simply told pre_configure to update the timestamps of the manpages. --- srcpkgs/recutils/patches/copyfile.patch | 1929 +++++++++++++++++++++++ srcpkgs/recutils/patches/exdev.patch | 53 + srcpkgs/recutils/template | 12 +- 3 files changed, 1992 insertions(+), 2 deletions(-) create mode 100644 srcpkgs/recutils/patches/copyfile.patch create mode 100644 srcpkgs/recutils/patches/exdev.patch diff --git a/srcpkgs/recutils/patches/copyfile.patch b/srcpkgs/recutils/patches/copyfile.patch new file mode 100644 index 000000000000..c2f289f6f41d --- /dev/null +++ b/srcpkgs/recutils/patches/copyfile.patch @@ -0,0 +1,1929 @@ +diff --git a/lib/copy-file.c b/lib/copy-file.c +new file mode 100644 +index 0000000..15e17ae +--- /dev/null ++++ b/lib/copy-file.c +@@ -0,0 +1,221 @@ ++/* Copying of files. ++ Copyright (C) 2001-2003, 2006-2007, 2009-2021 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2001. ++ ++ 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 . */ ++ ++ ++#include ++ ++/* Specification. */ ++#include "copy-file.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "error.h" ++#include "ignore-value.h" ++#include "safe-read.h" ++#include "full-write.h" ++#include "stat-time.h" ++#include "utimens.h" ++#include "acl.h" ++#include "binary-io.h" ++#include "quote.h" ++#include "gettext.h" ++ ++#define _(str) gettext (str) ++ ++enum { IO_SIZE = 32 * 1024 }; ++ ++int ++qcopy_file_preserving (const char *src_filename, const char *dest_filename) ++{ ++ int err = 0; ++ int src_fd; ++ struct stat statbuf; ++ int mode; ++ int dest_fd; ++ ++ src_fd = open (src_filename, O_RDONLY | O_BINARY | O_CLOEXEC); ++ if (src_fd < 0) ++ return GL_COPY_ERR_OPEN_READ; ++ if (fstat (src_fd, &statbuf) < 0) ++ { ++ err = GL_COPY_ERR_OPEN_READ; ++ goto error_src; ++ } ++ ++ mode = statbuf.st_mode & 07777; ++ off_t inbytes = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1; ++ bool empty_regular_file = inbytes == 0; ++ ++ dest_fd = open (dest_filename, ++ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, ++ 0600); ++ if (dest_fd < 0) ++ { ++ err = GL_COPY_ERR_OPEN_BACKUP_WRITE; ++ goto error_src; ++ } ++ ++ /* Copy the file contents. FIXME: Do not copy holes. */ ++ while (0 < inbytes) ++ { ++ size_t copy_max = -1; ++ copy_max -= copy_max % IO_SIZE; ++ size_t len = inbytes < copy_max ? inbytes : copy_max; ++ ssize_t copied = copy_file_range (src_fd, NULL, dest_fd, NULL, len, 0); ++ if (copied <= 0) ++ break; ++ inbytes -= copied; ++ } ++ ++ /* Finish up with read/write, in case the file was not a regular ++ file, or the file shrank or had I/O errors (in which case find ++ whether it was a read or write error). Read empty regular files ++ since they might be in /proc with their true sizes unknown until ++ they are read. */ ++ if (inbytes != 0 || empty_regular_file) ++ { ++ char smallbuf[1024]; ++ int bufsize = IO_SIZE; ++ char *buf = malloc (bufsize); ++ if (!buf) ++ buf = smallbuf, bufsize = sizeof smallbuf; ++ ++ while (true) ++ { ++ size_t n_read = safe_read (src_fd, buf, bufsize); ++ if (n_read == 0) ++ break; ++ if (n_read == SAFE_READ_ERROR) ++ { ++ err = GL_COPY_ERR_READ; ++ break; ++ } ++ if (full_write (dest_fd, buf, n_read) < n_read) ++ { ++ err = GL_COPY_ERR_WRITE; ++ break; ++ } ++ } ++ ++ if (buf != smallbuf) ++ free (buf); ++ if (err) ++ goto error_src_dest; ++ } ++ ++#if !USE_ACL ++ if (close (dest_fd) < 0) ++ { ++ err = GL_COPY_ERR_WRITE; ++ goto error_src; ++ } ++ if (close (src_fd) < 0) ++ return GL_COPY_ERR_AFTER_READ; ++#endif ++ ++ /* Preserve the access and modification times. */ ++ { ++ struct timespec ts[2]; ++ ++ ts[0] = get_stat_atime (&statbuf); ++ ts[1] = get_stat_mtime (&statbuf); ++ utimens (dest_filename, ts); ++ } ++ ++#if HAVE_CHOWN ++ /* Preserve the owner and group. */ ++ ignore_value (chown (dest_filename, statbuf.st_uid, statbuf.st_gid)); ++#endif ++ ++ /* Preserve the access permissions. */ ++#if USE_ACL ++ switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode)) ++ { ++ case -2: ++ err = GL_COPY_ERR_GET_ACL; ++ goto error_src_dest; ++ case -1: ++ err = GL_COPY_ERR_SET_ACL; ++ goto error_src_dest; ++ } ++#else ++ chmod (dest_filename, mode); ++#endif ++ ++#if USE_ACL ++ if (close (dest_fd) < 0) ++ { ++ err = GL_COPY_ERR_WRITE; ++ goto error_src; ++ } ++ if (close (src_fd) < 0) ++ return GL_COPY_ERR_AFTER_READ; ++#endif ++ ++ return 0; ++ ++ error_src_dest: ++ close (dest_fd); ++ error_src: ++ close (src_fd); ++ return err; ++} ++ ++void ++copy_file_preserving (const char *src_filename, const char *dest_filename) ++{ ++ switch (qcopy_file_preserving (src_filename, dest_filename)) ++ { ++ case 0: ++ return; ++ ++ case GL_COPY_ERR_OPEN_READ: ++ error (EXIT_FAILURE, errno, _("error while opening %s for reading"), ++ quote (src_filename)); ++ ++ case GL_COPY_ERR_OPEN_BACKUP_WRITE: ++ error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"), ++ quote (dest_filename)); ++ ++ case GL_COPY_ERR_READ: ++ error (EXIT_FAILURE, errno, _("error reading %s"), ++ quote (src_filename)); ++ ++ case GL_COPY_ERR_WRITE: ++ error (EXIT_FAILURE, errno, _("error writing %s"), ++ quote (dest_filename)); ++ ++ case GL_COPY_ERR_AFTER_READ: ++ error (EXIT_FAILURE, errno, _("error after reading %s"), ++ quote (src_filename)); ++ ++ case GL_COPY_ERR_GET_ACL: ++ error (EXIT_FAILURE, errno, "%s", quote (src_filename)); ++ ++ case GL_COPY_ERR_SET_ACL: ++ error (EXIT_FAILURE, errno, _("preserving permissions for %s"), ++ quote (dest_filename)); ++ ++ default: ++ abort (); ++ } ++} +diff --git a/lib/copy-file.h b/lib/copy-file.h +new file mode 100644 +index 0000000..09281d6 +--- /dev/null ++++ b/lib/copy-file.h +@@ -0,0 +1,54 @@ ++/* Copying of files. ++ Copyright (C) 2001-2003, 2009-2021 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2001. ++ ++ 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 . */ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/* Error codes returned by qcopy_file_preserving. */ ++enum ++{ ++ GL_COPY_ERR_OPEN_READ = -1, ++ GL_COPY_ERR_OPEN_BACKUP_WRITE = -2, ++ GL_COPY_ERR_READ = -3, ++ GL_COPY_ERR_WRITE = -4, ++ GL_COPY_ERR_AFTER_READ = -5, ++ GL_COPY_ERR_GET_ACL = -6, ++ GL_COPY_ERR_SET_ACL = -7 ++}; ++ ++/* Copy a regular file: from src_filename to dest_filename. ++ The destination file is assumed to be a backup file. ++ Modification times, owner, group and access permissions are preserved as ++ far as possible. ++ Return 0 if successful, otherwise set errno and return one of the error ++ codes above. */ ++extern int qcopy_file_preserving (const char *src_filename, const char *dest_filename); ++ ++/* Copy a regular file: from src_filename to dest_filename. ++ The destination file is assumed to be a backup file. ++ Modification times, owner, group and access permissions are preserved as ++ far as possible. ++ Exit upon failure. */ ++extern void copy_file_preserving (const char *src_filename, const char *dest_filename); ++ ++ ++#ifdef __cplusplus ++} ++#endif +diff --git a/m4/copy-file.m4 b/m4/copy-file.m4 +new file mode 100644 +index 0000000..6211171 +--- /dev/null ++++ b/m4/copy-file.m4 +@@ -0,0 +1,11 @@ ++# copy-file.m4 serial 5 ++dnl Copyright (C) 2003, 2009-2021 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++AC_DEFUN([gl_COPY_FILE], ++[ ++ AC_CHECK_HEADERS_ONCE([unistd.h]) ++ AC_CHECK_FUNCS([chown]) ++]) + +diff --git a/lib/Makefile.am b/lib/Makefile.am +index a6ec30b..f363b86 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -219,6 +225,12 @@ + + ## end gnulib module base64 + ++## begin gnulib module binary-io ++ ++librecutils_la_SOURCES += binary-io.h binary-io.c ++ ++## end gnulib module binary-io ++ + ## begin gnulib module btowc + + +@@ -289,6 +301,21 @@ + + ## end gnulib module closeout + ++## begin gnulib module copy-file ++ ++librecutils_la_SOURCES += copy-file.h copy-file.c ++ ++## end gnulib module copy-file ++ ++## begin gnulib module copy-file-range ++ ++ ++EXTRA_DIST += copy-file-range.c ++ ++EXTRA_librecutils_la_SOURCES += copy-file-range.c ++ ++## end gnulib module copy-file-range ++ + ## begin gnulib module crc + + librecutils_la_SOURCES += crc.c +@@ -605,6 +634,12 @@ + + ## end gnulib module ftello + ++## begin gnulib module full-write ++ ++librecutils_la_SOURCES += full-write.h full-write.c ++ ++## end gnulib module full-write ++ + ## begin gnulib module fwriting + + +@@ -778,6 +813,13 @@ + + ## end gnulib module havelib + ++## begin gnulib module ignore-value ++ ++ ++EXTRA_DIST += ignore-value.h ++ ++## end gnulib module ignore-value ++ + ## begin gnulib module intprops + + +@@ -1761,6 +1827,32 @@ + + ## end gnulib module root-uid + ++## begin gnulib module safe-read ++ ++librecutils_la_SOURCES += safe-read.c ++ ++EXTRA_DIST += safe-read.h sys-limits.h ++ ++## end gnulib module safe-read ++ ++## begin gnulib module safe-write ++ ++librecutils_la_SOURCES += safe-write.c ++ ++EXTRA_DIST += safe-read.c safe-write.h sys-limits.h ++ ++EXTRA_librecutils_la_SOURCES += safe-read.c ++ ++## end gnulib module safe-write ++ ++## begin gnulib module utimens ++ ++librecutils_la_SOURCES += utimens.c ++ ++EXTRA_DIST += utimens.h ++ ++## end gnulib module utimens ++ + ## begin gnulib module same-inode + + +diff --git a/lib/ignore-value.h b/lib/ignore-value.h +new file mode 100644 +index 0000000..0a3cf1e +--- /dev/null ++++ b/lib/ignore-value.h +@@ -0,0 +1,51 @@ ++/* ignore a function return without a compiler warning. -*- coding: utf-8 -*- ++ ++ Copyright (C) 2008-2021 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 . */ ++ ++/* Written by Jim Meyering, Eric Blake and Pádraig Brady. */ ++ ++/* Use "ignore_value" to avoid a warning when using a function declared with ++ gcc's warn_unused_result attribute, but for which you really do want to ++ ignore the result. Traditionally, people have used a "(void)" cast to ++ indicate that a function's return value is deliberately unused. However, ++ if the function is declared with __attribute__((warn_unused_result)), ++ gcc issues a warning even with the cast. ++ ++ Caution: most of the time, you really should heed gcc's warning, and ++ check the return value. However, in those exceptional cases in which ++ you're sure you know what you're doing, use this function. ++ ++ For the record, here's one of the ignorable warnings: ++ "copy.c:233: warning: ignoring return value of 'fchown', ++ declared with attribute warn_unused_result". */ ++ ++#ifndef _GL_IGNORE_VALUE_H ++#define _GL_IGNORE_VALUE_H ++ ++/* Normally casting an expression to void discards its value, but GCC ++ versions 3.4 and newer have __attribute__ ((__warn_unused_result__)) ++ which may cause unwanted diagnostics in that case. Use __typeof__ ++ and __extension__ to work around the problem, if the workaround is ++ known to be needed. ++ The workaround is not needed with clang. */ ++#if (3 < __GNUC__ + (4 <= __GNUC_MINOR__)) && !defined __clang__ ++# define ignore_value(x) \ ++ (__extension__ ({ __typeof__ (x) __x = (x); (void) __x; })) ++#else ++# define ignore_value(x) ((void) (x)) ++#endif ++ ++#endif +diff --git a/lib/safe-read.c b/lib/safe-read.c +new file mode 100644 +index 0000000..be9c33c +--- /dev/null ++++ b/lib/safe-read.c +@@ -0,0 +1,71 @@ ++/* An interface to read and write that retries after interrupts. ++ ++ Copyright (C) 1993-1994, 1998, 2002-2006, 2009-2021 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 . */ ++ ++#include ++ ++/* Specification. */ ++#ifdef SAFE_WRITE ++# include "safe-write.h" ++#else ++# include "safe-read.h" ++#endif ++ ++/* Get ssize_t. */ ++#include ++#include ++ ++#include ++ ++#ifdef EINTR ++# define IS_EINTR(x) ((x) == EINTR) ++#else ++# define IS_EINTR(x) 0 ++#endif ++ ++#include "sys-limits.h" ++ ++#ifdef SAFE_WRITE ++# define safe_rw safe_write ++# define rw write ++#else ++# define safe_rw safe_read ++# define rw read ++# undef const ++# define const /* empty */ ++#endif ++ ++/* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if ++ interrupted. Return the actual number of bytes read(written), zero for EOF, ++ or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */ ++size_t ++safe_rw (int fd, void const *buf, size_t count) ++{ ++ for (;;) ++ { ++ ssize_t result = rw (fd, buf, count); ++ ++ if (0 <= result) ++ return result; ++ else if (IS_EINTR (errno)) ++ continue; ++ else if (errno == EINVAL && SYS_BUFSIZE_MAX < count) ++ count = SYS_BUFSIZE_MAX; ++ else ++ return result; ++ } ++} +diff --git a/lib/safe-read.h b/lib/safe-read.h +new file mode 100644 +index 0000000..5482906 +--- /dev/null ++++ b/lib/safe-read.h +@@ -0,0 +1,47 @@ ++/* An interface to read() that retries after interrupts. ++ Copyright (C) 2002, 2006, 2009-2021 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 . */ ++ ++/* Some system calls may be interrupted and fail with errno = EINTR in the ++ following situations: ++ - The process is stopped and restarted (signal SIGSTOP and SIGCONT, user ++ types Ctrl-Z) on some platforms: Mac OS X. ++ - The process receives a signal for which a signal handler was installed ++ with sigaction() with an sa_flags field that does not contain ++ SA_RESTART. ++ - The process receives a signal for which a signal handler was installed ++ with signal() and for which no call to siginterrupt(sig,0) was done, ++ on some platforms: AIX, HP-UX, IRIX, OSF/1, Solaris. ++ ++ This module provides a wrapper around read() that handles EINTR. */ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#define SAFE_READ_ERROR ((size_t) -1) ++ ++/* Read up to COUNT bytes at BUF from descriptor FD, retrying if interrupted. ++ Return the actual number of bytes read, zero for EOF, or SAFE_READ_ERROR ++ upon error. */ ++extern size_t safe_read (int fd, void *buf, size_t count); ++ ++ ++#ifdef __cplusplus ++} ++#endif +diff --git a/lib/sys-limits.h b/lib/sys-limits.h +new file mode 100644 +index 0000000..cd05a81 +--- /dev/null ++++ b/lib/sys-limits.h +@@ -0,0 +1,42 @@ ++/* System call limits ++ ++ Copyright 2018-2021 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 2, 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 . */ ++ ++#ifndef _GL_SYS_LIMITS_H ++#define _GL_SYS_LIMITS_H ++ ++#include ++ ++/* Maximum number of bytes to read or write in a single system call. ++ This can be useful for system calls like sendfile on GNU/Linux, ++ which do not handle more than MAX_RW_COUNT bytes correctly. ++ The Linux kernel MAX_RW_COUNT is at least INT_MAX >> 20 << 20, ++ where the 20 comes from the Hexagon port with 1 MiB pages; use that ++ as an approximation, as the exact value may not be available to us. ++ ++ Using this also works around a serious Linux bug before 2.6.16; see ++ . ++ ++ Using this also works around a Tru64 5.1 bug, where attempting ++ to read INT_MAX bytes fails with errno == EINVAL. See ++ . ++ ++ Using this is likely to work around similar bugs in other operating ++ systems. */ ++ ++enum { SYS_BUFSIZE_MAX = INT_MAX >> 20 << 20 }; ++ ++#endif +diff --git a/m4/safe-read.m4 b/m4/safe-read.m4 +new file mode 100644 +index 0000000..3cba288 +--- /dev/null ++++ b/m4/safe-read.m4 +@@ -0,0 +1,12 @@ ++# safe-read.m4 serial 6 ++dnl Copyright (C) 2002-2003, 2005-2006, 2009-2021 Free Software Foundation, ++dnl Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++# Prerequisites of lib/safe-read.c. ++AC_DEFUN([gl_PREREQ_SAFE_READ], ++[ ++ AC_REQUIRE([gt_TYPE_SSIZE_T]) ++]) +diff --git a/lib/full-write.c b/lib/full-write.c +new file mode 100644 +index 0000000..2c0e06b +--- /dev/null ++++ b/lib/full-write.c +@@ -0,0 +1,79 @@ ++/* An interface to read and write that retries (if necessary) until complete. ++ ++ Copyright (C) 1993-1994, 1997-2006, 2009-2021 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 . */ ++ ++#include ++ ++/* Specification. */ ++#ifdef FULL_READ ++# include "full-read.h" ++#else ++# include "full-write.h" ++#endif ++ ++#include ++ ++#ifdef FULL_READ ++# include "safe-read.h" ++# define safe_rw safe_read ++# define full_rw full_read ++# undef const ++# define const /* empty */ ++#else ++# include "safe-write.h" ++# define safe_rw safe_write ++# define full_rw full_write ++#endif ++ ++#ifdef FULL_READ ++/* Set errno to zero upon EOF. */ ++# define ZERO_BYTE_TRANSFER_ERRNO 0 ++#else ++/* Some buggy drivers return 0 when one tries to write beyond ++ a device's end. (Example: Linux 1.2.13 on /dev/fd0.) ++ Set errno to ENOSPC so they get a sensible diagnostic. */ ++# define ZERO_BYTE_TRANSFER_ERRNO ENOSPC ++#endif ++ ++/* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if ++ interrupted or if a partial write(read) occurs. Return the number ++ of bytes transferred. ++ When writing, set errno if fewer than COUNT bytes are written. ++ When reading, if fewer than COUNT bytes are read, you must examine ++ errno to distinguish failure from EOF (errno == 0). */ ++size_t ++full_rw (int fd, const void *buf, size_t count) ++{ ++ size_t total = 0; ++ const char *ptr = (const char *) buf; ++ ++ while (count > 0) ++ { ++ size_t n_rw = safe_rw (fd, ptr, count); ++ if (n_rw == (size_t) -1) ++ break; ++ if (n_rw == 0) ++ { ++ errno = ZERO_BYTE_TRANSFER_ERRNO; ++ break; ++ } ++ total += n_rw; ++ ptr += n_rw; ++ count -= n_rw; ++ } ++ ++ return total; ++} +diff --git a/lib/full-write.h b/lib/full-write.h +new file mode 100644 +index 0000000..6c4e28a +--- /dev/null ++++ b/lib/full-write.h +@@ -0,0 +1,34 @@ ++/* An interface to write() that writes all it is asked to write. ++ ++ Copyright (C) 2002-2003, 2009-2021 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 . */ ++ ++#include ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted ++ or if partial writes occur. Return the number of bytes successfully ++ written, setting errno if that is less than COUNT. */ ++extern size_t full_write (int fd, const void *buf, size_t count); ++ ++ ++#ifdef __cplusplus ++} ++#endif +diff --git a/lib/utimens.c b/lib/utimens.c +new file mode 100644 +index 0000000..06d1aa3 +--- /dev/null ++++ b/lib/utimens.c +@@ -0,0 +1,647 @@ ++/* Set file access and modification times. ++ ++ Copyright (C) 2003-2021 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 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 . */ ++ ++/* Written by Paul Eggert. */ ++ ++/* derived from a function in touch.c */ ++ ++#include ++ ++#define _GL_UTIMENS_INLINE _GL_EXTERN_INLINE ++#include "utimens.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "stat-time.h" ++#include "timespec.h" ++ ++/* On native Windows, use SetFileTime; but avoid this when compiling ++ GNU Emacs, which arranges for this in some other way and which ++ defines WIN32_LEAN_AND_MEAN itself. */ ++ ++#if defined _WIN32 && ! defined __CYGWIN__ && ! defined EMACS_CONFIGURATION ++# define USE_SETFILETIME ++# define WIN32_LEAN_AND_MEAN ++# include ++# if GNULIB_MSVC_NOTHROW ++# include "msvc-nothrow.h" ++# else ++# include ++# endif ++#endif ++ ++/* Avoid recursion with rpl_futimens or rpl_utimensat. */ ++#undef futimens ++#if !HAVE_NEARLY_WORKING_UTIMENSAT ++# undef utimensat ++#endif ++ ++/* Solaris 9 mistakenly succeeds when given a non-directory with a ++ trailing slash. Force the use of rpl_stat for a fix. */ ++#ifndef REPLACE_FUNC_STAT_FILE ++# define REPLACE_FUNC_STAT_FILE 0 ++#endif ++ ++#if HAVE_UTIMENSAT || HAVE_FUTIMENS ++/* Cache variables for whether the utimensat syscall works; used to ++ avoid calling the syscall if we know it will just fail with ENOSYS, ++ and to avoid unnecessary work in massaging timestamps if the ++ syscall will work. Multiple variables are needed, to distinguish ++ between the following scenarios on Linux: ++ utimensat doesn't exist, or is in glibc but kernel 2.6.18 fails with ENOSYS ++ kernel 2.6.22 and earlier rejects AT_SYMLINK_NOFOLLOW ++ kernel 2.6.25 and earlier reject UTIME_NOW/UTIME_OMIT with non-zero tv_sec ++ kernel 2.6.32 used with xfs or ntfs-3g fail to honor UTIME_OMIT ++ utimensat completely works ++ For each cache variable: 0 = unknown, 1 = yes, -1 = no. */ ++static int utimensat_works_really; ++static int lutimensat_works_really; ++#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */ ++ ++/* Validate the requested timestamps. Return 0 if the resulting ++ timespec can be used for utimensat (after possibly modifying it to ++ work around bugs in utimensat). Return a positive value if the ++ timespec needs further adjustment based on stat results: 1 if any ++ adjustment is needed for utimes, and 2 if any adjustment is needed ++ for Linux utimensat. Return -1, with errno set to EINVAL, if ++ timespec is out of range. */ ++static int ++validate_timespec (struct timespec timespec[2]) ++{ ++ int result = 0; ++ int utime_omit_count = 0; ++ if ((timespec[0].tv_nsec != UTIME_NOW ++ && timespec[0].tv_nsec != UTIME_OMIT ++ && ! (0 <= timespec[0].tv_nsec ++ && timespec[0].tv_nsec < TIMESPEC_HZ)) ++ || (timespec[1].tv_nsec != UTIME_NOW ++ && timespec[1].tv_nsec != UTIME_OMIT ++ && ! (0 <= timespec[1].tv_nsec ++ && timespec[1].tv_nsec < TIMESPEC_HZ))) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ /* Work around Linux kernel 2.6.25 bug, where utimensat fails with ++ EINVAL if tv_sec is not 0 when using the flag values of tv_nsec. ++ Flag a Linux kernel 2.6.32 bug, where an mtime of UTIME_OMIT ++ fails to bump ctime. */ ++ if (timespec[0].tv_nsec == UTIME_NOW ++ || timespec[0].tv_nsec == UTIME_OMIT) ++ { ++ timespec[0].tv_sec = 0; ++ result = 1; ++ if (timespec[0].tv_nsec == UTIME_OMIT) ++ utime_omit_count++; ++ } ++ if (timespec[1].tv_nsec == UTIME_NOW ++ || timespec[1].tv_nsec == UTIME_OMIT) ++ { ++ timespec[1].tv_sec = 0; ++ result = 1; ++ if (timespec[1].tv_nsec == UTIME_OMIT) ++ utime_omit_count++; ++ } ++ return result + (utime_omit_count == 1); ++} ++ ++/* Normalize any UTIME_NOW or UTIME_OMIT values in (*TS)[0] and (*TS)[1], ++ using STATBUF to obtain the current timestamps of the file. If ++ both times are UTIME_NOW, set *TS to NULL (as this can avoid some ++ permissions issues). If both times are UTIME_OMIT, return true ++ (nothing further beyond the prior collection of STATBUF is ++ necessary); otherwise return false. */ ++static bool ++update_timespec (struct stat const *statbuf, struct timespec **ts) ++{ ++ struct timespec *timespec = *ts; ++ if (timespec[0].tv_nsec == UTIME_OMIT ++ && timespec[1].tv_nsec == UTIME_OMIT) ++ return true; ++ if (timespec[0].tv_nsec == UTIME_NOW ++ && timespec[1].tv_nsec == UTIME_NOW) ++ { ++ *ts = NULL; ++ return false; ++ } ++ ++ if (timespec[0].tv_nsec == UTIME_OMIT) ++ timespec[0] = get_stat_atime (statbuf); ++ else if (timespec[0].tv_nsec == UTIME_NOW) ++ gettime (×pec[0]); ++ ++ if (timespec[1].tv_nsec == UTIME_OMIT) ++ timespec[1] = get_stat_mtime (statbuf); ++ else if (timespec[1].tv_nsec == UTIME_NOW) ++ gettime (×pec[1]); ++ ++ return false; ++} ++ ++/* Set the access and modification timestamps of FD (a.k.a. FILE) to be ++ TIMESPEC[0] and TIMESPEC[1], respectively. ++ FD must be either negative -- in which case it is ignored -- ++ or a file descriptor that is open on FILE. ++ If FD is nonnegative, then FILE can be NULL, which means ++ use just futimes (or equivalent) instead of utimes (or equivalent), ++ and fail if on an old system without futimes (or equivalent). ++ If TIMESPEC is null, set the timestamps to the current time. ++ Return 0 on success, -1 (setting errno) on failure. */ ++ ++int ++fdutimens (int fd, char const *file, struct timespec const timespec[2]) ++{ ++ struct timespec adjusted_timespec[2]; ++ struct timespec *ts = timespec ? adjusted_timespec : NULL; ++ int adjustment_needed = 0; ++ struct stat st; ++ ++ if (ts) ++ { ++ adjusted_timespec[0] = timespec[0]; ++ adjusted_timespec[1] = timespec[1]; ++ adjustment_needed = validate_timespec (ts); ++ } ++ if (adjustment_needed < 0) ++ return -1; ++ ++ /* Require that at least one of FD or FILE are potentially valid, to avoid ++ a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather ++ than failing. */ ++ if (fd < 0 && !file) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ /* Some Linux-based NFS clients are buggy, and mishandle timestamps ++ of files in NFS file systems in some cases. We have no ++ configure-time test for this, but please see ++ for references to ++ some of the problems with Linux 2.6.16. If this affects you, ++ compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to ++ help in some cases, albeit at a cost in performance. But you ++ really should upgrade your kernel to a fixed version, since the ++ problem affects many applications. */ ++ ++#if HAVE_BUGGY_NFS_TIME_STAMPS ++ if (fd < 0) ++ sync (); ++ else ++ fsync (fd); ++#endif ++ ++ /* POSIX 2008 added two interfaces to set file timestamps with ++ nanosecond resolution; newer Linux implements both functions via ++ a single syscall. We provide a fallback for ENOSYS (for example, ++ compiling against Linux 2.6.25 kernel headers and glibc 2.7, but ++ running on Linux 2.6.18 kernel). */ ++#if HAVE_UTIMENSAT || HAVE_FUTIMENS ++ if (0 <= utimensat_works_really) ++ { ++ int result; ++# if __linux__ || __sun ++ /* As recently as Linux kernel 2.6.32 (Dec 2009), several file ++ systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, ++ but work if both times are either explicitly specified or ++ UTIME_NOW. Work around it with a preparatory [f]stat prior ++ to calling futimens/utimensat; fortunately, there is not much ++ timing impact due to the extra syscall even on file systems ++ where UTIME_OMIT would have worked. ++ ++ The same bug occurs in Solaris 11.1 (Apr 2013). ++ ++ FIXME: Simplify this for Linux in 2016 and for Solaris in ++ 2024, when file system bugs are no longer common. */ ++ if (adjustment_needed == 2) ++ { ++ if (fd < 0 ? stat (file, &st) : fstat (fd, &st)) ++ return -1; ++ if (ts[0].tv_nsec == UTIME_OMIT) ++ ts[0] = get_stat_atime (&st); ++ else if (ts[1].tv_nsec == UTIME_OMIT) ++ ts[1] = get_stat_mtime (&st); ++ /* Note that st is good, in case utimensat gives ENOSYS. */ ++ adjustment_needed++; ++ } ++# endif ++# if HAVE_UTIMENSAT ++ if (fd < 0) ++ { ++# if defined __APPLE__ && defined __MACH__ ++ size_t len = strlen (file); ++ if (len > 0 && file[len - 1] == '/') ++ { ++ struct stat statbuf; ++ if (stat (file, &statbuf) < 0) ++ return -1; ++ if (!S_ISDIR (statbuf.st_mode)) ++ { ++ errno = ENOTDIR; ++ return -1; ++ } ++ } ++# endif ++ result = utimensat (AT_FDCWD, file, ts, 0); ++# ifdef __linux__ ++ /* Work around a kernel bug: ++ https://bugzilla.redhat.com/show_bug.cgi?id=442352 ++ https://bugzilla.redhat.com/show_bug.cgi?id=449910 ++ It appears that utimensat can mistakenly return 280 rather ++ than -1 upon ENOSYS failure. ++ FIXME: remove in 2010 or whenever the offending kernels ++ are no longer in common use. */ ++ if (0 < result) ++ errno = ENOSYS; ++# endif /* __linux__ */ ++ if (result == 0 || errno != ENOSYS) ++ { ++ utimensat_works_really = 1; ++ return result; ++ } ++ } ++# endif /* HAVE_UTIMENSAT */ ++# if HAVE_FUTIMENS ++ if (0 <= fd) ++ { ++ result = futimens (fd, ts); ++# ifdef __linux__ ++ /* Work around the same bug as above. */ ++ if (0 < result) ++ errno = ENOSYS; ++# endif /* __linux__ */ ++ if (result == 0 || errno != ENOSYS) ++ { ++ utimensat_works_really = 1; ++ return result; ++ } ++ } ++# endif /* HAVE_FUTIMENS */ ++ } ++ utimensat_works_really = -1; ++ lutimensat_works_really = -1; ++#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */ ++ ++#ifdef USE_SETFILETIME ++ /* On native Windows, use SetFileTime(). See ++ ++ */ ++ if (0 <= fd) ++ { ++ HANDLE handle; ++ FILETIME current_time; ++ FILETIME last_access_time; ++ FILETIME last_write_time; ++ ++ handle = (HANDLE) _get_osfhandle (fd); ++ if (handle == INVALID_HANDLE_VALUE) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ if (ts == NULL || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) ++ { ++ /* GetSystemTimeAsFileTime ++ . ++ It would be overkill to use ++ GetSystemTimePreciseAsFileTime ++ . */ ++ GetSystemTimeAsFileTime (¤t_time); ++ } ++ ++ if (ts == NULL || ts[0].tv_nsec == UTIME_NOW) ++ { ++ last_access_time = current_time; ++ } ++ else if (ts[0].tv_nsec == UTIME_OMIT) ++ { ++ last_access_time.dwLowDateTime = 0; ++ last_access_time.dwHighDateTime = 0; ++ } ++ else ++ { ++ ULONGLONG time_since_16010101 = ++ (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL; ++ last_access_time.dwLowDateTime = (DWORD) time_since_16010101; ++ last_access_time.dwHighDateTime = time_since_16010101 >> 32; ++ } ++ ++ if (ts == NULL || ts[1].tv_nsec == UTIME_NOW) ++ { ++ last_write_time = current_time; ++ } ++ else if (ts[1].tv_nsec == UTIME_OMIT) ++ { ++ last_write_time.dwLowDateTime = 0; ++ last_write_time.dwHighDateTime = 0; ++ } ++ else ++ { ++ ULONGLONG time_since_16010101 = ++ (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL; ++ last_write_time.dwLowDateTime = (DWORD) time_since_16010101; ++ last_write_time.dwHighDateTime = time_since_16010101 >> 32; ++ } ++ ++ if (SetFileTime (handle, NULL, &last_access_time, &last_write_time)) ++ return 0; ++ else ++ { ++ DWORD sft_error = GetLastError (); ++ #if 0 ++ fprintf (stderr, "fdutimens SetFileTime error 0x%x\n", (unsigned int) sft_error); ++ #endif ++ switch (sft_error) ++ { ++ case ERROR_ACCESS_DENIED: /* fd was opened without O_RDWR */ ++ errno = EACCES; /* not specified by POSIX */ ++ break; ++ default: ++ errno = EINVAL; ++ break; ++ } ++ return -1; ++ } ++ } ++#endif ++ ++ /* The platform lacks an interface to set file timestamps with ++ nanosecond resolution, so do the best we can, discarding any ++ fractional part of the timestamp. */ ++ ++ if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0)) ++ { ++ if (adjustment_needed != 3 ++ && (fd < 0 ? stat (file, &st) : fstat (fd, &st))) ++ return -1; ++ if (ts && update_timespec (&st, &ts)) ++ return 0; ++ } ++ ++ { ++#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES ++ struct timeval timeval[2]; ++ struct timeval *t; ++ if (ts) ++ { ++ timeval[0].tv_sec = ts[0].tv_sec; ++ timeval[0].tv_usec = ts[0].tv_nsec / 1000; ++ timeval[1].tv_sec = ts[1].tv_sec; ++ timeval[1].tv_usec = ts[1].tv_nsec / 1000; ++ t = timeval; ++ } ++ else ++ t = NULL; ++ ++ if (fd < 0) ++ { ++# if HAVE_FUTIMESAT ++ return futimesat (AT_FDCWD, file, t); ++# endif ++ } ++ else ++ { ++ /* If futimesat or futimes fails here, don't try to speed things ++ up by returning right away. glibc can incorrectly fail with ++ errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0 ++ in high security mode doesn't allow ordinary users to read ++ /proc/self, so glibc incorrectly fails with errno == EACCES. ++ If errno == EIO, EPERM, or EROFS, it's probably safe to fail ++ right away, but these cases are rare enough that they're not ++ worth optimizing, and who knows what other messed-up systems ++ are out there? So play it safe and fall back on the code ++ below. */ ++ ++# if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES ++# if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG ++# undef futimes ++# define futimes(fd, t) futimesat (fd, NULL, t) ++# endif ++ if (futimes (fd, t) == 0) ++ { ++# if __linux__ && __GLIBC__ ++ /* Work around a longstanding glibc bug, still present as ++ of 2010-12-27. On older Linux kernels that lack both ++ utimensat and utimes, glibc's futimes rounds instead of ++ truncating when falling back on utime. The same bug ++ occurs in futimesat with a null 2nd arg. */ ++ if (t) ++ { ++ bool abig = 500000 <= t[0].tv_usec; ++ bool mbig = 500000 <= t[1].tv_usec; ++ if ((abig | mbig) && fstat (fd, &st) == 0) ++ { ++ /* If these two subtractions overflow, they'll ++ track the overflows inside the buggy glibc. */ ++ time_t adiff = st.st_atime - t[0].tv_sec; ++ time_t mdiff = st.st_mtime - t[1].tv_sec; ++ ++ struct timeval *tt = NULL; ++ struct timeval truncated_timeval[2]; ++ truncated_timeval[0] = t[0]; ++ truncated_timeval[1] = t[1]; ++ if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0) ++ { ++ tt = truncated_timeval; ++ tt[0].tv_usec = 0; ++ } ++ if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0) ++ { ++ tt = truncated_timeval; ++ tt[1].tv_usec = 0; ++ } ++ if (tt) ++ futimes (fd, tt); ++ } ++ } ++# endif ++ ++ return 0; ++ } ++# endif ++ } ++#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */ ++ ++ if (!file) ++ { ++#if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \ ++ || (HAVE_WORKING_UTIMES && HAVE_FUTIMES)) ++ errno = ENOSYS; ++#endif ++ return -1; ++ } ++ ++#ifdef USE_SETFILETIME ++ return _gl_utimens_windows (file, ts); ++#elif HAVE_WORKING_UTIMES ++ return utimes (file, t); ++#else ++ { ++ struct utimbuf utimbuf; ++ struct utimbuf *ut; ++ if (ts) ++ { ++ utimbuf.actime = ts[0].tv_sec; ++ utimbuf.modtime = ts[1].tv_sec; ++ ut = &utimbuf; ++ } ++ else ++ ut = NULL; ++ ++ return utime (file, ut); ++ } ++#endif /* !HAVE_WORKING_UTIMES */ ++ } ++} ++ ++/* Set the access and modification timestamps of FILE to be ++ TIMESPEC[0] and TIMESPEC[1], respectively. */ ++int ++utimens (char const *file, struct timespec const timespec[2]) ++{ ++ return fdutimens (-1, file, timespec); ++} ++ ++/* Set the access and modification timestamps of FILE to be ++ TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing ++ symlinks. Fail with ENOSYS if the platform does not support ++ changing symlink timestamps, but FILE was a symlink. */ ++int ++lutimens (char const *file, struct timespec const timespec[2]) ++{ ++ struct timespec adjusted_timespec[2]; ++ struct timespec *ts = timespec ? adjusted_timespec : NULL; ++ int adjustment_needed = 0; ++ struct stat st; ++ ++ if (ts) ++ { ++ adjusted_timespec[0] = timespec[0]; ++ adjusted_timespec[1] = timespec[1]; ++ adjustment_needed = validate_timespec (ts); ++ } ++ if (adjustment_needed < 0) ++ return -1; ++ ++ /* The Linux kernel did not support symlink timestamps until ++ utimensat, in version 2.6.22, so we don't need to mimic ++ fdutimens' worry about buggy NFS clients. But we do have to ++ worry about bogus return values. */ ++ ++#if HAVE_UTIMENSAT ++ if (0 <= lutimensat_works_really) ++ { ++ int result; ++# if __linux__ || __sun ++ /* As recently as Linux kernel 2.6.32 (Dec 2009), several file ++ systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, ++ but work if both times are either explicitly specified or ++ UTIME_NOW. Work around it with a preparatory lstat prior to ++ calling utimensat; fortunately, there is not much timing ++ impact due to the extra syscall even on file systems where ++ UTIME_OMIT would have worked. ++ ++ The same bug occurs in Solaris 11.1 (Apr 2013). ++ ++ FIXME: Simplify this for Linux in 2016 and for Solaris in ++ 2024, when file system bugs are no longer common. */ ++ if (adjustment_needed == 2) ++ { ++ if (lstat (file, &st)) ++ return -1; ++ if (ts[0].tv_nsec == UTIME_OMIT) ++ ts[0] = get_stat_atime (&st); ++ else if (ts[1].tv_nsec == UTIME_OMIT) ++ ts[1] = get_stat_mtime (&st); ++ /* Note that st is good, in case utimensat gives ENOSYS. */ ++ adjustment_needed++; ++ } ++# endif ++ result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW); ++# ifdef __linux__ ++ /* Work around a kernel bug: ++ https://bugzilla.redhat.com/show_bug.cgi?id=442352 ++ https://bugzilla.redhat.com/show_bug.cgi?id=449910 ++ It appears that utimensat can mistakenly return 280 rather ++ than -1 upon ENOSYS failure. ++ FIXME: remove in 2010 or whenever the offending kernels ++ are no longer in common use. */ ++ if (0 < result) ++ errno = ENOSYS; ++# endif ++ if (result == 0 || errno != ENOSYS) ++ { ++ utimensat_works_really = 1; ++ lutimensat_works_really = 1; ++ return result; ++ } ++ } ++ lutimensat_works_really = -1; ++#endif /* HAVE_UTIMENSAT */ ++ ++ /* The platform lacks an interface to set file timestamps with ++ nanosecond resolution, so do the best we can, discarding any ++ fractional part of the timestamp. */ ++ ++ if (adjustment_needed || REPLACE_FUNC_STAT_FILE) ++ { ++ if (adjustment_needed != 3 && lstat (file, &st)) ++ return -1; ++ if (ts && update_timespec (&st, &ts)) ++ return 0; ++ } ++ ++ /* On Linux, lutimes is a thin wrapper around utimensat, so there is ++ no point trying lutimes if utimensat failed with ENOSYS. */ ++#if HAVE_LUTIMES && !HAVE_UTIMENSAT ++ { ++ struct timeval timeval[2]; ++ struct timeval *t; ++ int result; ++ if (ts) ++ { ++ timeval[0].tv_sec = ts[0].tv_sec; ++ timeval[0].tv_usec = ts[0].tv_nsec / 1000; ++ timeval[1].tv_sec = ts[1].tv_sec; ++ timeval[1].tv_usec = ts[1].tv_nsec / 1000; ++ t = timeval; ++ } ++ else ++ t = NULL; ++ ++ result = lutimes (file, t); ++ if (result == 0 || errno != ENOSYS) ++ return result; ++ } ++#endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */ ++ ++ /* Out of luck for symlinks, but we still handle regular files. */ ++ if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st)) ++ return -1; ++ if (!S_ISLNK (st.st_mode)) ++ return fdutimens (-1, file, ts); ++ errno = ENOSYS; ++ return -1; ++} +diff --git a/lib/utimens.h b/lib/utimens.h +new file mode 100644 +index 0000000..295d3d7 +--- /dev/null ++++ b/lib/utimens.h +@@ -0,0 +1,49 @@ ++/* Set file access and modification times. ++ ++ Copyright 2012-2021 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 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 . */ ++ ++/* Written by Paul Eggert. */ ++ ++#include ++int fdutimens (int, char const *, struct timespec const [2]); ++int utimens (char const *, struct timespec const [2]); ++int lutimens (char const *, struct timespec const [2]); ++ ++#if GNULIB_FDUTIMENSAT ++# include ++# include ++ ++#ifndef _GL_INLINE_HEADER_BEGIN ++ #error "Please include config.h first." ++#endif ++_GL_INLINE_HEADER_BEGIN ++#ifndef _GL_UTIMENS_INLINE ++# define _GL_UTIMENS_INLINE _GL_INLINE ++#endif ++ ++int fdutimensat (int fd, int dir, char const *name, struct timespec const [2], ++ int atflag); ++ ++/* Using this function makes application code slightly more readable. */ ++_GL_UTIMENS_INLINE int ++lutimensat (int dir, char const *file, struct timespec const times[2]) ++{ ++ return utimensat (dir, file, times, AT_SYMLINK_NOFOLLOW); ++} ++ ++_GL_INLINE_HEADER_END ++ ++#endif +diff --git a/m4/utimens.m4 b/m4/utimens.m4 +new file mode 100644 +index 0000000..2ee4ef9 +--- /dev/null ++++ b/m4/utimens.m4 +@@ -0,0 +1,52 @@ ++dnl Copyright (C) 2003-2021 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++dnl serial 11 ++ ++AC_DEFUN([gl_UTIMENS], ++[ ++ dnl Prerequisites of lib/utimens.c. ++ AC_REQUIRE([gl_FUNC_UTIMES]) ++ AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC]) ++ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles ++ AC_CHECK_FUNCS_ONCE([futimes futimesat futimens utimensat lutimes]) ++ ++ if test $ac_cv_func_futimens = no && test $ac_cv_func_futimesat = yes; then ++ dnl FreeBSD 8.0-rc2 mishandles futimesat(fd,NULL,time). It is not ++ dnl standardized, but Solaris implemented it first and uses it as ++ dnl its only means to set fd time. ++ AC_CACHE_CHECK([whether futimesat handles NULL file], ++ [gl_cv_func_futimesat_works], ++ [touch conftest.file ++ AC_RUN_IFELSE([AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++]GL_MDA_DEFINES], ++ [[int fd = open ("conftest.file", O_RDWR); ++ if (fd < 0) return 1; ++ if (futimesat (fd, NULL, NULL)) return 2; ++ ]])], ++ [gl_cv_func_futimesat_works=yes], ++ [gl_cv_func_futimesat_works=no], ++ [case "$host_os" in ++ # Guess yes on Linux systems. ++ linux-* | linux) gl_cv_func_futimesat_works="guessing yes" ;; ++ # Guess yes on glibc systems. ++ *-gnu*) gl_cv_func_futimesat_works="guessing yes" ;; ++ # If we don't know, obey --enable-cross-guesses. ++ *) gl_cv_func_futimesat_works="$gl_cross_guess_normal" ;; ++ esac ++ ]) ++ rm -f conftest.file]) ++ case "$gl_cv_func_futimesat_works" in ++ *yes) ;; ++ *) ++ AC_DEFINE([FUTIMESAT_NULL_BUG], [1], ++ [Define to 1 if futimesat mishandles a NULL file name.]) ++ ;; ++ esac ++ fi ++]) +diff --git a/m4/utimes.m4 b/m4/utimes.m4 +new file mode 100644 +index 0000000..0440e78 +--- /dev/null ++++ b/m4/utimes.m4 +@@ -0,0 +1,161 @@ ++# Detect some bugs in glibc's implementation of utimes. ++# serial 8 ++ ++dnl Copyright (C) 2003-2005, 2009-2021 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++# See if we need to work around bugs in glibc's implementation of ++# utimes from 2003-07-12 to 2003-09-17. ++# First, there was a bug that would make utimes set mtime ++# and atime to zero (1970-01-01) unconditionally. ++# Then, there was code to round rather than truncate. ++# Then, there was an implementation (sparc64, Linux-2.4.28, glibc-2.3.3) ++# that didn't honor the NULL-means-set-to-current-time semantics. ++# Finally, there was also a version of utimes that failed on read-only ++# files, while utime worked fine (linux-2.2.20, glibc-2.2.5). ++# ++# From Jim Meyering, with suggestions from Paul Eggert. ++ ++AC_DEFUN([gl_FUNC_UTIMES], ++[ ++ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles ++ AC_CACHE_CHECK([whether the utimes function works], ++ [gl_cv_func_working_utimes], ++ [AC_RUN_IFELSE([AC_LANG_SOURCE([[ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++]GL_MDA_DEFINES[ ++ ++static int ++inorder (time_t a, time_t b, time_t c) ++{ ++ return a <= b && b <= c; ++} ++ ++int ++main () ++{ ++ int result = 0; ++ char const *file = "conftest.utimes"; ++ /* On OS/2, file timestamps must be on or after 1980 in local time, ++ with an even number of seconds. */ ++ static struct timeval timeval[2] = {{315620000 + 10, 10}, ++ {315620000 + 1000000, 999998}}; ++ ++ /* Test whether utimes() essentially works. */ ++ { ++ struct stat sbuf; ++ FILE *f = fopen (file, "w"); ++ if (f == NULL) ++ result |= 1; ++ else if (fclose (f) != 0) ++ result |= 1; ++ else if (utimes (file, timeval) != 0) ++ result |= 2; ++ else if (lstat (file, &sbuf) != 0) ++ result |= 1; ++ else if (!(sbuf.st_atime == timeval[0].tv_sec ++ && sbuf.st_mtime == timeval[1].tv_sec)) ++ result |= 4; ++ if (unlink (file) != 0) ++ result |= 1; ++ } ++ ++ /* Test whether utimes() with a NULL argument sets the file's timestamp ++ to the current time. Use 'fstat' as well as 'time' to ++ determine the "current" time, to accommodate NFS file systems ++ if there is a time skew between the host and the NFS server. */ ++ { ++ int fd = open (file, O_WRONLY|O_CREAT, 0644); ++ if (fd < 0) ++ result |= 1; ++ else ++ { ++ time_t t0, t2; ++ struct stat st0, st1, st2; ++ if (time (&t0) == (time_t) -1) ++ result |= 1; ++ else if (fstat (fd, &st0) != 0) ++ result |= 1; ++ else if (utimes (file, timeval) != 0 ++ && (errno != EACCES ++ /* OS/2 kLIBC utimes fails on opened files. */ ++ || close (fd) != 0 ++ || utimes (file, timeval) != 0 ++ || (fd = open (file, O_WRONLY)) < 0)) ++ result |= 2; ++ else if (utimes (file, NULL) != 0 ++ && (errno != EACCES ++ /* OS/2 kLIBC utimes fails on opened files. */ ++ || close (fd) != 0 ++ || utimes (file, NULL) != 0 ++ || (fd = open (file, O_WRONLY)) < 0)) ++ result |= 8; ++ else if (fstat (fd, &st1) != 0) ++ result |= 1; ++ else if (write (fd, "\n", 1) != 1) ++ result |= 1; ++ else if (fstat (fd, &st2) != 0) ++ result |= 1; ++ else if (time (&t2) == (time_t) -1) ++ result |= 1; ++ else ++ { ++ int m_ok_POSIX = inorder (t0, st1.st_mtime, t2); ++ int m_ok_NFS = inorder (st0.st_mtime, st1.st_mtime, st2.st_mtime); ++ if (! (st1.st_atime == st1.st_mtime)) ++ result |= 16; ++ if (! (m_ok_POSIX || m_ok_NFS)) ++ result |= 32; ++ } ++ if (close (fd) != 0) ++ result |= 1; ++ } ++ if (unlink (file) != 0) ++ result |= 1; ++ } ++ ++ /* Test whether utimes() with a NULL argument works on read-only files. */ ++ { ++ int fd = open (file, O_WRONLY|O_CREAT, 0444); ++ if (fd < 0) ++ result |= 1; ++ else if (close (fd) != 0) ++ result |= 1; ++ else if (utimes (file, NULL) != 0) ++ result |= 64; ++ if (unlink (file) != 0) ++ result |= 1; ++ } ++ ++ return result; ++} ++ ]])], ++ [gl_cv_func_working_utimes=yes], ++ [gl_cv_func_working_utimes=no], ++ [case "$host_os" in ++ # Guess yes on musl systems. ++ *-musl*) gl_cv_func_working_utimes="guessing yes" ;; ++ # Guess no on native Windows. ++ mingw*) gl_cv_func_working_utimes="guessing no" ;; ++ *) gl_cv_func_working_utimes="$gl_cross_guess_normal" ;; ++ esac ++ ]) ++ ]) ++ ++ case "$gl_cv_func_working_utimes" in ++ *yes) ++ AC_DEFINE([HAVE_WORKING_UTIMES], [1], [Define if utimes works properly.]) ++ ;; ++ esac ++]) +diff --git a/lib/binary-io.c b/lib/binary-io.c +new file mode 100644 +index 0000000..f267897 +--- /dev/null ++++ b/lib/binary-io.c +@@ -0,0 +1,39 @@ ++/* Binary mode I/O. ++ Copyright 2017-2021 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 . */ ++ ++#include ++ ++#define BINARY_IO_INLINE _GL_EXTERN_INLINE ++#include "binary-io.h" ++ ++#if defined __DJGPP__ || defined __EMX__ ++# include ++ ++int ++set_binary_mode (int fd, int mode) ++{ ++ if (isatty (fd)) ++ /* If FD refers to a console (not a pipe, not a regular file), ++ O_TEXT is the only reasonable mode, both on input and on output. ++ Silently ignore the request. If we were to return -1 here, ++ all programs that use xset_binary_mode would fail when run ++ with console input or console output. */ ++ return O_TEXT; ++ else ++ return __gl_setmode (fd, mode); ++} ++ ++#endif +diff --git a/lib/binary-io.h b/lib/binary-io.h +new file mode 100644 +index 0000000..8654fd2 +--- /dev/null ++++ b/lib/binary-io.h +@@ -0,0 +1,77 @@ ++/* Binary mode I/O. ++ Copyright (C) 2001, 2003, 2005, 2008-2021 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 . */ ++ ++#ifndef _BINARY_H ++#define _BINARY_H ++ ++/* For systems that distinguish between text and binary I/O. ++ O_BINARY is guaranteed by the gnulib . */ ++#include ++ ++/* The MSVC7 doesn't like to be included after '#define fileno ...', ++ so we include it here first. */ ++#include ++ ++#ifndef _GL_INLINE_HEADER_BEGIN ++ #error "Please include config.h first." ++#endif ++_GL_INLINE_HEADER_BEGIN ++#ifndef BINARY_IO_INLINE ++# define BINARY_IO_INLINE _GL_INLINE ++#endif ++ ++#if O_BINARY ++# if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__ ++# include /* declares setmode() */ ++# define __gl_setmode setmode ++# else ++# define __gl_setmode _setmode ++# undef fileno ++# define fileno _fileno ++# endif ++#else ++ /* On reasonable systems, binary I/O is the only choice. */ ++ /* Use a function rather than a macro, to avoid gcc warnings ++ "warning: statement with no effect". */ ++BINARY_IO_INLINE int ++__gl_setmode (int fd _GL_UNUSED, int mode _GL_UNUSED) ++{ ++ return O_BINARY; ++} ++#endif ++ ++/* Set FD's mode to MODE, which should be either O_TEXT or O_BINARY. ++ Return the old mode if successful, -1 (setting errno) on failure. ++ Ordinarily this function would be called 'setmode', since that is ++ its old name on MS-Windows, but it is called 'set_binary_mode' here ++ to avoid colliding with a BSD function of another name. */ ++ ++#if defined __DJGPP__ || defined __EMX__ ++extern int set_binary_mode (int fd, int mode); ++#else ++BINARY_IO_INLINE int ++set_binary_mode (int fd, int mode) ++{ ++ return __gl_setmode (fd, mode); ++} ++#endif ++ ++/* This macro is obsolescent. */ ++#define SET_BINARY(fd) ((void) set_binary_mode (fd, O_BINARY)) ++ ++_GL_INLINE_HEADER_END ++ ++#endif /* _BINARY_H */ +diff --git a/lib/safe-write.c b/lib/safe-write.c +new file mode 100644 +index 0000000..a460dc9 +--- /dev/null ++++ b/lib/safe-write.c +@@ -0,0 +1,18 @@ ++/* An interface to write that retries after interrupts. ++ Copyright (C) 2002, 2009-2021 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 . */ ++ ++#define SAFE_WRITE ++#include "safe-read.c" +diff --git a/lib/safe-write.h b/lib/safe-write.h +new file mode 100644 +index 0000000..4307ffe +--- /dev/null ++++ b/lib/safe-write.h +@@ -0,0 +1,37 @@ ++/* An interface to write() that retries after interrupts. ++ Copyright (C) 2002, 2009-2021 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 . */ ++ ++/* Some system calls may be interrupted and fail with errno = EINTR in the ++ following situations: ++ - The process is stopped and restarted (signal SIGSTOP and SIGCONT, user ++ types Ctrl-Z) on some platforms: Mac OS X. ++ - The process receives a signal for which a signal handler was installed ++ with sigaction() with an sa_flags field that does not contain ++ SA_RESTART. ++ - The process receives a signal for which a signal handler was installed ++ with signal() and for which no call to siginterrupt(sig,0) was done, ++ on some platforms: AIX, HP-UX, IRIX, OSF/1, Solaris. ++ ++ This module provides a wrapper around write() that handles EINTR. */ ++ ++#include ++ ++#define SAFE_WRITE_ERROR ((size_t) -1) ++ ++/* Write up to COUNT bytes at BUF to descriptor FD, retrying if interrupted. ++ Return the actual number of bytes written, zero for EOF, or SAFE_WRITE_ERROR ++ upon error. */ ++extern size_t safe_write (int fd, const void *buf, size_t count); +diff --git a/m4/safe-write.m4 b/m4/safe-write.m4 +new file mode 100644 +index 0000000..ef10d96 +--- /dev/null ++++ b/m4/safe-write.m4 +@@ -0,0 +1,11 @@ ++# safe-write.m4 serial 4 ++dnl Copyright (C) 2002, 2005-2006, 2009-2021 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++# Prerequisites of lib/safe-write.c. ++AC_DEFUN([gl_PREREQ_SAFE_WRITE], ++[ ++ gl_PREREQ_SAFE_READ ++]) + + diff --git a/srcpkgs/recutils/patches/exdev.patch b/srcpkgs/recutils/patches/exdev.patch new file mode 100644 index 000000000000..6d1f8bb213a1 --- /dev/null +++ b/srcpkgs/recutils/patches/exdev.patch @@ -0,0 +1,53 @@ +From 86f662a8202408134a235572ec60141d3082f975 Mon Sep 17 00:00:00 2001 +From: "Jose E. Marchesi" +Date: Tue, 28 Jan 2020 12:13:42 +0100 +Subject: utils: make utilitis to work with temporary files in a different + filesystem + +2020-01-28 Jose E. Marchesi + + * bootstrap.conf (gnulib_modules): Import the modules copy-file + and remove. + * utils/recutl.c (recutl_write_db_to_file): Copy and remove + instead of rename temporary files. +--- + utils/recutl.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +(limited to 'utils/recutl.c') + +diff --git a/utils/recutl.c b/utils/recutl.c +index 9cf823d..a814fd8 100644 +--- a/utils/recutl.c ++++ b/utils/recutl.c +@@ -58,6 +58,7 @@ + #include + #include + #include "read-file.h" ++#include "copy-file.h" + + /* + * Global variables. +@@ -432,12 +433,13 @@ recutl_write_db_to_file (rec_db_t db, + + if (file_name) + { +- /* Rename the temporary file to file_name. */ +- if (rename (tmp_file_name, file_name) == -1) +- { +- remove (tmp_file_name); +- recutl_fatal (_("renaming file %s to %s\n"), tmp_file_name, file_name); +- } ++ /* Rename the temporary file to file_name. We copy and remove ++ instead of renaming because the later doesn't work across ++ different mount points, and it is getting common for /tmp to ++ be mounted in its own filesystem. */ ++ if (qcopy_file_preserving (tmp_file_name, file_name) != 0) ++ recutl_fatal (_("renaming file %s to %s\n"), tmp_file_name, file_name); ++ remove (tmp_file_name); + + /* Restore the attributes of the original file. */ + if (stat_result != -1) +-- +cgit v1.2.1 + diff --git a/srcpkgs/recutils/template b/srcpkgs/recutils/template index 3e71312c4e25..76e6da4c5848 100644 --- a/srcpkgs/recutils/template +++ b/srcpkgs/recutils/template @@ -1,17 +1,25 @@ # Template file for 'recutils' pkgname=recutils version=1.8 -revision=1 +revision=2 build_style=gnu-configure configure_args="--with-bash-headers --disable-rpath" -hostmakedepends="pkg-config" +# TODO remove automake in 1.9; only needed for copy-file +hostmakedepends="automake pkg-config" makedepends="acl-devel libgcrypt-devel libuuid-devel libcurl-devel" +pre_configure() { + # XXX horrible kludge to avoid help2man - remove in 1.9 + touch man/*.1 + # XXX ONLY needed for copy-file - remove in 1.9 + aclocal && automake +} short_desc="Utilities to deal with recfiles" maintainer="Orphaned " license="GPL-3.0-or-later" homepage="https://www.gnu.org/software/recutils/" distfiles="${GNU_SITE}/recutils/recutils-${version}.tar.gz" checksum=df8eae69593fdba53e264cbf4b2307dfb82120c09b6fab23e2dad51a89a5b193 +patch_args=-Np1 librec1_package() { short_desc+=" - rec1 library"