Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add set_permissions argument #113

Merged
merged 8 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,19 @@ recreated. The `skeleton` and `predicate` arguments cannot be used together.
### Tar.extract

```jl
extract([ predicate, ] tarball, [ dir ];
[ skeleton, ] [ copy_symlinks ]) -> dir
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`
* `predicate :: Header --> Bool`
* `tarball :: Union{AbstractString, AbstractCmd, IO}`
* `dir :: AbstractString`
* `skeleton :: Union{AbstractString, AbstractCmd, IO}`
* `copy_symlinks :: Bool`
* `set_permissions :: Bool`

Extract a tar archive ("tarball") located at the path `tarball` into the
directory `dir`. If `tarball` is an IO object instead of a path, then the
Expand Down Expand Up @@ -105,6 +110,8 @@ will also not be copied and will instead be skipped. By default, `extract` will
detect whether symlinks can be created in `dir` or not and will automatically
copy symlinks if they cannot be created.

If `set_permissions` is `false`, no permissions are set on the extracted files.

### Tar.list

```jl
Expand Down
27 changes: 19 additions & 8 deletions src/Tar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,19 @@ function list(
end

"""
extract([ predicate, ] tarball, [ dir ];
[ skeleton, ] [ copy_symlinks ]) -> dir

predicate :: Header --> Bool
tarball :: Union{AbstractString, AbstractCmd, IO}
dir :: AbstractString
skeleton :: Union{AbstractString, AbstractCmd, IO}
copy_symlinks :: Bool
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

Extract a tar archive ("tarball") located at the path `tarball` into the
directory `dir`. If `tarball` is an IO object instead of a path, then the
Expand Down Expand Up @@ -207,13 +212,16 @@ link to `/etc/passwd` will not be copied. Symlinks which are in any way cyclic
will also not be copied and will instead be skipped. By default, `extract` will
detect whether symlinks can be created in `dir` or not and will automatically
copy symlinks if they cannot be created.

If `set_permissions` is `false`, no permissions are set on the extracted files.
"""
function extract(
predicate::Function,
tarball::ArgRead,
dir::Union{AbstractString, Nothing} = nothing;
skeleton::Union{ArgWrite, Nothing} = nothing,
copy_symlinks::Union{Bool, Nothing} = nothing,
set_permissions::Bool = true,
)
predicate === true_predicate || skeleton === nothing ||
error("extract: predicate and skeleton cannot be used together")
Expand All @@ -230,6 +238,7 @@ function extract(
predicate, tar, dir,
skeleton = skeleton,
copy_symlinks = copy_symlinks,
set_permissions = set_permissions,
)
end
end
Expand All @@ -241,11 +250,13 @@ function extract(
dir::Union{AbstractString, Nothing} = nothing;
skeleton::Union{ArgWrite, Nothing} = nothing,
copy_symlinks::Union{Bool, Nothing} = nothing,
set_permissions::Bool = true,
)
extract(
true_predicate, tarball, dir,
skeleton = skeleton,
copy_symlinks = copy_symlinks,
set_permissions = set_permissions,
)
end

Expand Down
5 changes: 3 additions & 2 deletions src/extract.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ function extract_tarball(
buf::Vector{UInt8} = Vector{UInt8}(undef, DEFAULT_BUFFER_SIZE),
skeleton::IO = devnull,
copy_symlinks::Bool = false,
set_permissions::Bool = true,
)
paths = read_tarball(predicate, tar; buf=buf, skeleton=skeleton) do hdr, parts
# get the file system version of the path
Expand Down Expand Up @@ -82,7 +83,7 @@ function extract_tarball(
error("unsupported tarball entry type: $(hdr.type)")
end
# apply tarball permissions
if hdr.type in (:file, :hardlink)
if set_permissions && hdr.type in (:file, :hardlink)
exec = 0o100 & hdr.mode != 0
tar_mode = exec ? 0o755 : 0o644
sys_mode = filemode(sys_path)
Expand Down Expand Up @@ -139,7 +140,7 @@ function extract_tarball(
src = reduce(joinpath, init=root, split(what, '/'))
dst = reduce(joinpath, init=root, split(path, '/'))
cp(src, dst)
if Sys.iswindows()
if set_permissions && Sys.iswindows()
# our `cp` doesn't copy ACL properties, so manually set them via `chmod`
function copy_mode(src::String, dst::String)
chmod(dst, filemode(src))
Expand Down
21 changes: 20 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ end
@arg_test tar @test_throws ErrorException tar_count(tar, strict=true)
@arg_test tar @test n + 1 == tar_count(tar, strict=false)
end
rm(tarball)
end

@testset "API: extract" begin
Expand Down Expand Up @@ -704,6 +705,23 @@ end
end
end
end
rm(tarball)

@testset "set_permissions" begin
tarball, _ = make_test_tarball()
dir = Tar.extract(tarball, set_permissions=false)
f_path = joinpath(dir, "0-ffffffff")
x_path = joinpath(dir, "0-xxxxxxxx")
@test isfile(f_path)
@test isfile(x_path)
if !Sys.iswindows()
@test !Sys.isexecutable(f_path)
@test !Sys.isexecutable(x_path)
end
@test Sys.isexecutable(f_path) == Sys.isexecutable(x_path)
rm(dir, recursive=true)
rm(tarball)
end
end

@testset "API: rewrite" begin
Expand Down Expand Up @@ -845,7 +863,7 @@ end

if Sys.iswindows() && Sys.which("icacls") !== nothing && VERSION >= v"1.6"
@testset "windows permissions" begin
tarball, hash = make_test_tarball()
tarball, _ = make_test_tarball()
mktempdir() do dir
Tar.extract(tarball, dir)
f_path = joinpath(dir, "0-ffffffff")
Expand All @@ -861,5 +879,6 @@ if Sys.iswindows() && Sys.which("icacls") !== nothing && VERSION >= v"1.6"
x_acl = readchomp(`icacls $(x_path)`)
@test occursin("Everyone:(RX,WA)", x_acl)
end
rm(tarball)
end
end