深度剖析 Linux cp 命令的秘密( 九 )

static enum Sparse_type const sparse_type[] ={  SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS};所以,main 函数里赋值了 x.sparse_mode 这个参数,这个参数也是稀疏文件行为的指导参数,后面怎么处理稀疏文件,就依赖于这个参数 。
下面就是依次调用 do_copy ,copy,copy_internal 函数,do_copy,copy 这两个函数就是处理一些封装,校验,包括涉及目录的一些逻辑,跟我们本次稀疏文件解密关系不大,直接略过 。
copy_internal 则是一个巨长的函数,里面的逻辑多数是一些兼容性,适配场景的考虑,也和本次关系不大 。对于一个普通文件( regular 类型) 最终调用到 copy_reg 函数,才是普通文件 copy 的实现所在 。
  else if (S_ISREG (src_mode)           || (x->copy_as_regular && !S_ISLNK (src_mode)))    {      copied_as_regular = true;      // 普通文件的拷贝      if (! copy_reg (src_name, dst_name, x, dst_mode_bits & S_IRWXUGO,                      omitted_permissions, &new_dst, &src_sb))        goto un_backup;普通文件的 copy 就是从函数 copy_reg 才真正开始的 。在这个函数里,首先 open 源文件和目标文件的句柄,然后进行数据拷贝 。
static boolcopy_reg( ... ) {  // 确认要拷贝数据  if (data_copy_required)    {      // 获取到块大小,buffer 大小等参数      size_t buf_alignment = getpagesize ();      size_t buf_size = io_blksize (sb);      size_t hole_size = ST_BLKSIZE (sb);      bool make_holes = false;      // 关键函数来啦,is_probably_sparse 函数就是用来判断源文件是否是稀疏文件的;      bool sparse_src = is_probably_sparse (&src_open_sb);      if (S_ISREG (sb.st_mode))        {          if (x->sparse_mode == SPARSE_ALWAYS)            // sparse_always 模式,也是追求极致空间效率的策略;            // 所以这种方式不管源文件是否真的是稀疏文件,都会生成稀疏的目标文件;            make_holes = true;          // 如果是 sparse_auto 的策略,并且源文件是稀疏文件,那么目标文件也会是稀疏文件(也就是可以有洞洞的文件)          if (x->sparse_mode == SPARSE_AUTO && sparse_src)            make_holes = true;        }      // 如果到这里判断不是目标不会是稀疏文件,那么就使用更有效率的方式来 copy,比如用更大的 buffer 来装数据,一次 copy 更多;      if (! make_holes)        {            // 略        }      // 源文件是稀疏文件的情况下,可以使用 extent_copy 这种更有效率的方式进行拷贝 。      if (sparse_src)        {          if (extent_copy (source_desc, dest_desc, buf, buf_size, hole_size,                           src_open_sb.st_size,                           make_holes ? x->sparse_mode : SPARSE_NEVER,                           src_name, dst_name, &normal_copy_required))            goto preserve_metadata;                    }      // 如果源文件判断不是稀疏文件,那么就使用标准的 sparse_copy 函数来拷贝 。      if (! sparse_copy (source_desc, dest_desc, buf, buf_size,                         make_holes ? hole_size : 0,                         x->sparse_mode == SPARSE_ALWAYS, src_name, dst_name,                         UINTMAX_MAX, &n_read,                         &wrote_hole_at_eof))        {          return_val = false;          goto close_src_and_dst_desc;        }        // 略    }    }


推荐阅读