Skip to content

Commit

Permalink
System [Linux]: Support clonefile() on Linux.
Browse files Browse the repository at this point in the history
  • Loading branch information
grubba committed Dec 6, 2024
1 parent 86f3758 commit 9ac9e4f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/modules/system/configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ AC_CHECK_HEADERS(syslog.h sys/syslog.h sys/types.h errno.h unistd.h pwd.h \
sys/systeminfo.h windows.h sys/param.h utime.h sys/utime.h sys/id.h \
sys/time.h sys/shm.h sys/mman.h fcntl.h sys/fcntl.h netinfo/ni.h \
sys/prctl.h cygwin/ipc.h cygwin/sem.h cygwin/shm.h ws2tcpip.h \
NewAPIs.h sys/loadavg.h sys/clonefile.h)
NewAPIs.h sys/loadavg.h sys/clonefile.h linux/fs.h sys/ioctl.h)

# some Linux systems have a broken resource.h that compiles anyway /Mirar
AC_MSG_CHECKING([for working sys/resource.h])
Expand Down Expand Up @@ -98,7 +98,7 @@ AC_HAVE_FUNCS(syslog link symlink readlink resolvepath realpath chown lchown \
getrlimit setrlimit setproctitle \
setitimer getitimer mmap munmap \
gettimeofday settimeofday prctl inet_ntoa inet_ntop getaddrinfo \
getloadavg daemon clonefile)
getloadavg daemon clonefile copy_file_range)

if test "x$ac_cv_func_setpgrp" = "xyes"; then
AC_MSG_CHECKING([if setpgrp takes two arguments (BSD)])
Expand Down
56 changes: 52 additions & 4 deletions src/modules/system/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "pike_rusage.h"
#include "pike_netlib.h"
#include "pike_cpulib.h"
#include "fdlib.h"

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
Expand Down Expand Up @@ -119,8 +120,15 @@
#include <sys/clonefile.h>
#endif

#include "dmalloc.h"
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h>
#endif

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#include "dmalloc.h"

#define sp Pike_sp

Expand Down Expand Up @@ -437,16 +445,56 @@ void f_resolvepath(INT32 args)
}
#endif /* HAVE_RESOLVEPATH || HAVE_REALPATH */

#if !defined(HAVE_CLONEFILE) && defined(HAVE_COPY_FILE_RANGE)
int clonefile(const char *from, const char *to, int flags)
{
int ret = -1;
int fromfd = -1;
int tofd = -1;
struct stat stat;

if (flags) {
/* No flags are supported currently. */
errno = EINVAL;
return -1;
}

fromfd = fd_open(from, fd_RDONLY, 0);
if (fromfd < 0) return -1;

if (fd_fstat(fromfd, &stat) < 0) goto cleanup;

if ((stat.st_mode & S_IFMT) != S_IFREG) {
errno = EINVAL;
goto cleanup;
}

tofd = fd_open(to, fd_CREAT|fd_TRUNC|fd_RDWR, stat.st_mode);
if (tofd < 0) goto cleanup;

ret = copy_file_range(fromfd, NULL, tofd, NULL, stat.st_size, 0);

cleanup:
if (tofd >= 0) close(tofd);

if (fromfd >= 0) close(fromfd);

return ret;
}

#define HAVE_CLONEFILE
#endif

#ifdef HAVE_CLONEFILE
/*! @decl void clonefile(string from, string to)
*!
*! Copy a file @[from] with copy-on-write semantics to the destination named
*! @[to].
*!
*! @note
*! This function is currently only available on macOS, and then only when
*! @[from] and @[to] reference a common file system with copy-on-write
*! support (e.g. an APFS volume).
*! This function is currently only available on macOS and Linux, and then
*! only when @[from] and @[to] reference a common file system with
*! copy-on-write support (e.g. an APFS volume).
*!
*! @seealso
*! @[hardlink()], @[symlink()]
Expand Down

0 comments on commit 9ac9e4f

Please sign in to comment.