2 # Ar reads ar(5) formatted files.
6 class Error < RuntimeError; end
13 # Removes +files+ from the archive.
19 Tempfile.open "#{File.basename @path}.new" do |io|
22 each do |name, mtime, uid, gid, mode, data|
23 next if files.include? name
25 write_file io, name, mtime, uid, gid, mode, data
28 FileUtils.mv io.path, @path
35 # Yields each archive item's metadata and data.
38 open @path, 'rb' do |io|
39 raise Error, "#{@path} is not an archive file" if io.gets != "!<arch>\n"
43 mtime = io.read(12).to_i
44 mtime = Time.at(mtime).utc
45 uid = io.read( 6).to_i
46 gid = io.read( 6).to_i
47 mode = io.read( 8).to_i(8)
48 size = io.read(10).to_i
51 name = if name =~ /^#1\/(\d+)/ then
54 io.read(name_length).delete "\000"
60 io.read 1 if size % 2 == 1
62 yield name, mtime, uid, gid, mode, data
68 # Exctracts metadata and data for +file+. Returns an Array containing the
69 # name, last modification time, uid, gid, mode and archive item data.
78 # Lists the files in the archive in order.
81 map do |name,| name end
85 # Adds or replaces the file +name+ in the archive. If the file already
86 # exists, it is moved to the end of the archive.
88 def replace(name, mtime, uid, gid, mode, data)
89 if File.exist? @path then
90 delete name if list.include? name
92 open @path, 'ab' do |io| io.write "!<arch>\n" end
95 open @path, 'ab' do |io|
96 write_file io, name, mtime.to_i, uid, gid, mode, data
103 # Writes the archive to +io+.
108 each do |name, mtime, uid, gid, mode, data|
109 write_file io, name, mtime, uid, gid, mode, data
115 def write_file(io, name, mtime, uid, gid, mode, data) # :nodoc:
116 unless name.length > 16 then
118 io.write name.ljust(16)
120 padding = 4 - name.length % 4
121 padding = 0 if padding > 3
122 io.write "#1/#{name.length + padding}".ljust(16)
125 io.write mtime .to_i.to_s.ljust(12)
126 io.write uid .to_s .ljust( 6)
127 io.write gid .to_s .ljust( 6)
128 io.write mode .to_s(8) .ljust( 8)
129 size = data.length + (padding ? name.length + padding : 0)
130 io.write size .to_s .ljust(10)
133 if name.length > 16 then
134 name = name.ljust name.length + padding, "\000"
139 io.write "\n" if data.length % 2 == 1
144 def self.after_loaded # :nodoc: