cpfile 子例程

用途

从源文件到目标文件的内容的优化复制操作。

标准 C 库 (libc.a)

语法

#include <unistd.h>

int cpfile(sfd, dfd, offset, nbytesp, flags)
int        sfd;
int        dfd;
off64_t    offset;
size64_t  *nbytesp;
uint64_t   flags;

描述

cpfile 子例程将 nbytes 数据从打开的源文件 (在 sfd 参数中指定的标识) 复制到打开的目标文件 (由 dfd 参数指定的标识)。 cpfile 子例程仅复制常规文件。 cpfile 子例程可以将文件从一个本地文件系统,网络文件系统 (NFS) 或已安装的文件系统复制到其他文件系统。 如果此函数用于任何其他类型的文件或文件系统,那么将返回错误。

offset 参数指定从源文件开始读操作的位置,并开始写入目标文件中的相同 offset 值,除非目标文件以追加方式打开 (通过使用 O_APPEND 标志)。 如果 offset 值为负数或指示超出源文件末尾的位置,那么将返回错误。

nbytesp 自变量是输入和输出自变量。 基本上这个自变量用来传递值也是为了返回一个值。 对于输入操作,地址指向要从指定 offset 值复制的字节数。 如果偏移值非零,那么值 0 将复制整个文件 (或者直到文件结束)。 由于以下原因,复制的字节数可能少于请求的字节数:

  • 空间不足,无法写入目标文件。
  • 内存不足,无法分配临时缓冲区。
  • 达到上限或检测到暂挂信号。

将返回错误值-1并设置全局变量 "errno,以表示复制操作失败。 返回时, nbytesp 值指定在从调用返回的子例程之前成功复制的字节数。

如果 cpfile 子例程被任何信号中断,那么它将从内核空间返回到用户空间以处理该信号。 错误号指向 EINTR 值,而 nbytesp 值指示在 cpfile 子例程中断之前复制的字节数。 如果希望应用程序在处理信号后继续从源文件复制数据字节,请使用新的偏移值和长度再次调用 cpfile 子例程。

注: 如果应用程序重新启动停止的操作,那么可能需要指定 NO_DEST_FSIZE_CHECK 标志,因为在应用程序从第一次调用返回后,目标文件大小可能不为零。

flags 参数用于控制调用 cpfile 子例程的行为。 如果您不想使用该标志,请将值指定为 0 提供的值。 任何其他值都指示有效标志。 可以将多个标志值作为位一起传递。

标志值的受支持选项如下所示:

SPARSE_DEST_FILE
具有所有零字符串的源文件块是通过使用 fclear 操作而不是对目标文件的写操作来设置的。 如果源文件稀疏,那么目标文件在复制操作后也会变得稀疏。
NO_DEST_FSIZE_CHECK
cpfile 子例程不得检查任何目标文件的大小。 如果设置了此标志,那么 cpfile 子例程将覆盖目标文件的内容。

