.\"
.\" Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
.\"
-.Dd April 27, 2006
+.Dd July 22, 2019
.Dt COPYFILE 3
.Os
.Sh NAME
.It Dv COPYFILE_PACK
Serialize the
.Va from
-file. The
+file.
+The
.Va to
file is an AppleDouble-format file.
.It Dv COPYFILE_UNPACK
Unserialize the
.Va from
-file. The
+file.
+The
.Va from
file is an AppleDouble-format file; the
.Va to
.Fn copyfile
function.) No error is returned if
.Xr remove 3
-fails. Note that
+fails.
+Note that
.Xr remove 3
removes a symbolic link itself, not the
target of the link.
file before starting. (This is only applicable for the
.Fn copyfile
function.)
+.It Dv COPYFILE_CLONE_FORCE
+Clone the file instead.
+This is a force flag i.e. if cloning fails, an error is returned.
+This flag is equivalent to (COPYFILE_EXCL | COPYFILE_ACL | COPYFILE_STAT | COPYFILE_XATTR | COPYFILE_DATA
+| COPYFILE_NOFOLLOW_SRC).
+Note that if cloning is successful, progress callbacks will not be invoked.
+Note also that there is no support for cloning directories: if a directory is provided as the source,
+an error will be returned.
+Since this flag implies COPYFILE_NOFOLLOW_SRC, symbolic links themselves will be cloned instead of their targets.
+(This is only applicable for the
+.Fn copyfile
+function.)
+.It Dv COPYFILE_CLONE
+Try to clone the file instead.
+This is a best try flag i.e. if cloning fails, fallback to copying the file.
+This flag is equivalent to (COPYFILE_EXCL | COPYFILE_ACL | COPYFILE_STAT | COPYFILE_XATTR | COPYFILE_DATA
+| COPYFILE_NOFOLLOW_SRC).
+Note that if cloning is successful, progress callbacks will not be invoked.
+Note also that there is no support for cloning directories: if a directory is provided as the source and
+COPYFILE_CLONE_FORCE is not passed, this will instead copy the directory.
+Since this flag implies COPYFILE_NOFOLLOW_SRC, symbolic links themselves will be cloned instead of their targets.
+Recursive copying however is supported, see below for more information.
+(This is only applicable for the
+.Fn copyfile
+function.)
+.It Dv COPYFILE_DATA_SPARSE
+Copy a file sparsely.
+This requires that the source and destination file systems support sparse files with hole sizes
+at least as large as their block sizes.
+This also requires that the source file is sparse, and for
+.Fn fcopyfile
+the source file descriptor's offset be a multiple of the minimum hole size.
+If COPYFILE_DATA is also specified, this will fall back to a full copy
+if sparse copying cannot be performed for any reason; otherwise, an error is returned.
.It Dv COPYFILE_NOFOLLOW
This is a convenience macro, equivalent to
-.Dv (COPYFILE_NOFOLLOW_DST|COPYFILE_NOFOLLOW_SRC) .
+.Dv (COPYFILE_NOFOLLOW_DST | COPYFILE_NOFOLLOW_SRC) .
+.It Dv COPYFILE_RUN_IN_PLACE
+If the src file has quarantine information, add the QTN_FLAG_DO_NOT_TRANSLOCATE flag to the quarantine information of the dst file.
+This allows a bundle to run in place instead of being translocated.
+.It Dv COPYFILE_PRESERVE_DST_TRACKED
+Preserve the UF_TRACKED flag at
+.Va to
+when copying metadata, regardless of whether
+.Va from
+has it set.
+This flag is used in conjunction with COPYFILE_STAT, or COPYFILE_CLONE (for its fallback case).
.El
.Pp
+Copying files into a directory is supported.
+If
+.Va to
+is a directory,
+.Va from
+will be copied into
+.Va to
+(if
+.Va from
+is a directory,
+copying its contents requires use of the COPYFILE_RECURSIVE parameter,
+which is documented below).
+.Pp
The
.Fn copyfile_state_get
and
.It Dv COPYFILE_STATE_SRC_FILENAME
.It Dv COPYFILE_STATE_DST_FILENAME
Get or set the filename associated with the source (or destination)
-file. If it has not been initialized yet, the value will be
+file.
+If it has not been initialized yet, the value will be
.Dv NULL .
For
.Fn copyfile_state_set ,
(Only valid for
.Fn copyfile_state_get ;
see below for more details about callbacks.)
+If a
+.Dv COPYFILE_CLONE
+or
+.Dv COPYFILE_CLONE_FORCE
+operation successfully cloned the requested objects, then this value will be 0.
The
.Va dst
parameter is a pointer to
(see below for details). This field cannot be set,
and may be
.Dv NULL .
+.It Dv COPYFILE_STATE_WAS_CLONED
+True if a
+.Dv COPYFILE_CLONE
+or
+.Dv COPYFILE_CLONE_FORCE
+operation successfully cloned the requested objects.
+The
+.Va dst
+parameter is a pointer to
+.Vt bool
+(type
+.Vt bool\ * ).
.El
.Sh Recursive Copies
When given the
within the directory have been copied yet.)
.It Dv COPYFILE_RECURSE_DIR_CLEANUP
The object being copied is a directory, and all of the
-objects contained have been copied. At this stage, the destination directory
+objects contained have been copied.
+At this stage, the destination directory
being copied will have any extra permissions that were added to
allow the copying will be removed.
.It Dv COPYFILE_RECURSE_ERROR
the stage of the copy, and will be one of the following values:
.Bl -tag -width COPYFILE_FINISH
.It Dv COPYFILE_START
-Before copying has begun. The third
-parameter will be a newly-created
+Before copying has begun.
+The third parameter will be a newly-created
.Vt copyfile_state_t
object with the call-back function and context pre-loaded.
.It Dv COPYFILE_FINISH
After copying has successfully finished.
.It Dv COPYFILE_ERR
-Indicates an error has happened at some stage. If the
-first argument to the call-back function is
+Indicates an error has happened at some stage.
+If the first argument to the call-back function is
.Dv COPYFILE_RECURSE_ERROR ,
then an error occurred while processing the source hierarchy;
otherwise, it will indicate what type of object was being copied,
The copy will continue as expected.
.It Dv COPYFILE_SKIP
This object will be skipped, and the next object will
-be processed. (Note that, when entering a directory.
-returning
+be processed.
+(Note that, when entering a directory, returning
.Dv COPYFILE_SKIP
from the call-back function will prevent the contents
of the directory from being copied.)
.It Dv COPYFILE_QUIT
-The entire copy is aborted at this stage. Any filesystem
+The entire copy is aborted at this stage.
+Any filesystem
objects created up to this point will remain.
.Fn copyfile
will return -1, but
.Dv errno
value will be set appropriately.
.Pp
+Note that recursive cloning is also supported with the
+.Dv COPYFILE_CLONE
+flag (but not the
+.Dv COPYFILE_CLONE_FORCE
+flag).
+A recursive clone operation invokes
+.Fn copyfile
+with
+.Dv COPYFILE_CLONE
+on every entry found in the source file-system object.
+Because
+.Fn copyfile
+does not allow the cloning of directories, a recursive clone will
+instead copy any directory it finds (while cloning its contents).
+As symbolic links may point to directories, they are not followed
+during recursive clones even if the source is a symbolic link.
+Additionally, because the
+.Dv COPYFILE_CLONE
+flag implies the
+.Dv COPYFILE_EXCL
+flag, recursive clones require a nonexistent destination.
+.Pp
The
.Dv COPYFILE_PACK ,
.Dv COPYFILE_UNPACK ,
.Dv COPYFILE_UNLINK
flags are not used during a recursive copy, and will result
in an error being returned.
+.Pp
+Note that if the source path ends in a
+.Va /
+its contents are copied rather than the directory itself (like cp(1)).
+The behavior of a recursive copy on a directory hierarchy also depends
+on the contents of the destination.
+If the destination is a directory, the source directory (or its contents,
+if the source path ends in a
+.Va /
+) will be copied into it.
+If the destination exists but is not a
+directory, and the source is a non-empty directory, the copy will fail;
+the exact error set depends on the flags provided to
+.Fn copyfile
+initially.
.Sh Progress Callback
In addition to the recursive callbacks described above,
.Fn copyfile
.Fn fcopyfile
will also use a callback to report data (e.g.,
.Dv COPYFILE_DATA )
-progress. If given, the callback will be invoked on each
+progress.
+If given, the callback will be invoked on each
.Xr write 2
-call. The first argument to the callback function will be
+call.
+The first argument to the callback function will be
.Dv COPYFILE_COPY_DATA .
The second argument will either be
.Dv COPYFILE_PROGRESS
may be called for all of the extended attributes, before
the first callback with
.Dv COPYFILE_PROGRESS
-is invoked.) Any attribute skipped by returning
+is invoked.)
+Any attribute skipped by returning
.Dv COPYFILE_SKIP
from the
.Dv COPYFILE_START
.Dv NULL
in the case of
.Fn fcopyfile .
+.Pp
+Note that progress callbacks are not invoked when a clone is requested
+(e.g.
+.Dv COPYFILE_CLONE )
+unless the clone cannot be performed and a copy is performed instead.
.Sh RETURN VALUES
Except when given the
.Dv COPYFILE_CHECK
does not reset the seek position for either source or destination.
This can result in the destination file being a different size
than the source file.
+.Sh EXAMPLES
+.Bd -literal -offset indent
+/* Initialize a state variable */
+copyfile_state_t s;
+s = copyfile_state_alloc();
+/* Copy the data and extended attributes of one file to another */
+copyfile("/tmp/f1", "/tmp/f2", s, COPYFILE_DATA | COPYFILE_XATTR);
+/* Convert a file to an AppleDouble file for serialization */
+copyfile("/tmp/f2", "/tmp/tmpfile", NULL, COPYFILE_ALL | COPYFILE_PACK);
+/* Release the state variable */
+copyfile_state_free(s);
+/* A more complex way to call copyfile() */
+s = copyfile_state_alloc();
+copyfile_state_set(s, COPYFILE_STATE_SRC_FILENAME, "/tmp/foo");
+/* One of src or dst must be set... rest can come from the state */
+copyfile(NULL, "/tmp/bar", s, COPYFILE_ALL);
+/* Now copy the same source file to another destination file */
+copyfile(NULL, "/tmp/car", s, COPYFILE_ALL);
+copyfile_state_free(s);
+/* Remove extended attributes from a file */
+copyfile("/dev/null", "/tmp/bar", NULL, COPYFILE_XATTR);
+.Ed
.Sh ERRORS
.Fn copyfile
and
or
.Va to
parameter to
-.Fn copyfile
+.Fn fcopyfile
was a negative number.
.It Bq Er ENOMEM
A memory allocation failed.
.It Bq Er ENOTSUP
The source file was not a directory, symbolic link, or regular file.
+.It Bq Er ENOTSUP
+COPYFILE_CLONE_FORCE was specified and file cloning is not supported.
+.It Bq Er ENOTSUP
+COPYFILE_DATA_SPARSE was specified, sparse copying is not supported,
+and COPYFILE_DATA was not specified.
.It Bq Er ECANCELED
The copy was cancelled by callback.
+.It Bq Er EEXIST
+The
+.Va to
+parameter to
+.Fn copyfile
+already existed and was passed in with
+.Dv COPYFILE_EXCL .
+.It Bq Er ENOENT
+The
+.Va from
+parameter to
+.Fn copyfile
+did not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix for
+the
+.Va from
+or
+.Va to
+parameters.
+.It Bq Er EACCES
+Write permission is denied for a component of the path prefix for the
+.Va to
+parameter.
.El
+.Pp
In addition, both functions may set
.Dv errno
via an underlying library or system call.
-.Sh EXAMPLES
-.Bd -literal -offset indent
-/* Initialize a state variable */
-copyfile_state_t s;
-s = copyfile_state_alloc();
-/* Copy the data and extended attributes of one file to another */
-copyfile("/tmp/f1", "/tmp/f2", s, COPYFILE_DATA | COPYFILE_XATTR);
-/* Convert a file to an AppleDouble file for serialization */
-copyfile("/tmp/f2", "/tmp/tmpfile", NULL, COPYFILE_ALL | COPYFILE_PACK);
-/* Release the state variable */
-copyfile_state_free(s);
-/* A more complex way to call copyfile() */
-s = copyfile_state_alloc();
-copyfile_state_set(s, COPYFILE_STATE_SRC_FILENAME, "/tmp/foo");
-/* One of src or dst must be set... rest can come from the state */
-copyfile(NULL, "/tmp/bar", s, COPYFILE_ALL);
-/* Now copy the same source file to another destination file */
-copyfile(NULL, "/tmp/car", s, COPYFILE_ALL);
-copyfile_state_free(s);
-/* Remove extended attributes from a file */
-copyfile("/dev/null", "/tmp/bar", NULL, COPYFILE_XATTR);
-.Ed
.Sh SEE ALSO
-.Xr listxattr 2 ,
.Xr getxattr 2 ,
+.Xr listxattr 2 ,
.Xr setxattr 2 ,
.Xr acl 3
+.Sh HISTORY
+The
+.Fn copyfile
+API was introduced in Mac OS X 10.5.
.Sh BUGS
Both
.Fn copyfile
functions lack a way to set the input or output block size.
.Pp
Recursive copies do not honor hard links.
-.Sh HISTORY
-The
-.Fn copyfile
-API was introduced in Mac OS X 10.5.