File: ar.rb

package info (click to toggle)
dpkg-ruby 0.3.6%2Bnmu2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 348 kB
  • ctags: 386
  • sloc: ruby: 2,841; fortran: 90; makefile: 75; cpp: 36; sh: 8
file content (159 lines) | stat: -rw-r--r-- 4,129 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#
# ar.rb - ar(1) ruby interface (for debian.rb)
# Copyright (c) 2001 Fumitoshi UKAI <ukai@debian.or.jp>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# $Id: ar.rb,v 1.3 2003/10/07 17:07:02 ukai Exp $
#

# struct ar_hdr
#  {
#   char ar_name[16];           /* Member file name, sometimes / terminated. */
#   char ar_date[12];           /* File date, decimal seconds since Epoch.  */
#   char ar_uid[6], ar_gid[6];  /* User and group IDs, in ASCII decimal.  */
#   char ar_mode[8];            /* File mode, in ASCII octal.  */
#   char ar_size[10];           /* File size, in ASCII decimal.  */
#   char ar_fmag[2];            /* Always contains ARFMAG.  */
# };

module Debian
  class ArError < StandardError; end
  class Ar
    ARMAG = "!<arch>\n"
    SARMAG = 8
    ARFMAG = "`\n"
    AR_HDR_SIZE = (16+12+6+6+8+10+2)
    class ArFile
      class Stat
	def initialize(time,uid,gid,mode,size,dev)
	  @time, @uid, @gid, @mode, @size, @dev = time,uid,gid,mode,size,dev
	end
	def <=>(s) @time <=> s.atime; end
	def atime; @time; end
	def blksize; 0; end
	def blockdev?; false; end
	def blocks; 0; end
	def chardev?; false; end
	def ctime; @time; end
	def dev; @dev; end
	def directory?; false; end
	def executable?; false; end
	def executable_real?; false; end
	def file?; true; end
	def ftype; 'file'; end
	def gid; @gid; end
	def grpowned?; false; end
	def ino; @dev; end
	def mode; @mode; end
	def mtime; @time; end
	def nlink; 1; end
	def owned?; false; end
	def pipe?; false; end
	def rdev; @dev; end
	def readable?; true; end
	def readable_real?; true; end
	def setgid?; false; end
	def setuid?; false; end
	def size; @size; end
	def size?; @size == 0 ? nil : @size; end
	def socket?; false; end
	def sticky?; false; end
	def symlink?; false; end
	def uid; @uid; end
	def writable?; false; end
	def writable_real?; false; end
	def zero?; @size == 0; end
      end

      def initialize(fp,name,date,uid,gid,mode,size,pos)
	@fp,@name = fp,name
	@stat = Stat.new(date,uid,gid,mode,size,pos)
	@size = size
	@pos = pos
	@cur = 0
      end
      attr_reader :name, :size, :pos, :cur, :stat

      def read(size = -1)
	if size < 0
	  size = @size - @cur
	end
	if @cur + size > @size
	  size = @size - @cur
	end
	@fp.seek(@pos + @cur, IO::SEEK_SET)
	r = @fp.read(size)
	@cur += r.size
	return r
      end

      def eof?; @cur == @size; end
      def rewind; @cur = 0; end
    end
    
    def initialize(file)
      @fp = File.open(file)
      magic = @fp.gets
      unless magic == ARMAG
	raise ArError, "archive broken"
      end
      @ofs = []
    end

    def close
      @fp.close
    end

    def list
      @fp.seek(SARMAG, IO::SEEK_SET)
      while ! @fp.eof?
	hdr = @fp.read(AR_HDR_SIZE)
	name,date,uid,gid,mode,size,fmag = hdr.unpack('a16a12a6a6a8a10a2')
	unless fmag == ARFMAG
	  raise ArError, "invalid archive field magic #{fmag} @ #{@fp.pos} [#{hdr}]"
	end
	name.strip!
	size = size.to_i
	@ofs.push(ArFile.new(@fp,
			     name,Time.at(date.to_i), uid.to_i, gid.to_i,
			     mode.oct, size, @fp.pos))
	# puts "hdr=[#{hdr}] pos=#{@fp.pos}, size=#{size} #{(size + 1)&~1}"
	@fp.seek((size + 1)&~1, IO::SEEK_CUR)
      end
      @ofs
    end
    def each_file
      if @ofs.empty?; list; end
      @ofs.each {|file|
	yield file.name, file
      }
    end

    def open(name)
      if @ofs.empty?; list; end
      @ofs.each {|file|
	if file.name == name
	  if block_given?
	    return yield(file)
	  else
	    return file
	  end
	end
      }
    end
  end

end