Skip to content

Commit

Permalink
Add symlink support, closes #8
Browse files Browse the repository at this point in the history
  • Loading branch information
Pete Fritchman authored and halostatue committed Mar 26, 2022
1 parent 3ded648 commit 5bd757a
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 8 deletions.
22 changes: 22 additions & 0 deletions lib/archive/tar/minitar/writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,28 @@ def mkdir(name, opts = {})
nil
end

# Creates a symbolic link entry in the tar.
def symlink(name, link_target, opts = {})
raise ClosedStream if @closed

raise FileNameTooLong if link_target.size > 100

name, prefix = split_name(name)
header = {
:name => name,
:mode => opts[:mode],
:typeflag => "2",
:size => 0,
:linkname => link_target,
:gid => opts[:gid],
:uid => opts[:uid],
:mtime => opts[:mtime],
:prefix => prefix
}
@io.write(PosixHeader.new(header))
nil
end

# Passes the #flush method to the wrapped stream, used for buffered
# streams.
def flush
Expand Down
2 changes: 1 addition & 1 deletion test/minitest_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- ruby encoding: utf-8 -*-
# frozen_string_literal: true

require "fileutils"
require "minitar"
Expand Down
13 changes: 9 additions & 4 deletions test/support/tar_test_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,24 @@ def tar_dir_header(name, prefix, mode)
update_checksum(header("5", name, prefix, 0, mode))
end

def header(type, fname, dname, length, mode)
def tar_symlink_header(name, prefix, mode, target)
update_checksum(header("2", name, prefix, 0, mode, target))
end

def header(type, fname, dname, length, mode, link_name = "")
raw_header(type,
asciiz(fname, 100),
asciiz(dname, 155),
z(to_oct(length, 11)),
z(to_oct(mode, 7)))
z(to_oct(mode, 7)),
asciiz(link_name, 100))
end

def raw_header(type, fname, dname, length, mode)
def raw_header(type, fname, dname, length, mode, link_name = "")
arr = [
fname, mode, z(to_oct(nil, 7)), z(to_oct(nil, 7)),
length, z(to_oct(0, 11)), BLANK_CHECKSUM, type,
NULL_100, USTAR, DOUBLE_ZERO, asciiz("", 32), asciiz("", 32),
asciiz(link_name, 100), USTAR, DOUBLE_ZERO, asciiz("", 32), asciiz("", 32),
z(to_oct(nil, 7)), z(to_oct(nil, 7)), dname
]

Expand Down
20 changes: 17 additions & 3 deletions test/test_tar_writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ def test_write_operations_fail_after_closed
@os.add_file_simple("sadd", :mode => 0o644, :size => 20) { |f| }
@os.close
assert_raises(Minitar::ClosedStream) { @os.flush }
assert_raises(Minitar::ClosedStream) {
@os.add_file("dfdsf", :mode => 0o644) {}
}
assert_raises(Minitar::ClosedStream) { @os.add_file("dfdsf", :mode => 0o644) {} }
assert_raises(Minitar::ClosedStream) { @os.mkdir "sdfdsf", :mode => 0o644 }
assert_raises(Minitar::ClosedStream) { @os.symlink "a", "b", :mode => 0o644 }
end

def test_file_name_is_split_correctly
Expand Down Expand Up @@ -261,4 +260,19 @@ def test_file_size_is_checked
end
@os.add_file_simple("lib/foo/bar", :mode => 0o644, :size => 10) { |f| }
end

def test_symlink
@dummyos.reset
@os.symlink("lib/foo/bar", "lib/foo/baz", :mode => 0o644)
@os.flush
assert_headers_equal(tar_dir_header("lib/foo", "", 0o644),
@dummyos.data[0, 512])
end

def test_symlink_target_size_is_checked
@dummyos.reset
assert_raises(Minitar::FileNameTooLong) do
@os.symlink("lib/foo/bar", "x" * 101)
end
end
end

0 comments on commit 5bd757a

Please sign in to comment.