COPYFILE(3)
π copyfile(3) π
(Library Functions Manual)
β¨ NAME β¨
copyfile, fcopyfile, copyfile_state_alloc, copyfile_state_free, copyfile_state_get, copyfile_state_set β copy a file
π LIBRARY π
Standard C Library (libc, -lc)
π SYNOPSIS π
#include <copyfile.h>
int
copyfile(const char *from, const char *to, copyfile_state_t state,
copyfile_flags_t flags);
int
fcopyfile(int from, int to, copyfile_state_t state,
copyfile_flags_t flags);
copyfile_state_t
copyfile_state_alloc(void);
int
copyfile_state_free(copyfile_state_t state);
int
copyfile_state_get(copyfile_state_t state, uint32_t flag, void * dst);
int
copyfile_state_set(copyfile_state_t state, uint32_t flag,
const void * src);
typedef int
(*copyfile_callback_t)(int what, int stage, copyfile_state_t state,
const char * src, const char * dst, void * ctx);
π¦ DESCRIPTION π¦
Okay so these functions are the whole βcopy a fileβs data and/or metadataβ situation. And yes, metadata means permissions, extended attributes, access control lists, and so forth β the fileβs whole little aura, not just the bytes. π
The copyfile_state_alloc() function initializes a copyfile_state_t object (which is an opaque data type). This object can be passed to copyfile() and fcopyfile(); copyfile_state_get() and copyfile_state_set() can be used to manipulate the state (see below). The copyfile_state_free() function is used to deallocate the object and its contents. Cleanup queen behavior, no cap. π§Ήβ¨
The copyfile() function can copy the named from file to the named to file; the fcopyfile() function does the same, but using the file descriptors of already-opened files. If the state parameter is the return value from copyfile_state_alloc(), then copyfile() and fcopyfile() will use the information from the state object; if it is NULL, then both functions will work normally, but less control will be available to the caller. The flags parameter controls which contents are copied:
COPYFILE_ACLβ Copy the source fileβs access control lists.COPYFILE_STATβ Copy the source fileβs POSIX information (mode, modification time, etc.). Note thatsetuidandsetgidbits are by default not copied from source files or to destination files that reside on volumes that are mounted with theMNT_NOSUIDmount(2)flag, but this can be overridden through the use ofCOPYFILE_STATE_PRESERVE_SUIDin thecopyfile_state_tobject.COPYFILE_XATTRβ Copy the source fileβs extended attributes.COPYFILE_DATAβ Copy the source fileβs data.
These values may be orβd together; several convenience macros are provided:
COPYFILE_SECURITYβ Copy the source fileβs POSIX and ACL information; equivalent to(COPYFILE_STAT|COPYFILE_ACL).COPYFILE_METADATAβ Copy the metadata; equivalent to(COPYFILE_SECURITY|COPYFILE_XATTR).COPYFILE_ALLβ Copy the entire file; equivalent to(COPYFILE_METADATA|COPYFILE_DATA).
The copyfile() and fcopyfile() functions can also have their behavior modified by the following flags:
COPYFILE_RECURSIVEβ Causescopyfile()to recursively copy a hierarchy. This flag is not used byfcopyfile(); see below for more information.COPYFILE_CHECKβ Return a bitmask (corresponding to theflagsargument) indicating which contents would be copied; no data are actually copied. (E.g., ifflagswas set toCOPYFILE_CHECK|COPYFILE_METADATA, and thefromfile had extended attributes but no ACLs, the return value would beCOPYFILE_XATTR.)COPYFILE_PACKβ Serialize thefromfile. Thetofile is an AppleDouble-format file.COPYFILE_UNPACKβ Unserialize thefromfile. Thefromfile is an AppleDouble-format file; thetofile will have the extended attributes, ACLs, resource fork, and FinderInfo data from thetofile, regardless of theflagsargument passed in.COPYFILE_EXCLβ Fail if thetofile already exists. (This is only applicable for thecopyfile()function.)COPYFILE_NOFOLLOW_SRCβ Do not follow thefromfile, if it is a symbolic link. (This is only applicable for thecopyfile()function.)COPYFILE_NOFOLLOW_DSTβ Do not follow thetofile, if it is a symbolic link. (This is only applicable for thecopyfile()function.)COPYFILE_MOVEβ Unlink (usingremove(3)) thefromfile. (This is only applicable for thecopyfile()function.) No error is returned ifremove(3)fails. Note thatremove(3)removes a symbolic link itself, not the target of the link.COPYFILE_UNLINKβ Unlink thetofile before starting. (This is only applicable for thecopyfile()function.)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_STAT | COPYFILE_XATTR | COPYFILE_DATA | COPYFILE_NOFOLLOW_SRC). Note that if cloning is successful, progress callbacks will not be invoked, nor will anysetuidorsetgidbits be copied to the destination. 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 impliesCOPYFILE_NOFOLLOW_SRC, symbolic links themselves will be cloned instead of their targets. (This is only applicable for thecopyfile()function.) Finally, note that ACLs will not be cloned unlessCOPYFILE_ACLis also passed.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_STAT | COPYFILE_XATTR | COPYFILE_DATA | COPYFILE_NOFOLLOW_SRC). Note that if cloning is successful, progress callbacks will not be invoked, nor will anysetuidorsetgidbits be copied to the destination. Note also that there is no support for cloning directories: if a directory is provided as the source andCOPYFILE_CLONE_FORCEis not passed, this will instead copy the directory. Since this flag impliesCOPYFILE_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 thecopyfile()function.) Finally, note that ACLs will not be cloned unlessCOPYFILE_ACLis also passed.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 forfcopyfile()the source file descriptorβs offset be a multiple of the minimum hole size. IfCOPYFILE_DATAis also specified, this will fall back to a full copy if sparse copying cannot be performed for any reason; otherwise, an error is returned.COPYFILE_NOFOLLOWβ This is a convenience macro, equivalent to(COPYFILE_NOFOLLOW_DST | COPYFILE_NOFOLLOW_SRC).COPYFILE_RUN_IN_PLACEβ If thesrcfile has quarantine information, add theQTN_FLAG_DO_NOT_TRANSLOCATEflag to the quarantine information of thedstfile. This allows a bundle to run in place instead of being translocated.COPYFILE_PRESERVE_DST_TRACKEDβ Preserve theUF_TRACKEDflag attowhen copying metadata, regardless of whetherfromhas it set. This flag is used in conjunction withCOPYFILE_STAT, orCOPYFILE_CLONE(for its fallback case).
fcopyfile() function can also have its behavior modified by the following flags:
COPYFILE_NOCACHEβ turn caching off for bothfromandtoarguments. This is a best effort attempt, and if succeeded the file descriptors would keep the no-caching policy when returning fromfcopyfile().
Copying files into a directory is supported. If to is a directory, from will be copied into to (if from is a directory, copying its contents requires use of the COPYFILE_RECURSIVE parameter, which is documented below).
The copyfile_state_get() and copyfile_state_set() functions can be used to manipulate the copyfile_state_t object returned by copyfile_state_alloc(). In both functions, the dst parameterβs type depends on the flag parameter that is passed in.
COPYFILE_STATE_SRC_FDβ Get or set the file descriptor associated with the source file. If this has not been initialized yet, the value will be-2. Thedst(forcopyfile_state_get()) andsrc(forcopyfile_state_set()) parameters are pointers toint.COPYFILE_STATE_DST_FDβ Get or set the file descriptor associated with the destination file. If this has not been initialized yet, the value will be-2. Thedst(forcopyfile_state_get()) andsrc(forcopyfile_state_set()) parameters are pointers toint.COPYFILE_STATE_SRC_FILENAMECOPYFILE_STATE_DST_FILENAMEβ okay so this one gets or sets the filename tied to the source (or destination) file, and if it hasnβt been initialized yet the value isNULLπ. Forcopyfile_state_set(), thesrcparameter is a pointer to a C string (i.e.,char *);copyfile_state_set()makes a private copy of this string. For thecopyfile_state_get()function, thedstparameter is a pointer to a pointer to a C string (i.e.,char **); the returned value is a pointer to the state's copy, and must not be modified or released π«.COPYFILE_STATE_STATUS_CBβ get or set the callback status function (currently only used for recursive copies; see below for details) π. Thesrcparameter and thedstparameter are pointers to a function of typecopyfile_callback_t(see above).COPYFILE_STATE_STATUS_CTXβ get or set the context parameter for the status call-back function (see below for details) π«Ά. Thesrcparameter and thedstparameter are opaque pointers (typevoid *).COPYFILE_STATE_QUARANTINEβ get or set the quarantine information with the source file π¦. Thesrcparameter is a pointer to an opaque object (typevoid *).COPYFILE_STATE_COPIEDβ get the number of data bytes copied so far π. (Only valid forcopyfile_state_get(); see below for more details about callbacks.) If aCOPYFILE_CLONEorCOPYFILE_CLONE_FORCEoperation successfully cloned the requested objects, then this value will be0. Thedstparameter is a pointer tooff_t(typeoff_t *).COPYFILE_STATE_XATTRNAMEβ get the name of the extended attribute during a callback forCOPYFILE_COPY_XATTR(see below for details) π·οΈ. This field cannot be set, and may beNULL.COPYFILE_STATE_WAS_CLONEDβ true if aCOPYFILE_CLONEorCOPYFILE_CLONE_FORCEoperation successfully cloned the requested objects π. Thedstparameter is a pointer tobool(typebool *).COPYFILE_STATE_SRC_BSIZE,COPYFILE_STATE_DST_BSIZE,COPYFILE_STATE_BSIZEβ get or set the copy blocksize associated with the source or destination file (or both) π§±. The caller must ensure that its environment does not restrict a memory allocation of this size. If the copy blocksize for the destination file is specified to be larger than the copy blocksize for the source file, it will be ignored. If this has not been initialized by the caller, the value will be0. Thedstparameter and thesrcparameter are pointers touint32_t(typeuint32_t *).COPYFILE_STATE_FORBID_CROSS_MOUNTβ get or set the current setting for crossing mount points during aCOPYFILE_RECURSIVEoperation π. By default, recursive copying descends into directories that have a different device number than the directory from which the descent began. Thedstparameter and thesrcparameter are pointers tobool(typebool *).COPYFILE_STATE_NOCPROTECTβ get or set the current setting for copying content-protection classes from the source to the destination file π‘οΈ. Thedstparameter and thesrcparameter are pointers touint32_t(typeuint32_t *).COPYFILE_STATE_PRESERVE_SUIDβ get or set the current setting for preserving the setuid and setgid bits on the destination file during a copy π . (See the descriptions above forCOPYFILE_STATandCOPYFILE_CLONEfor details.) Thedstparameter and thesrcparameter are pointers touint32_t(typeuint32_t *).COPYFILE_STATE_RECURSIVE_SRC_FTSENTβ get any available file entry information during a recursive copy πΈ. If none is available, the value will beNULL. (Only valid forcopyfile_state_get().) Thedstparameter is a pointer to a pointer to aconst FTSENT(typeconst FTSENT **); the returned value is the state's copy, and must not be modified or released π«.COPYFILE_STATE_FORBID_DST_EXISTING_SYMLINKSβ get or set the current setting for forbidding copying over existing symlinks π₯. By default, copying over an existing destination is allowed regardless of the type of file that already exists at the destination path. Thedstparameter and thesrcparameter are pointers touint32_t(typeuint32_t *).
π Recursive Copies π
okay so when you pass the COPYFILE_RECURSIVE flag, copyfile() β and not fcopyfile() β will use the fts(3) functions to recursively descend into the source file-system object. It then calls copyfile() on each of the entries it finds that way. If a call-back function is given (using copyfile_state_set() and COPYFILE_STATE_STATUS_CB), the call-back function will be called four times for each directory object, and twice for all other objects. (Each directory will be examined twice, once on entry -- before copying each of the objects contained in the directory -- and once on exit -- after copying each object contained in the directory, in order to perform some final cleanup.) π§
The call-back function will have one of the following values as the first argument, indicating what is being copied:
COPYFILE_RECURSE_FILEβ The object being copied is a file (or, rather, something other than a directory).COPYFILE_RECURSE_DIRβ The object being copied is a directory, and is being entered. (That is, none of the filesystem objects contained within the directory have been copied yet.) WhenCOPYFILE_STATE_FORBID_CROSS_MOUNTis set, the call-back function will be skipped for any encountered mount points.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 being copied will have any extra permissions that were added to allow the copying will be removed (by a finalCOPYFILE_STAToperation - note that this occurs even if theCOPYFILE_STATflag was not passed to the recursive copy).COPYFILE_RECURSE_ERRORβ There was an error in processing an element of the source hierarchy; this happens whenfts(3)returns an error or unknown file type. (Currently, the second argument to the call-back function will always beCOPYFILE_ERRin this case.)
The second argument to the call-back function will indicate the stage of the copy, and will be one of the following values:
COPYFILE_STARTβ Before copying has begun. The third parameter will be a newly-createdcopyfile_state_tobject with the call-back function and context pre-loaded.COPYFILE_FINISHβ After copying has successfully finished.COPYFILE_ERRβ Indicates an error has happened at some stage. If the first argument to the call-back function isCOPYFILE_RECURSE_ERROR, then an error occurred while processing the source hierarchy; otherwise, it will indicate what type of object was being copied, anderrnowill be set to indicate the error.
The fourth and fifth parameters are the source and destination paths that are to be copied (or have been copied, or failed to copy, depending on the second argument).
The last argument to the call-back function will be the value set by COPYFILE_STATE_STATUS_CTX, if any.
The call-back function is required to return one of the following values:
COPYFILE_CONTINUEβ The copy will continue as expected.COPYFILE_SKIPβ This object will be skipped, and the next object will be processed. (Note that, when entering a directory, returningCOPYFILE_SKIPfrom the call-back function will prevent the contents of the directory from being copied.)COPYFILE_QUITβ The entire copy is aborted at this stage. Any filesystem objects created up to this point will remain.copyfile()will return-1, buterrnowill be unmodified.
The call-back function must always return one of the values listed above; if not, the results are undefined. π
The call-back function will be called twice for each object (and an additional two times for directory cleanup); the first call will have a stage parameter of COPYFILE_START; the second time, that value will be either COPYFILE_FINISH or COPYFILE_ERR to indicate a successful completion, or an error during processing. In the event of an error, the errno value will be set appropriately.
Note that recursive cloning is also supported with the COPYFILE_CLONE flag (but not the COPYFILE_CLONE_FORCE flag). A recursive clone operation invokes copyfile() with COPYFILE_CLONE on every entry found in the source file-system object. Because 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 COPYFILE_CLONE flag implies the COPYFILE_EXCL flag, recursive clones require a nonexistent destination.
The COPYFILE_PACK, COPYFILE_UNPACK, COPYFILE_MOVE, and COPYFILE_UNLINK flags are not used during a recursive copy, and will result in an error being returned.
Note that if the source path ends in a / 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 /) 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 copyfile() initially.
π« Progress Callback π«
In addition to the recursive callbacks described above, copyfile() and fcopyfile() will also use a callback to report data (e.g., COPYFILE_DATA) progress. If given, the callback will be invoked on each write(2) call. The first argument to the callback function will be COPYFILE_COPY_DATA. The second argument will either be COPYFILE_PROGRESS (indicating that the write was successful), or COPYFILE_ERR (indicating that there was an error of some sort).
The amount of data bytes copied so far can be retrieved using copyfile_state_get(), with the COPYFILE_STATE_COPIED requestor (the argument type is a pointer to off_t).
When copying extended attributes, the first argument to the callback function will be COPYFILE_COPY_XATTR. The other arguments will be as described for COPYFILE_COPY_DATA; the name of the extended attribute being copied may be retrieved using copyfile_state_get() and the parameter COPYFILE_STATE_XATTRNAME. When using COPYFILE_PACK, the callback may be called with COPYFILE_START for each of the extended attributes first, followed by COPYFILE_PROGRESS before getting and packing the data for each individual attribute, and then COPYFILE_FINISH when finished with each individual attribute. (That is, COPYFILE_START may be called for all of the extended attributes, before the first callback with COPYFILE_PROGRESS is invoked.) Any attribute skipped by returning COPYFILE_SKIP from the COPYFILE_START callback will not be placed into the packed output file.
The return value for the data callback must be one of
COPYFILE_CONTINUEβ The copy will continue as expected. (In the case of error, it will attempt to write the data again.)COPYFILE_SKIPβ The data copy will be aborted, but without error.COPYFILE_QUITβ The data copy will be aborted; in the case ofCOPYFILE_PROGRESS,errnowill be set toECANCELED.
While the src and dst parameters will be passed in, they may be NULL in the case of fcopyfile().
Note that progress callbacks are not invoked when a clone is requested (e.g. COPYFILE_CLONE) unless the clone cannot be performed and a copy is performed instead. π¦
π RETURN VALUES π
Except when given the COPYFILE_CHECK flag, copyfile() and fcopyfile() return less than 0 on error, and 0 on success. All of the other functions return 0 on success, and less than 0 on error. π
β οΈ WARNING β οΈ
When performing a recursive copy, if the source hierarchy changes while the copy is occurring, the results are undefined; however, an effort is made to detect this and return an error to the caller instead of proceeding.
fcopyfile() 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. π
Bothcopyfile()andfcopyfile()will temporarily mark an unwritable destination writable for the duration of the copy. After the copy is performed (except when theCOPYFILE_STATflag is passed in), an attempt is made to revert the destination's permissions to their starting state.
πΈ EXAMPLES πΈ
/* 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);
π ERRORS π
okay bestie, when the universe says βnope,β copyfile() and fcopyfile() will fail if:
[EINVAL]β an invalid flag was passed in withCOPYFILE_RECURSIVE.[EINVAL]β thefromortoparameter tocopyfile()was aNULLpointer.[EINVAL]β thefromortoparameter tofcopyfile()was a negative number.[ENOMEM]β a memory allocation failed.[ENOTSUP]β the source file was not a directory, symbolic link, or regular file.[ENOTSUP]βCOPYFILE_CLONE_FORCEwas specified and file cloning is not supported.[ENOTSUP]βCOPYFILE_DATA_SPARSEwas specified, sparse copying is not supported, andCOPYFILE_DATAwas not specified.[ECANCELED]β the copy was cancelled by callback.[EEXIST]β thetoparameter tocopyfile()already existed and was passed in withCOPYFILE_EXCL.[ENOENT]β thefromparameter tocopyfile()did not exist.[EACCES]β search permission is denied for a component of the path prefix for thefromortoparameters.[EACCES]β write permission is denied for a component of the path prefix for thetoparameter.[EBADF]βCOPYFILE_RECURSIVEwas specified and a change in the source hierarchy was detected.
in addition, both functions may set errno via an underlying library or system call. so yeah, errno can still be messy even after the fancy flag check π
π SEE ALSO π
go touch grass with the related crew:
π°οΈ HISTORY π°οΈ
the copyfile() API was introduced in Mac OS X 10.5. vintage behavior, still doing its thing β¨
π BUGS π
π bug alert: recursive copies do not honor hard links. no cap, thatβs the whole note.
okay bye bestie π β this is the Debian COPYFILE(3) page, dated March 29, 2024. go forth and copy responsibly πβ¨
π¦ where this page comes from
- nixpkgs unstable: copyfile 240
- Copyright (c) 2024 Apple Computer, Inc. All rights reserved
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms