Tar

Tar.create函数
create(
    [ predicate, ] dir, [ tarball ];
    [ skeleton, ] [ portable = false ]
) -> tarball

    predicate :: String --> Bool
    dir       :: AbstractString
    tarball   :: Union{AbstractString, AbstractCmd, IO}
    skeleton  :: Union{AbstractString, AbstractCmd, IO}
    portable  :: Bool

创建目录 dir 的 tar 归档文件(“tarball”)。生成的归档文件将写入路径 tarball,或者如果未指定路径,则创建一个临时路径并由函数调用返回。如果 tarball 是一个 IO 对象,则 tarball 内容将写入该句柄(句柄保持打开状态)。

如果传递了 predicate 函数,则在递归搜索 dir 时遇到每个系统路径时都会调用它,并且只有当 predicate(path) 为真时,path 才包含在 tarball 中。如果 predicate(path) 对目录返回 false,则该目录将被完全排除:该目录下的任何内容都不会包含在归档文件中。

如果传递了 skeleton 关键字,则给定的文件或 IO 句柄将用作生成 tarball 的“骨架”。您可以通过将 skeleton 关键字传递给 extract 命令来创建骨架文件。如果使用该骨架文件调用 create 并且提取的文件没有更改,则会重新创建相同的 tarball。skeletonpredicate 参数不能一起使用。

如果 portable 标志为真,则会检查路径名称在 Windows 上的有效性,这确保它们不包含非法字符或具有保留的名称。有关详细信息,请参阅 https://stackoverflow.com/a/31976060/659248。

Tar.extract函数
extract(
    [ predicate, ] tarball, [ dir ];
    [ skeleton = <none>, ]
    [ copy_symlinks = <auto>, ]
    [ set_permissions = true, ]
) -> dir

    predicate       :: Header --> Bool
    tarball         :: Union{AbstractString, AbstractCmd, IO}
    dir             :: AbstractString
    skeleton        :: Union{AbstractString, AbstractCmd, IO}
    copy_symlinks   :: Bool
    set_permissions :: Bool

将位于路径 tarball 的 tar 归档文件(“tarball”)提取到目录 dir 中。如果 tarball 是 IO 对象而不是路径,则归档内容将从该 IO 流中读取。归档文件将提取到 dirdir 必须是现有空目录或可以作为新目录创建的非现有路径。如果未指定 dir,则归档文件将提取到一个临时目录中,该目录由 extract 返回。

如果传递了 predicate 函数,则在提取 tarball 时遇到每个 Header 对象时都会调用它,并且只有当 predicate(hdr) 为真时,才会提取该条目。这可以用于有选择地仅提取归档文件的部分内容,跳过导致 extract 抛出错误的条目,或在提取过程中记录提取的内容。

在传递给谓词函数之前,Header 对象会从 tarball 中的原始标头进行一些修改:path 字段已规范化,以删除 . 条目并将多个连续的斜杠替换为单个斜杠。如果条目的类型为 :hardlink,则链接目标路径也将以相同的方式规范化,以便它与目标条目的路径匹配;size 字段设置为目标路径的大小(该路径必须是已查看的文件)。

如果传递了 skeleton 关键字,则提取的 tarball 的“骨架”将写入给定的文件或 IO 句柄。可以通过将 skeleton 关键字传递给 create 函数来使用此骨架文件重新创建相同的 tarball。skeletonpredicate 参数不能一起使用。

如果 copy_symlinkstrue,则不会像这样提取符号链接,而是如果它们在 tarball 内部并且可以这样做,则将它们提取为其链接到的内容的副本。非内部符号链接(例如,指向 /etc/passwd 的链接)不会被复制。以任何方式循环的符号链接也不会被复制,而是会被跳过。默认情况下,extract 将检测是否可以在 dir 中创建符号链接,如果无法创建,则会自动复制符号链接。

如果 set_permissionsfalse,则不会在提取的文件上设置任何权限。

Tar.list函数
list(tarball; [ strict = true ]) -> Vector{Header}
list(callback, tarball; [ strict = true ])

    callback  :: Header, [ <data> ] --> Any
    tarball   :: Union{AbstractString, AbstractCmd, IO}
    strict    :: Bool

列出位于路径 tarball 的 tar 归档文件(“tarball”)的内容。如果 tarball 是 IO 句柄,则从该流中读取 tar 内容。返回一个 Header 结构体的向量。有关详细信息,请参阅 Header

如果提供了 callback,则不会返回标头的向量,而是对每个 Header 调用 callback。如果 tarball 中的项目数量很大或您希望在 tarball 中出现错误之前检查项目,这将非常有用。如果 callback 函数可以接受类型为 Vector{UInt8}Vector{Pair{Symbol, String}} 的第二个参数,则它将使用原始标头数据的表示形式调用它,作为单个字节向量或作为将字段名称映射到该字段原始数据的对的向量(如果将这些字段连接在一起,则结果是标头的原始数据)。

默认情况下,如果 list 遇到 extract 函数拒绝提取的任何 tarball 内容,则会出错。使用 strict=false,它将跳过这些检查并列出 tar 文件的所有内容,无论 extract 是否提取它们。请注意,恶意 tarball 可以执行各种巧妙且意想不到的操作来试图欺骗您执行某些不良操作。

如果 tarball 参数是骨架文件(请参阅 extractcreate),则 list 将从文件标头检测到这一点,并适当地列出或迭代骨架文件标头。

Tar.rewrite函数
rewrite(
    [ predicate, ] old_tarball, [ new_tarball ];
    [ portable = false, ]
) -> new_tarball

    predicate   :: Header --> Bool
    old_tarball :: Union{AbstractString, AbtractCmd, IO}
    new_tarball :: Union{AbstractString, AbtractCmd, IO}
    portable    :: Bool

old_tarball 重写为 create 生成的标准格式,同时还检查它是否不包含任何会导致 extract 引发错误的内容。这在功能上等同于执行

Tar.create(Tar.extract(predicate, old_tarball), new_tarball)

但是,它永远不会将任何内容提取到磁盘,而是使用 seek 函数来导航旧 tarball 的数据。如果没有传递 new_tarball 参数,则新的 tarball 将写入一个临时文件,其路径将被返回。

如果传递了 predicate 函数,则在提取 old_tarball 时遇到每个 Header 对象时都会调用它,并且除非 predicate(hdr) 为真,否则该条目将被跳过。这可以用于有选择地仅重写归档文件的部分内容,跳过会导致 extract 抛出错误的条目,或在重写过程中记录遇到的内容。

在传递给谓词函数之前,Header 对象会从 tarball 中的原始标头进行一些修改:path 字段已规范化,以删除 . 条目并将多个连续的斜杠替换为单个斜杠。如果条目的类型为 :hardlink,则链接目标路径也将以相同的方式规范化,以便它与目标条目的路径匹配;size 字段设置为目标路径的大小(该路径必须是已查看的文件)。

如果 portable 标志为真,则会检查路径名称在 Windows 上的有效性,这确保它们不包含非法字符或具有保留的名称。有关详细信息,请参阅 https://stackoverflow.com/a/31976060/659248。

Tar.tree_hash函数
tree_hash([ predicate, ] tarball;
          [ algorithm = "git-sha1", ]
          [ skip_empty = false ]) -> hash::String

    predicate  :: Header --> Bool
    tarball    :: Union{AbstractString, AbstractCmd, IO}
    algorithm  :: AbstractString
    skip_empty :: Bool

计算tar包包含的文件树的树哈希值。默认情况下,它使用git的树哈希算法和SHA1安全哈希函数(就像当前版本的git一样)。这意味着对于任何git可以表示其文件树的tar包——即仅包含文件、符号链接和非空目录的tar包——此函数计算的哈希值将与git为该文件树计算的哈希值相同。请注意,tar包可以表示包含空目录的文件树,而git无法存储这些文件树,并且此函数可以为这些文件树生成哈希值,默认情况下(请参阅下面的skip_empty以了解如何更改此行为),这些哈希值将与省略这些空目录的tar包的哈希值不同。简而言之,哈希函数与git在所有git可以表示的树上达成一致,但以一致的方式将可哈希树的域扩展到git无法表示的其他树。

如果传递了predicate函数,则在处理tarball时遇到每个Header对象时都会调用它,并且只有当predicate(hdr)为真时才会对条目进行哈希处理。这可以用来选择性地仅哈希归档的一部分,跳过导致extract抛出错误的条目,或者记录在哈希过程中提取的内容。

在传递给谓词函数之前,Header 对象会从 tarball 中的原始标头进行一些修改:path 字段已规范化,以删除 . 条目并将多个连续的斜杠替换为单个斜杠。如果条目的类型为 :hardlink,则链接目标路径也将以相同的方式规范化,以便它与目标条目的路径匹配;size 字段设置为目标路径的大小(该路径必须是已查看的文件)。

当前支持的algorithm值包括git-sha1(默认值)和git-sha256,后者使用与git-sha1相同的基本算法,但用SHA2-256替换了SHA1哈希函数,SHA2-256是git未来将过渡使用的哈希函数(由于已知的SHA1攻击)。未来可能会添加对其他文件树哈希算法的支持。

skip_empty选项控制是否将tar包中递归不包含文件或符号链接的目录包含在哈希中或忽略。通常,如果您正在对tar包或文件树的内容进行哈希处理,您会关心所有目录,而不仅仅是非空目录,因此将这些目录包含在计算的哈希中是默认行为。那么为什么此函数甚至提供跳过空目录的选项呢?因为git拒绝存储空目录,并且如果您尝试将它们添加到存储库中,它将忽略它们。因此,如果您通过将文件添加到git存储库并然后请求git获取树哈希来计算参考树哈希,那么您获得的哈希值将与tree_hash使用skip_empty=true计算的哈希值匹配。换句话说,此选项允许tree_hash模拟git如何对包含空目录的树进行哈希处理。但是,如果您正在对可能包含空目录的树进行哈希处理(即不来自git存储库),建议您使用不忽略空目录的工具(例如此工具)对其进行哈希处理。

Tar.Header类型

Header类型是一个结构体,表示tar文件中单个记录的基本元数据,其定义如下

struct Header
    path :: String # path relative to the root
    type :: Symbol # type indicator (see below)
    mode :: UInt16 # mode/permissions (best viewed in octal)
    size :: Int64  # size of record data in bytes
    link :: String # target path of a symlink
end

类型用以下符号表示:filehardlinksymlinkchardevblockdevdirectoryfifo,或者对于未知类型,类型标志字符作为符号。请注意,extract拒绝提取除filesymlinkdirectory之外的其他类型的记录;list仅在使用strict=false调用时才会列出其他类型的记录。

tar格式包含有关记录的各种其他元数据,包括用户和组ID、用户和组名称以及时间戳。Tar包在设计上完全忽略了这些元数据。创建tar文件时,这些字段始终设置为零/空。读取tar文件时,除了验证每个标头记录的所有字段的标头校验和外,这些字段将被忽略。