Use clonefile(2) in more places

A lot of file copies that we create are not subsequently modified,
especially in the destroot phase. This makes cloning a more efficient
alternative.

* Modified xinstall and 'file copy' Tcl commands to try cloning.
* Created a vendored copy of install(1) that tries cloning.
* Created a thin wrapper around cp(1) that adds the -c flag.
* If the build directory is on a filesystem that supports cloning, the
  configure.install option defaults to our install(1), and the
  directory containing our install and cp commands is added to the
  front of PATH, currently only during the destroot phase.

The code for all of the above is not built on systems that lack
clonefile(2). If cloning fails, everything will fall back to creating
a copy as previously done.
This commit is contained in:
Joshua Root
2024-08-28 00:24:25 +10:00
parent 8d945d0549
commit 3da9cd2a0d
21 changed files with 1910 additions and 31 deletions
+2 -1
View File
@@ -32,7 +32,7 @@ src/darwintracelib1.0/sip_copy_proc.[ch]
src/machista1.0/tests/libmachista-test
src/port/*
!src/port/*.tcl
src/programs/daemondo/build/
src/programs/*/build/
src/**/*.o
src/**/*.a
src/**/*.dylib
@@ -44,6 +44,7 @@ tests/test/trace/test.tcl
vendor/vendor-destroot/
vendor/tclsh
vendor/install/build/
vendor/**/*.o
vendor/**/*.a
vendor/**/*.dylib
+1
View File
@@ -37,6 +37,7 @@ XCODEBUILD = @XCODEBUILD@
INTREE_TCLSH = @INTREE_TCLSH@
TCLSH = @TCLSH@
TCL_PACKAGE_PATH = @TCL_PACKAGE_PATH@
TCL_PREFIX = @TCL_PREFIX@
DSCL = @DSCL@
DSEDITGROUP = @DSEDITGROUP@
Vendored
+21 -3
View File
@@ -672,6 +672,7 @@ VENDOR_TCLX_SUBDIR
VENDOR_DESTROOT
VENDOR_TCL_INSTALL
VENDOR_TCL_SUBDIR
CLONEBIN_PATH
localstatedir_expanded
MPCONFIGDIR_EXPANDED
DARWINTRACE_SIP_WORKAROUND_PATH
@@ -689,6 +690,8 @@ HAVE_STRLCPY
HAVE_STRLCAT
HAVE_GETLINE
HAVE_GETDELIM
EXTRA_PROGS
HAVE_CLONEFILE
HAVE_TIMINGSAFE_BCMP
HAVE_GETENTROPY
HAVE_ARC4RANDOM_BUF
@@ -704,7 +707,6 @@ RUNUSR
DSTGRP
DSTUSR
MPCONFIGDIR
EXTRA_PROGS
HAVE_FUNCTION_CFNOTIFICATIONCENTERGETDARWINNOTIFYCENTER
HAVE_FRAMEWORK_IOKIT
HAVE_FRAMEWORK_SYSTEMCONFIGURATION
@@ -7012,8 +7014,6 @@ printf %s "checking for whether we will build daemondo... " >&6; }
printf "%s\n" "${result}" >&6; }
# Check for paths
@@ -7729,6 +7729,17 @@ HAVE_GETENTROPY=$ac_cv_func_getentropy
HAVE_TIMINGSAFE_BCMP=$ac_cv_func_timingsafe_bcmp
# For vendor/install
HAVE_CLONEFILE=$ac_cv_func_clonefile
# For programs/cp
if test x$ac_cv_func_clonefile = xyes; then
EXTRA_PROGS="$EXTRA_PROGS cp"
ac_config_files="$ac_config_files src/programs/cp/Makefile vendor/install/Makefile"
fi
# Check for library functions, replacements are in pextlib1.0/compat/
ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline"
if test "x$ac_cv_func_getline" = xyes
@@ -8660,6 +8671,11 @@ eval "macports_libexec_dir=$macports_libexec_dir"
prefix=$oldprefix
exec_prefix=$oldexec_prefix
if test x$ac_cv_func_clonefile = xyes; then
CLONEBIN_PATH="${macports_libexec_dir}/clonebin"
fi
## Tcl package
mp_fn_var_prepend() {
eval "$1=\"$2\$$1\""
@@ -10448,6 +10464,8 @@ do
case $ac_config_target in
"src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;;
"src/programs/daemondo/Makefile") CONFIG_FILES="$CONFIG_FILES src/programs/daemondo/Makefile" ;;
"src/programs/cp/Makefile") CONFIG_FILES="$CONFIG_FILES src/programs/cp/Makefile" ;;
"vendor/install/Makefile") CONFIG_FILES="$CONFIG_FILES vendor/install/Makefile" ;;
"Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"Mk/macports.autoconf.mk") CONFIG_FILES="$CONFIG_FILES Mk/macports.autoconf.mk" ;;
+14 -2
View File
@@ -201,8 +201,6 @@ MP_COMPILER_ATTRIBUTE_UNUSED
MP_PROG_DAEMONDO
AC_SUBST(EXTRA_PROGS)
# Check for paths
AC_PREFIX_DEFAULT(/opt/local)
AC_ARG_WITH(
@@ -269,6 +267,15 @@ AC_SUBST(HAVE_ARC4RANDOM_BUF, $ac_cv_func_arc4random_buf)
AC_SUBST(HAVE_GETENTROPY, $ac_cv_func_getentropy)
AC_SUBST(HAVE_TIMINGSAFE_BCMP, $ac_cv_func_timingsafe_bcmp)
# For vendor/install
AC_SUBST(HAVE_CLONEFILE, $ac_cv_func_clonefile)
# For programs/cp
if test x$ac_cv_func_clonefile = xyes; then
EXTRA_PROGS="$EXTRA_PROGS cp"
AC_CONFIG_FILES([src/programs/cp/Makefile vendor/install/Makefile])
fi
AC_SUBST(EXTRA_PROGS)
# Check for library functions, replacements are in pextlib1.0/compat/
AC_CHECK_FUNCS([getline getdelim strlcat strlcpy])
AC_SUBST(HAVE_GETDELIM, $ac_cv_func_getdelim)
@@ -347,6 +354,11 @@ eval "macports_libexec_dir=$macports_libexec_dir"
prefix=$oldprefix
exec_prefix=$oldexec_prefix
if test x$ac_cv_func_clonefile = xyes; then
CLONEBIN_PATH="${macports_libexec_dir}/clonebin"
fi
AC_SUBST(CLONEBIN_PATH)
## Tcl package
MP_CONFIG_SUBDIR([vendor/tcl/unix], [--prefix=${macports_libexec_dir} --enable-threads])
VENDOR_TCL_SUBDIR=tcl/unix
+24 -1
View File
@@ -49,7 +49,7 @@ package require mpcommon 1.0
namespace eval macports {
variable bootstrap_options [dict create]
# Config file options with no special handling
foreach opt [list binpath auto_path extra_env portdbformat \
foreach opt [list binpath auto_path clonebin_path extra_env portdbformat \
portarchivetype portimage_mode hfscompression portautoclean \
porttrace portverbose keeplogs destroot_umask release_urls release_version_urls \
rsync_server rsync_options rsync_dir \
@@ -87,6 +87,9 @@ namespace eval macports {
macosx_deployment_target packagemaker_path default_compilers sandbox_enable sandbox_network \
delete_la_files cxx_stdlib pkg_post_unarchive_deletions {*}$user_options]
# Options set in the portfile interpreter but only in system_options
variable portinterp_private_options [list clonebin_path]
# deferred options are only computed when needed.
# they are not exported to the trace thread.
# they are not exported to the interpreter in system_options array.
@@ -985,6 +988,7 @@ proc mportinit {{up_ui_options {}} {up_options {}} {up_variations {}}} {
macports::portarchive_hfscompression \
macports::host_cache \
macports::porturl_prefix_map \
macports::clonebin_path \
macports::ui_options \
macports::global_options \
macports::global_variations
@@ -1486,6 +1490,15 @@ match macports.conf.default."
set env(PATH) $binpath
}
if {![info exists clonebin_path]} {
if {![catch {fs_clone_capable [file join $portdbpath build]} result] && $result
&& [file executable ${macports::autoconf::clonebin_path}/install]} {
set clonebin_path ${macports::autoconf::clonebin_path}
} else {
set clonebin_path {}
}
}
# Set startupitem default type (can be overridden by portfile)
if {![info exists startupitem_type]} {
set startupitem_type default
@@ -1896,6 +1909,7 @@ proc macports::copy_xcode_plist {target_homedir} {
proc macports::worker_init {workername portpath porturl portbuildpath options variations} {
variable portinterp_options; variable portinterp_deferred_options
variable portinterp_private_options
variable ui_priorities; variable ui_options
# Hide any Tcl commands that should be inaccessible to port1.0 and Portfiles
@@ -2044,6 +2058,15 @@ proc macports::worker_init {workername portpath porturl portbuildpath options va
$workername eval [list set $opt ?]
}
foreach opt $portinterp_private_options {
if {![info exists $opt]} {
variable $opt
}
if {[info exists $opt]} {
$workername eval [list set system_options($opt) [set $opt]]
}
}
foreach {opt val} $options {
$workername eval [list set user_options($opt) $val]
$workername eval [list set $opt $val]
+1
View File
@@ -35,6 +35,7 @@ namespace eval macports::autoconf {
variable aa_path "@AA@"
variable bzip2_path "@BZIP2_BIN@"
variable chown_path "@CHOWN@"
variable clonebin_path "@CLONEBIN_PATH@"
variable gzip_path "@GZIP_BIN@"
variable macports_conf_path "@MPCONFIGDIR_EXPANDED@"
variable macports_keys_base "@prefix_expanded@/share/macports/keys/base"
+74 -9
View File
@@ -47,6 +47,14 @@
#include <sys/cdefs.h>
#endif
/* For clonefile */
#ifdef HAVE_SYS_ATTR_H
#include <sys/attr.h>
#endif
#ifdef HAVE_SYS_CLONEFILE_H
#include <sys/clonefile.h>
#endif
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/mount.h>
@@ -131,6 +139,9 @@ static char *funcname;
static int safecopy, docompare, dostrip, dobackup, dopreserve, nommap;
static mode_t mode;
#ifdef HAVE_CLONEFILE
static int clone(const char *, const char *, int, char *, size_t);
#endif
static int copy(Tcl_Interp *interp, int, const char *, int, const char *, off_t);
static int compare(int, const char *, size_t, int, const char *, size_t);
static int create_newfile(Tcl_Interp *interp, const char *, int, struct stat *);
@@ -139,6 +150,7 @@ static int install(Tcl_Interp *interp, const char *, const char *, u_long, u_int
static int install_dir(Tcl_Interp *interp, char *);
static u_long numeric_id(Tcl_Interp *interp, const char *, const char *, int *rval);
static void strip(const char *);
static void tempfile_template(const char *, char *, size_t);
static int trymmap(int);
static void usage(Tcl_Interp *interp);
@@ -432,9 +444,14 @@ install(Tcl_Interp *interp, const char *from_name, const char *to_name, u_long f
{
struct stat from_sb, temp_sb, to_sb;
struct timeval tvb[2];
int devnull, files_match, from_fd = 0, serrno, target;
int tempcopy, temp_fd, to_fd = 0;
int devnull, files_match, from_fd = -1, serrno, target;
int tempcopy, temp_fd = -1, to_fd = -1;
char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
#ifdef HAVE_CLONEFILE
const int tryclone = 1;
#else
const int tryclone = 0;
#endif
files_match = 0;
@@ -484,7 +501,7 @@ install(Tcl_Interp *interp, const char *from_name, const char *to_name, u_long f
/* Only copy safe if the target exists. */
tempcopy = safecopy && target;
if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) {
if ((!tryclone || dostrip || docompare) && !devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) {
char errmsg[255];
snprintf(errmsg, sizeof errmsg, "%s: Unable to open: %s, %s",
@@ -517,6 +534,26 @@ install(Tcl_Interp *interp, const char *from_name, const char *to_name, u_long f
}
if (!files_match) {
int done_clone = 0;
#ifdef HAVE_CLONEFILE
if (tryclone && !devnull && !dostrip) {
done_clone = (clone(from_name, to_name, tempcopy, tempfile, sizeof(tempfile)) == 0);
}
if (done_clone &&
(((to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY, 0)) < 0)
|| (!tempcopy && fstat(to_fd, &to_sb) == -1))) {
(void)unlink(tempcopy ? tempfile : to_name);
done_clone = 0;
}
if (!done_clone && from_fd < 0 && (from_fd = open(from_name, O_RDONLY, 0)) < 0) {
char errmsg[255];
snprintf(errmsg, sizeof errmsg, "%s: Unable to open: %s, %s",
funcname, from_name, strerror(errno));
Tcl_SetResult(interp, errmsg, TCL_VOLATILE);
return TCL_ERROR;
}
#endif
if (!done_clone) {
if (tempcopy) {
to_fd = create_tempfile(to_name, tempfile,
sizeof(tempfile));
@@ -539,8 +576,9 @@ install(Tcl_Interp *interp, const char *from_name, const char *to_name, u_long f
}
ui_info(interp, "%s: %s -> %s", funcname, from_name, to_name);
}
} /* !done_clone */
if (!devnull) {
if (copy(interp, from_fd, from_name, to_fd,
if (!done_clone && copy(interp, from_fd, from_name, to_fd,
tempcopy ? tempfile : to_name, from_sb.st_size) != TCL_OK)
return TCL_ERROR;
#if HAVE_COPYFILE
@@ -838,12 +876,11 @@ compare(int from_fd, const char *from_name UNUSED, size_t from_len,
return rv;
}
/*
* create_tempfile --
* create a temporary file based on path and open it
/* tempfile_template --
* prepare a template filename for use with mktemp/mkstemp.
*/
static int
create_tempfile(const char *path, char *temp, size_t tsize)
static void
tempfile_template(const char *path, char *temp, size_t tsize)
{
char *p;
@@ -855,6 +892,16 @@ create_tempfile(const char *path, char *temp, size_t tsize)
p = temp;
(void)strncpy(p, "INS@XXXX", &temp[tsize - 1] - p);
temp[tsize - 1] = '\0';
}
/*
* create_tempfile --
* create a temporary file based on path and open it
*/
static int
create_tempfile(const char *path, char *temp, size_t tsize)
{
tempfile_template(path, temp, tsize);
return (mkstemp(temp));
}
@@ -993,6 +1040,24 @@ copy(Tcl_Interp *interp, int from_fd, const char *from_name, int to_fd, const ch
return TCL_OK;
}
/*
* clone --
* create a clone of a file
*/
#ifdef HAVE_CLONEFILE
static int
clone(const char *from_name, const char *to_name,
int use_temp, char *temp_name, size_t tsize)
{
if (use_temp) {
tempfile_template(to_name, temp_name, tsize);
mktemp(temp_name);
to_name = temp_name;
}
return clonefile(from_name, to_name, CLONE_NOFOLLOW|CLONE_NOOWNERCOPY);
}
#endif
/*
* strip --
* use strip(1) to strip the target file
+1 -1
View File
@@ -291,7 +291,7 @@ options configure.perl configure.python configure.ruby \
default configure.perl {}
default configure.python {}
default configure.ruby {}
default configure.install {${portutil::autoconf::install_command}}
default configure.install {[expr {$system_options(clonebin_path) ne "" ? [file join $system_options(clonebin_path) install] : ${portutil::autoconf::install_command}}]}
default configure.awk {}
default configure.bison {}
default configure.pkg_config {}
+13 -1
View File
@@ -126,7 +126,19 @@ proc portdestroot::destroot_start {args} {
}
proc portdestroot::destroot_main {args} {
command_exec -callback portprogress::target_progress_callback destroot
global system_options
if {$system_options(clonebin_path) ne ""} {
global env
set saved_path $env(PATH)
set env(PATH) $system_options(clonebin_path):$env(PATH)
}
try {
command_exec -callback portprogress::target_progress_callback destroot
} finally {
if {[info exists saved_path]} {
set env(PATH) $saved_path
}
}
return 0
}
+36
View File
@@ -0,0 +1,36 @@
srcdir = @srcdir@
VPATH = @srcdir@
include ../../../Mk/macports.autoconf.mk
SRCS = cp.c
OBJS = cp.o
PROGRAM = build/cp
.PHONY: cp mkdirs
all: cp
cp: mkdirs ${PROGRAM}
${PROGRAM}: ${OBJS}
${CC} ${CFLAGS} -o ${PROGRAM} ${LIBS} ${OBJS}
mkdirs:
mkdir -p build
clean:
rm -Rf build ${PROGRAM} ${OBJS}
distclean: clean
rm -f Makefile
install: cp
${INSTALL} -d -m 755 "${DESTDIR}${TCL_PREFIX}/clonebin"
${INSTALL} -o "${DSTUSR}" -g "${DSTGRP}" -m 555 "${PROGRAM}" "${DESTDIR}${TCL_PREFIX}/clonebin"
test:
codesign:: ${PROGRAM}
../../codesign.sh $?
+26
View File
@@ -0,0 +1,26 @@
/* cp wrapper to add -c (clone) option */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/errno.h>
extern char **environ;
int main(int argc, char *argv[])
{
const char *cp_path = "/bin/cp";
const char *clone_arg = "-c";
const char **new_argv = malloc(sizeof(char *) * (argc+1));
if (new_argv) {
new_argv[0] = cp_path;
new_argv[1] = clone_arg;
for (int i = 1; i < argc; i++) {
new_argv[i+1] = argv[i];
}
execve(cp_path, new_argv, environ);
}
/* something failed */
perror("cp");
return errno;
}
+2
View File
@@ -17,6 +17,8 @@ LIBS = -framework CoreFoundation \
-framework IOKit
PROGRAM = build/daemondo
.PHONY: daemondo mkdirs
all: daemondo
daemondo: mkdirs ${PROGRAM}
Generated Vendored
+28 -9
View File
@@ -2,14 +2,15 @@ TCL_SUBDIR= @VENDOR_TCL_SUBDIR@
TCLX_SUBDIR= @VENDOR_TCLX_SUBDIR@
TCLLIB_SUBDIR= @VENDOR_TCLLIB_SUBDIR@
SIGNIFY_SUBDIR= signify-osx
INSTALL_SUBDIR= install
PREFIX= @prefix@
DESTROOT= @abs_top_builddir@/vendor/vendor-destroot
.PHONY: all clean distclean install destroot test
.PHONY: destroot-tcl destroot-tclx destroot-tcllib destroot-signify
.PHONY: install-tcl install-tclx install-tcllib install-signify
.PHONY: %-tcl %-tclx %-tcllib %-signify
.PHONY: destroot-tcl destroot-tclx destroot-tcllib destroot-signify destroot-install
.PHONY: install-tcl install-tclx install-tcllib install-signify install-install
.PHONY: %-tcl %-tclx %-tcllib %-signify %-install
# for make all, run destroot (where destroot will depend on all of each
# subpackage)
@@ -37,33 +38,47 @@ all-tcllib: all-tcl
@echo ===\> making $(@:%-signify=%) in ${DIRPRFX}${SIGNIFY_SUBDIR}
@umask 0022; $(MAKE) -C ${SIGNIFY_SUBDIR} $(@:%-signify=%)
%-install:
@echo ===\> making $(@:%-install=%) in ${DIRPRFX}${INSTALL_SUBDIR}
@umask 0022; $(MAKE) -C ${INSTALL_SUBDIR} $(@:%-install=%)
DESTROOT_TARGETS= destroot-tcl destroot-tclx destroot-tcllib
ifneq (@OS_PLATFORM@,linux)
DESTROOT_TARGETS+= destroot-signify
endif
ifeq (@HAVE_CLONEFILE@,yes)
DESTROOT_TARGETS+= destroot-install
endif
destroot: $(DESTROOT_TARGETS)
destroot-tcl: all-tcl
@echo ===\> staging to destroot in ${DIRPRFX}@VENDOR_TCL_SUBDIR@
@umask 0022; $(MAKE) -C @VENDOR_TCL_SUBDIR@ DESTDIR=${DESTROOT} @VENDOR_TCL_INSTALL@
@umask 0022; $(MAKE) -C @VENDOR_TCL_SUBDIR@ "DESTDIR=${DESTROOT}" @VENDOR_TCL_INSTALL@
destroot-tclx: all-tclx
@echo ===\> staging to destroot in ${DIRPRFX}@VENDOR_TCLX_SUBDIR@
@umask 0022; $(MAKE) -C @VENDOR_TCLX_SUBDIR@ DESTDIR=${DESTROOT} @VENDOR_TCLX_INSTALL@
@umask 0022; $(MAKE) -C @VENDOR_TCLX_SUBDIR@ "DESTDIR=${DESTROOT}" @VENDOR_TCLX_INSTALL@
destroot-tcllib: all-tcllib
@echo ===\> staging to destroot in ${DIRPRFX}@VENDOR_TCLLIB_SUBDIR@
@umask 0022; $(MAKE) -C @VENDOR_TCLLIB_SUBDIR@ DESTDIR=${DESTROOT} TCLSH_PROG=@INTREE_TCLSH@ @VENDOR_TCLLIB_INSTALL@
@umask 0022; $(MAKE) -C @VENDOR_TCLLIB_SUBDIR@ "DESTDIR=${DESTROOT}" TCLSH_PROG=@INTREE_TCLSH@ @VENDOR_TCLLIB_INSTALL@
@chmod -R ugo+rX ${DESTROOT}${PREFIX}/libexec/macports/lib/tcllib*
destroot-signify:
@echo ===\> staging to destroot in ${DIRPRFX}${SIGNIFY_SUBDIR}
@umask 0022; $(MAKE) -C ${SIGNIFY_SUBDIR} install PREFIX=${DESTROOT}${PREFIX}/libexec/macports
@umask 0022; $(MAKE) -C ${SIGNIFY_SUBDIR} install "PREFIX=${DESTROOT}${PREFIX}/libexec/macports"
destroot-install:
@echo ===\> staging to destroot in ${DIRPRFX}${INSTALL_SUBDIR}
@umask 0022; $(MAKE) -C ${INSTALL_SUBDIR} install "DESTDIR=${DESTROOT}"
INSTALL_TARGETS= install-tcl install-tclx install-tcllib
ifneq (@OS_PLATFORM@,linux)
INSTALL_TARGETS+= install-signify
endif
ifeq (@HAVE_CLONEFILE@,yes)
INSTALL_TARGETS+= install-install
endif
install: $(INSTALL_TARGETS)
@@ -106,12 +121,16 @@ install-signify:
@echo ===\> making $(@:%-signify=%) in ${DIRPRFX}${SIGNIFY_SUBDIR}
@umask 0022; $(MAKE) -C ${SIGNIFY_SUBDIR} install PREFIX=$(DESTDIR)${PREFIX}/libexec/macports
install-install:
@echo ===\> making $(@:%-install=%) in ${DIRPRFX}${INSTALL_SUBDIR}
@umask 0022; $(MAKE) -C ${INSTALL_SUBDIR} install
test:
clean: clean-tcl clean-tcllib clean-tclx clean-signify
clean: clean-tcl clean-tcllib clean-tclx clean-signify clean-install
rm -rf ${DESTROOT}
distclean: distclean-tcl distclean-tcllib distclean-tclx distclean-signify
distclean: distclean-tcl distclean-tcllib distclean-tclx distclean-signify distclean-install
rm -f Makefile
rm -rf vendor-destroot
rm -f tclsh
+38
View File
@@ -0,0 +1,38 @@
srcdir = @srcdir@
VPATH = @srcdir@
include ../../Mk/macports.autoconf.mk
SRCS = xinstall.c
OBJS = xinstall.o
PROGRAM = build/install
.PHONY: xinstall mkdirs
all: xinstall
xinstall: mkdirs ${PROGRAM}
${PROGRAM}: ${OBJS}
${CC} ${CFLAGS} -o ${PROGRAM} ${LIBS} ${OBJS}
mkdirs:
mkdir -p build
clean:
rm -Rf build ${PROGRAM} ${OBJS}
distclean: clean
rm -f Makefile
install: xinstall
${INSTALL} -d -m 755 "${DESTDIR}${TCL_PREFIX}/clonebin"
${INSTALL} -m 555 "${PROGRAM}" "${DESTDIR}${TCL_PREFIX}/clonebin"
test: xinstall
if which -s kyua > /dev/null ; then \
cd tests && env "PATH=../build:$$PATH" kyua test ; \
fi
codesign:: ${PROGRAM}
../../codesign.sh $?
+3
View File
@@ -0,0 +1,3 @@
syntax(2)
test_suite('install')
atf_test_program{name='install_test.sh'}
+448
View File
@@ -0,0 +1,448 @@
#! /usr/bin/env atf-sh
#
# Copyright (c) 2016 Jilles Tjoelker
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
copy_to_nonexistent_with_opts() {
printf 'test\n123\r456\r\n789\0z' >testf
atf_check install "$@" testf copyf
cmp testf copyf || atf_fail "bad copy"
[ ! testf -nt copyf ] || atf_fail "bad timestamp"
[ ! -e copyf.bak ] || atf_fail "no backup expected"
}
atf_test_case copy_to_nonexistent
copy_to_nonexistent_body() {
copy_to_nonexistent_with_opts
}
atf_test_case copy_to_nonexistent_safe
copy_to_nonexistent_safe_body() {
copy_to_nonexistent_with_opts -S
}
atf_test_case copy_to_nonexistent_comparing
copy_to_nonexistent_comparing_body() {
copy_to_nonexistent_with_opts -C
}
atf_test_case copy_to_nonexistent_safe_comparing
copy_to_nonexistent_safe_comparing_body() {
copy_to_nonexistent_with_opts -S -C
}
atf_test_case copy_to_nonexistent_backup
copy_to_nonexistent_backup_body() {
copy_to_nonexistent_with_opts -b -B.bak
}
atf_test_case copy_to_nonexistent_backup_safe
copy_to_nonexistent_backup_safe_body() {
copy_to_nonexistent_with_opts -b -B.bak -S
}
atf_test_case copy_to_nonexistent_preserving
copy_to_nonexistent_preserving_body() {
copy_to_nonexistent_with_opts -p
[ ! testf -ot copyf ] || atf_fail "bad timestamp 2"
}
copy_self_with_opts() {
printf 'test\n123\r456\r\n789\0z' >testf
printf 'test\n123\r456\r\n789\0z' >testf2
atf_check -s not-exit:0 -o empty -e match:. install "$@" testf testf
cmp testf testf2 || atf_fail "file changed after self-copy attempt"
}
atf_test_case copy_self
copy_self_body() {
copy_self_with_opts
}
atf_test_case copy_self_safe
copy_self_safe_body() {
copy_self_with_opts -S
}
atf_test_case copy_self_comparing
copy_self_comparing_body() {
copy_self_with_opts -C
}
atf_test_case copy_self_safe_comparing
copy_self_safe_comparing_body() {
copy_self_with_opts -S -C
}
overwrite_with_opts() {
printf 'test\n123\r456\r\n789\0z' >testf
printf 'test\n123\r456\r\n789\0w' >otherf
atf_check install "$@" testf otherf
cmp testf otherf || atf_fail "bad overwrite"
[ ! testf -nt otherf ] || atf_fail "bad timestamp"
}
atf_test_case overwrite
overwrite_body() {
overwrite_with_opts
}
atf_test_case overwrite_safe
overwrite_safe_body() {
overwrite_with_opts -S
}
atf_test_case overwrite_comparing
overwrite_comparing_body() {
overwrite_with_opts -C
}
atf_test_case overwrite_safe_comparing
overwrite_safe_comparing_body() {
overwrite_with_opts -S -C
}
overwrite_eq_with_opts() {
printf 'test\n123\r456\r\n789\0z' >testf
printf 'test\n123\r456\r\n789\0z' >otherf
atf_check install "$@" testf otherf
cmp testf otherf || atf_fail "bad overwrite"
[ ! testf -nt otherf ] || atf_fail "bad timestamp"
}
atf_test_case overwrite_eq
overwrite_eq_body() {
overwrite_eq_with_opts
}
atf_test_case overwrite_eq_safe
overwrite_eq_safe_body() {
overwrite_eq_with_opts -S
}
atf_test_case overwrite_eq_comparing
overwrite_eq_comparing_body() {
overwrite_eq_with_opts -C
}
atf_test_case overwrite_eq_safe_comparing
overwrite_eq_safe_comparing_body() {
overwrite_eq_with_opts -S -C
}
overwrite_backup_with_opts() {
printf 'test\n123\r456\r\n789\0z' >testf
printf 'test\n123\r456\r\n789\0w' >otherf
printf 'test\n123\r456\r\n789\0w' >otherf2
atf_check install -b -B.bak "$@" testf otherf
cmp testf otherf || atf_fail "bad overwrite"
[ ! testf -nt otherf ] || atf_fail "bad timestamp"
cmp otherf.bak otherf2 || atf_fail "bad backup"
}
atf_test_case overwrite_backup
overwrite_backup_body() {
overwrite_backup_with_opts
}
atf_test_case overwrite_backup_safe
overwrite_backup_safe_body() {
overwrite_backup_with_opts -S
}
atf_test_case overwrite_backup_comparing
overwrite_backup_comparing_body() {
overwrite_backup_with_opts -C
}
atf_test_case overwrite_backup_safe_comparing
overwrite_backup_safe_comparing_body() {
overwrite_backup_with_opts -S -C
}
setup_stripbin() {
cat <<\STRIPBIN >stripbin
#!/bin/sh
[ "$1" = "-o" ] && dst="$2" && shift 2
[ "$1" = "--" ] && shift
[ -z "$dst" ] && dst="$1"
STRIPBIN
[ "$1" = "true" ] && cmd="cat" || cmd="tr z @"
echo $cmd '<"$1" >"$1.new" && mv -- "$1.new" "$dst"' >>stripbin
chmod 755 stripbin
export STRIPBIN="$PWD/stripbin"
}
strip_changing_with_opts() {
setup_stripbin
printf 'test\n123\r456\r\n789\0z' >testf
atf_check install -s "$@" testf copyf
[ ! testf -nt copyf ] || atf_fail "bad timestamp"
printf 'test\n123\r456\r\n789\0@' >otherf
cmp otherf copyf || atf_fail "bad stripped copy"
}
# atf_test_case strip_changing
# strip_changing_body() {
# strip_changing_with_opts
# }
#
# atf_test_case strip_changing_comparing
# strip_changing_comparing_body() {
# strip_changing_with_opts -C
# }
strip_changing_overwrite_with_opts() {
setup_stripbin
printf 'test\n123\r456\r\n789\0z' >testf
printf 'test\n123\r456\r\n789\0w' >copyf
atf_check install -s "$@" testf copyf
[ ! testf -nt copyf ] || atf_fail "bad timestamp"
printf 'test\n123\r456\r\n789\0@' >otherf
cmp otherf copyf || atf_fail "bad stripped copy"
}
# atf_test_case strip_changing_overwrite
# strip_changing_overwrite_body() {
# strip_changing_overwrite_with_opts
# }
#
# atf_test_case strip_changing_overwrite_comparing
# strip_changing_overwrite_comparing_body() {
# strip_changing_overwrite_with_opts -C
# }
strip_changing_overwrite_eq_with_opts() {
setup_stripbin
printf 'test\n123\r456\r\n789\0z' >testf
printf 'test\n123\r456\r\n789\0@' >copyf
atf_check install -s "$@" testf copyf
[ ! testf -nt copyf ] || atf_fail "bad timestamp"
printf 'test\n123\r456\r\n789\0@' >otherf
cmp otherf copyf || atf_fail "bad stripped copy"
}
# atf_test_case strip_changing_overwrite_eq
# strip_changing_overwrite_eq_body() {
# strip_changing_overwrite_eq_with_opts
# }
#
# atf_test_case strip_changing_overwrite_eq_comparing
# strip_changing_overwrite_eq_comparing_body() {
# strip_changing_overwrite_eq_with_opts -C
# }
# atf_test_case strip_noop
# strip_noop_body() {
# setup_stripbin true
# printf 'test\n123\r456\r\n789\0z' >testf
# atf_check install -s testf copyf
# [ ! testf -nt copyf ] || atf_fail "bad timestamp"
# printf 'test\n123\r456\r\n789\0z' >otherf
# cmp otherf copyf || atf_fail "bad stripped copy"
# }
#atf_test_case hard_link
#hard_link_body() {
# printf 'test\n123\r456\r\n789\0z' >testf
# atf_check install -l h testf copyf
# [ testf -ef copyf ] || atf_fail "not same file"
# [ ! -L copyf ] || atf_fail "copy is symlink"
#}
#atf_test_case symbolic_link
#symbolic_link_body() {
# printf 'test\n123\r456\r\n789\0z' >testf
# atf_check install -l s testf copyf
# [ testf -ef copyf ] || atf_fail "not same file"
# [ -L copyf ] || atf_fail "copy is not symlink"
#}
#atf_test_case symbolic_link_absolute
#symbolic_link_absolute_body() {
# printf 'test\n123\r456\r\n789\0z' >testf
# atf_check install -l sa testf copyf
# [ testf -ef copyf ] || atf_fail "not same file"
# [ -L copyf ] || atf_fail "copy is not symlink"
# copyf_path=$(readlink copyf)
# testf_path="$(pwd -P)/testf"
# if [ "$copyf_path" != "$testf_path" ]; then
# atf_fail "unexpected symlink contents ('$copyf_path' != '$testf_path')"
# fi
#}
#atf_test_case symbolic_link_relative
#symbolic_link_relative_body() {
# printf 'test\n123\r456\r\n789\0z' >testf
# atf_check install -l sr testf copyf
# [ testf -ef copyf ] || atf_fail "not same file"
# [ -L copyf ] || atf_fail "copy is not symlink"
# copyf_path=$(readlink copyf)
# testf_path="testf"
# if [ "$copyf_path" != "$testf_path" ]; then
# atf_fail "unexpected symlink contents ('$copyf_path' != '$testf_path')"
# fi
#}
# atf_test_case symbolic_link_relative_absolute_source_and_dest1
# symbolic_link_relative_absolute_source_and_dest1_head() {
# atf_set "descr" "Verify -l rs with absolute paths (.../copyf -> .../a/b/c/testf)"
# }
# symbolic_link_relative_absolute_source_and_dest1_body() {
# src_path=a/b/c/testf
# src_path_prefixed=$PWD/$src_path
# dest_path=$PWD/copyf
#
# atf_check mkdir -p a/b/c
# atf_check touch $src_path
# atf_check install -l sr $src_path_prefixed $dest_path
# [ $src_path_prefixed -ef $dest_path ] || atf_fail "not same file"
# [ -L $dest_path ] || atf_fail "copy is not symlink"
# dest_path_relative=$(readlink $dest_path)
# src_path_relative="$src_path"
# if [ "$src_path_relative" != "$dest_path_relative" ]; then
# atf_fail "unexpected symlink contents ('$src_path_relative' != '$dest_path_relative')"
# fi
# }
# atf_test_case symbolic_link_relative_absolute_source_and_dest1_double_slash
# symbolic_link_relative_absolute_source_and_dest1_double_slash_head() {
# atf_set "descr" "Verify -l rs with absolute paths (.../copyf -> .../a/b/c/testf), using double-slashes"
# }
# symbolic_link_relative_absolute_source_and_dest1_double_slash_body() {
# src_path=a//b//c//testf
# src_path_prefixed=$PWD/$src_path
# dest_path=$PWD/copyf
#
# atf_check mkdir -p a/b/c
# atf_check touch $src_path
# atf_check install -l sr $src_path_prefixed $dest_path
# [ $src_path_prefixed -ef $dest_path ] || atf_fail "not same file"
# [ -L $dest_path ] || atf_fail "copy is not symlink"
# dest_path_relative=$(readlink $dest_path)
# src_path_relative="$(echo $src_path | sed -e 's,//,/,g')"
# if [ "$src_path_relative" != "$dest_path_relative" ]; then
# atf_fail "unexpected symlink contents ('$src_path_relative' != '$dest_path_relative')"
# fi
# }
# atf_test_case symbolic_link_relative_absolute_source_and_dest2
# symbolic_link_relative_absolute_source_and_dest2_head() {
# atf_set "descr" "Verify -l rs with absolute paths (.../a/b/c/copyf -> .../testf)"
# }
# symbolic_link_relative_absolute_source_and_dest2_body() {
# src_path=testf
# src_path_prefixed=$PWD/$src_path
# dest_path=$PWD/a/b/c/copyf
#
# atf_check mkdir -p a/b/c
# atf_check touch $src_path
# atf_check install -l sr $src_path_prefixed $dest_path
# [ $src_path_prefixed -ef $dest_path ] || atf_fail "not same file"
# [ -L $dest_path ] || atf_fail "copy is not symlink"
# dest_path_relative=$(readlink $dest_path)
# src_path_relative="../../../$src_path"
# if [ "$src_path_relative" != "$dest_path_relative" ]; then
# atf_fail "unexpected symlink contents ('$src_path_relative' != '$dest_path_relative')"
# fi
# }
atf_test_case mkdir_simple
mkdir_simple_body() {
atf_check install -d dir1/dir2
[ -d dir1 ] || atf_fail "dir1 missing"
[ -d dir1/dir2 ] || atf_fail "dir2 missing"
atf_check install -d dir1/dir2/dir3
[ -d dir1/dir2/dir3 ] || atf_fail "dir3 missing"
atf_check install -d dir1
atf_check install -d dir1/dir2/dir3
}
# atf_test_case symbolic_link_relative_absolute_common
# symbolic_link_relative_absolute_common_head() {
# atf_set "descr" "Verify -l rs with absolute paths having common components"
# }
# symbolic_link_relative_absolute_common_body() {
# filename=foo.so
# src_path=lib
# src_path_prefixed=$PWD/$src_path
# dest_path=$PWD/libexec/
# src_file=$src_path_prefixed/$filename
# dest_file=$dest_path/$filename
#
# atf_check mkdir $src_path_prefixed $dest_path
# atf_check touch $src_file
# atf_check install -l sr $src_file $dest_path
#
# dest_path_relative=$(readlink $dest_file)
# src_path_relative="../lib/$filename"
# if [ "$src_path_relative" != "$dest_path_relative" ]; then
# atf_fail "unexpected symlink contents ('$src_path_relative' != '$dest_path_relative')"
# fi
# }
atf_init_test_cases() {
atf_add_test_case copy_to_nonexistent
atf_add_test_case copy_to_nonexistent_safe
atf_add_test_case copy_to_nonexistent_comparing
atf_add_test_case copy_to_nonexistent_safe_comparing
atf_add_test_case copy_to_nonexistent_backup
atf_add_test_case copy_to_nonexistent_backup_safe
atf_add_test_case copy_to_nonexistent_preserving
atf_add_test_case copy_self
atf_add_test_case copy_self_safe
atf_add_test_case copy_self_comparing
atf_add_test_case copy_self_safe_comparing
atf_add_test_case overwrite
atf_add_test_case overwrite_safe
atf_add_test_case overwrite_comparing
atf_add_test_case overwrite_safe_comparing
atf_add_test_case overwrite_eq
atf_add_test_case overwrite_eq_safe
atf_add_test_case overwrite_eq_comparing
atf_add_test_case overwrite_eq_safe_comparing
atf_add_test_case overwrite_backup
atf_add_test_case overwrite_backup_safe
atf_add_test_case overwrite_backup_comparing
atf_add_test_case overwrite_backup_safe_comparing
#atf_add_test_case strip_changing
#atf_add_test_case strip_changing_comparing
#atf_add_test_case strip_changing_overwrite
#atf_add_test_case strip_changing_overwrite_comparing
#atf_add_test_case strip_changing_overwrite_eq
#atf_add_test_case strip_changing_overwrite_eq_comparing
#atf_add_test_case strip_noop
#atf_add_test_case hard_link
#atf_add_test_case symbolic_link
#atf_add_test_case symbolic_link_absolute
#atf_add_test_case symbolic_link_relative
#atf_add_test_case symbolic_link_relative_absolute_source_and_dest1
#atf_add_test_case symbolic_link_relative_absolute_source_and_dest1_double_slash
#atf_add_test_case symbolic_link_relative_absolute_source_and_dest2
#atf_add_test_case symbolic_link_relative_absolute_common
atf_add_test_case mkdir_simple
}
+878
View File
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
Applied to original from file_cmds-430.140.2
--- xinstall.c.orig 2024-08-20 16:07:42
+++ xinstall.c 2024-08-27 16:58:56
@@ -70,9 +70,9 @@
#ifdef __APPLE__
#include <TargetConditionals.h>
#include <copyfile.h>
+#include <sys/attr.h>
+#include <sys/clonefile.h>
#endif /* __APPLE__ */
-
-#include "pathnames.h"
/* Bootstrap aid - this doesn't exist in most older releases */
#ifndef MAP_FAILED
@@ -92,6 +92,7 @@
mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
char *suffix = BACKUP_SUFFIX;
+static int clone __P((const char *, const char *, int, char *, size_t));
void copy __P((int, char *, int, char *, off_t));
int compare __P((int, const char *, size_t, int, const char *, size_t));
int create_newfile __P((char *, int, struct stat *));
@@ -100,6 +101,7 @@
void install_dir __P((char *));
u_long numeric_id __P((char *, char *));
void strip __P((char *));
+static void tempfile_template __P((const char *, char *, size_t));
int trymmap __P((int));
void usage __P((void));
@@ -276,9 +278,10 @@
{
struct stat from_sb, temp_sb, to_sb;
struct utimbuf utb;
- int devnull, files_match, from_fd=0, serrno, target;
- int tempcopy, temp_fd, to_fd=0;
+ int devnull, files_match, from_fd=-1, serrno, target;
+ int tempcopy, temp_fd=-1, to_fd=-1;
char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
+ const int tryclone = 1;
files_match = 0;
@@ -334,6 +337,17 @@
}
if (!files_match) {
+ int done_clone = 0;
+ if (tryclone && !devnull && !dostrip) {
+ done_clone = (clone(from_name, to_name, tempcopy, tempfile, sizeof(tempfile)) == 0);
+ }
+ if (done_clone &&
+ (((to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY, 0)) < 0)
+ || (!tempcopy && fstat(to_fd, &to_sb) == -1))) {
+ (void)unlink(tempcopy ? tempfile : to_name);
+ done_clone = 0;
+ }
+ if (!done_clone) {
if (tempcopy) {
to_fd = create_tempfile(to_name, tempfile,
sizeof(tempfile));
@@ -350,6 +364,7 @@
if (!devnull)
copy(from_fd, from_name, to_fd,
tempcopy ? tempfile : to_name, from_sb.st_size);
+ } /* !done_clone */
}
if (dostrip) {
@@ -592,11 +607,11 @@
}
/*
- * create_tempfile --
- * create a temporary file based on path and open it
+ * tempfile_template --
+ * prepare a template filename for use with mktemp/mkstemp.
*/
-int
-create_tempfile(char *path,
+static void
+tempfile_template(const char *path,
char *temp,
size_t tsize)
{
@@ -610,6 +625,18 @@
p = temp;
(void)strncpy(p, "INS@XXXX", &temp[tsize - 1] - p);
temp[tsize - 1] = '\0';
+}
+
+/*
+ * create_tempfile --
+ * create a temporary file based on path and open it
+ */
+int
+create_tempfile(char *path,
+ char *temp,
+ size_t tsize)
+{
+ tempfile_template(path, temp, tsize);
return (mkstemp(temp));
}
@@ -736,6 +763,22 @@
}
/*
+ * clone --
+ * create a clone of a file
+ */
+static int
+clone(const char *from_name, const char *to_name,
+ int use_temp, char *temp_name, size_t tsize)
+{
+ if (use_temp) {
+ tempfile_template(to_name, temp_name, tsize);
+ mktemp(temp_name);
+ to_name = temp_name;
+ }
+ return clonefile(from_name, to_name, CLONE_NOFOLLOW|CLONE_NOOWNERCOPY);
+}
+
+/*
* strip --
* use strip(1) to strip the target file
*/
+112
View File
@@ -0,0 +1,112 @@
diff --git a/vendor/tcl8.6.14/unix/configure b/vendor/tcl8.6.14/unix/configure
index 87dc84d1e..a161fed43 100755
--- a/vendor/tcl8.6.14/unix/configure
+++ b/vendor/tcl8.6.14/unix/configure
@@ -17439,7 +17439,7 @@ fi
done
-for ac_header in copyfile.h
+for ac_header in sys/clonefile.h copyfile.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -17589,7 +17589,7 @@ fi
done
-for ac_func in copyfile
+for ac_func in clonefile copyfile
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5
diff --git a/vendor/tcl8.6.14/unix/tclUnixFCmd.c b/vendor/tcl8.6.14/unix/tclUnixFCmd.c
index 26429df73..82da6d433 100644
--- a/vendor/tcl8.6.14/unix/tclUnixFCmd.c
+++ b/vendor/tcl8.6.14/unix/tclUnixFCmd.c
@@ -51,6 +51,18 @@
#ifdef HAVE_FTS
#include <fts.h>
#endif
+#ifdef HAVE_SYS_CLONEFILE_H
+#include <sys/clonefile.h>
+#endif
+#ifdef HAVE_CLONEFILE
+#if defined(__APPLE__) && \
+ defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED < 101200
+#define MayUseCloneFile() (clonefile != NULL)
+#else
+#define MayUseCloneFile() (1)
+#endif
+#endif /* HAVE_CLONEFILE */
/*
* The following constants specify the type of callback when
@@ -526,14 +538,50 @@ DoCopyFile(
}
return TCL_OK;
}
-
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclUnixCloneFile -
+ *
+ * Helper function for TclUnixCopyFile. Clones one regular file, using
+ * clonefile().
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * A file is cloned.
+ *
+ *----------------------------------------------------------------------
+ */
+#ifdef HAVE_CLONEFILE
+int
+TclUnixCloneFile(
+ const char *src, /* Pathname of file to clone (native). */
+ const char *dst, /* Pathname of file to create (native). */
+ const Tcl_StatBuf *statBufPtr,
+ /* Used to copy attributes. */
+ int dontCopyAtts) /* If flag set, don't copy attributes. */
+{
+ if (clonefile(src, dst, CLONE_NOFOLLOW|CLONE_NOOWNERCOPY) == 0) {
+ if (dontCopyAtts || CopyFileAtts(src, dst, statBufPtr) == TCL_OK) {
+ return TCL_OK;
+ }
+ }
+ unlink(dst); /* INTL: Native. */
+ return TCL_ERROR;
+}
+#endif
+
/*
*----------------------------------------------------------------------
*
* TclUnixCopyFile -
*
* Helper function for TclpCopyFile. Copies one regular file, using
- * read() and write().
+ * read() and write(), or clones it with TclUnixCloneFile() if
+ * supported.
*
* Results:
* A standard Tcl result.
@@ -558,6 +606,13 @@ TclUnixCopyFile(
char *buffer; /* Data buffer for copy */
size_t nread;
+#ifdef HAVE_CLONEFILE
+ if (MayUseCloneFile() &&
+ TclUnixCloneFile(src, dst, statBufPtr, dontCopyAtts) == TCL_OK) {
+ return TCL_OK;
+ }
+#endif
+
#ifdef DJGPP
#define BINMODE |O_BINARY
#else
+2 -2
View File
@@ -17439,7 +17439,7 @@ fi
done
for ac_header in copyfile.h
for ac_header in sys/clonefile.h copyfile.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -17589,7 +17589,7 @@ fi
done
for ac_func in copyfile
for ac_func in clonefile copyfile
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5

Some files were not shown because too many files have changed in this diff Show More