请考虑有关 cpfile 子例程的以下信息:

  • cpfile 子例程用于下列其中一个目的:
    • cpfile 子例程用于创建源文件的相同副本。 目标文件大小必须为零,小于或等于源文件大小。
      注: 如果目标文件大小非零,那么必须打开 NO_DEST_FSIZE_CHECK 标志。 cpfile 子例程不会显式截断目标文件。 因此,在调用之前,应用程序必须将目标文件截断为零,小于或等于源文件大小。 在复制操作完成后,以追加方式打开的非零大小目标文件不会创建源文件的相同副本。
    • cpfile 子例程用于将由 offset 参数指定的偏移值处的目标文件部分替换为同一偏移值处的源文件部分。 因此,目标文件大小可以非零。 在这种情况下,应用程序必须打开 NO_DEST_FSIZE_CHECK 标志。
    • cpfile 子例程用于将源文件的内容与目标文件的内容并置。 在这种情况下,应用程序必须以追加方式 (通过使用 O_APPEND 标志) 打开目标文件,并且必须打开 NO_DEST_FSIZE_CHECK 标志,因为目标文件大小非零。 cpfile 子例程开始将数据从源文件追加到目标文件的末尾。
  • 可以在多线程环境中使用 cpfile 子例程。
  • 当子例程正在复制数据时,对源文件或目标文件执行并行写操作可能会产生意外结果。
  • 如果指定了 SPARSE_DEST_FILE 标志,那么 cpfile 子例程将通过跳过在源文件中包含所有零字符串的块来优化源文件的复制操作,方法是使用 fclear 标志而不是对目标文件执行写操作。
  • cpfile 子例程不会将任何属性,扩展属性和访问控制表 (ACL) 从源文件复制到目标文件。 如果需要,必须手动复制这些属性。
  • 如果系统调用检测到任何暂挂信号,那么 cpfile 子例程将从内核空间返回到用户空间以处理应用程序的信号。 如果应用程序在处理暂挂信号后继续复制操作,那么应用程序必须使用新的偏移值和长度再次调用 cpfile 子例程。 新偏移值指示从何处继续复制操作,新长度指示要从指定偏移量复制的字节数。
    注: 应用程序可能需要为连续调用指定 NO_DEST_FSIZE_CHECK 标志,因为在上次调用 cpfile 子例程之后,目标文件大小可能非零。
  • 缺省情况下, cpfile 子例程期望目标文件大小为零。 如果应用程序想要使用大小非零的目标文件,那么应用程序必须传递 NO_DEST_FSIZE_CHECK 标志以避免失败。 如果应用程序要将源文件与目标文件并置,那么它必须以追加方式 (通过使用O_APPEND 标志) 打开目标文件,并在打开 NO_DEST_FSIZE_CHECK 标志的情况下调用 cpfile 子例程。
    注: 如果应用程序指定了 NO_DEST_FSIZE_CHECK 标志,那么不会检查目标文件大小。 因此,如果目标文件大于源文件,那么目标文件中的数据 (位于与源文件大小相等的偏移量之后) 不会被 cpfile 子例程修改。

参数

斯夫德
指定源文件的文件描述符。
德夫德
指定目标文件的文件描述符。
抵消
指定要从中读取数据的源文件中的位置以及要开始写入数据的目标文件中的位置。
恩比特斯普
指定输入值或输出值。 此参数指定要复制的字节数。 值 0 将复制整个文件。 此参数返回复制的字节数。
标志
指定描述部分中子例程的参数所定义的标志值。

返回值

成功完成后,对 cpfile 子例程的调用将返回 0。 复制到目标文件的字节数不得大于 nbytes 参数指定的值。 否则,返回值为-1,并设置全局变量 "errno表示出错。 在这两种情况下, nbytesp 变量都具有复制到目标文件的字节数的值。

错误代码

当下列一个或多个错误代码为 true 时, cpfile 子例程不成功。 文件系统可以生成除以下列表中指定的错误以外的错误:

EBADF
文件描述符参数无效。
EINTR
操作被信号中断。
EINVAL
偏移量,长度或标志参数无效或 nbytesp 参数为空。 如果目标文件大小非零,并且未设置 NO_DEST_FSIZE_CHECK 标志,那么将返回 EINVAL 错误代码。
ENOMEM
系统中没有可用于执行 I/O 操作的内存。
埃弗比奇
请求了大于 MAX_FILESIZE 值的偏移值。
再次
源或目标文件已意外更改。 错误代码指示必须再次调用 cpfile 子例程。

示例

以下代码片段显示了使用 cpfile 子例程复制文件的优化方法:


#include <unistd.h>
int main (int argc, char **argv)
{
       int sfd, dfd;
       size64_t  nbytes = 0;
       uint64_t  flags = 0;
       off64_t   offset = 0;

       /* Open source file */
       sfd = open(argv[0], O_RDONLY, 0);
       if (sfd < 0)
       {
             perror(“open”);
             exit(-1);
       }
       /* Open destination file. Create if not exist and truncate to zero size. */
       dfd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC, 0644);
       if (dfd < 0)
       {
              perror(“open”);
              exit(-1);
       }

       /* Perform any other tasks like copying attributes */
       /* Call cpfile to copy whole file. */
       rc = cpfile(sfd, dfd, offset, &nbytes, flags);
       {
              perror(“cpfile”);
              exit(-1);
       }
       close(sfd);
       close(dfd);
}