package.rb

来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· RB 代码 · 共 853 行 · 第 1/2 页

RB
853
字号
## Copyright (C) 2004 Mauricio Julio Fern醤dez Pradier# See LICENSE.txt for additional licensing information.#require 'yaml'require 'yaml/syck'require 'fileutils'require 'zlib'require 'digest/md5'require 'fileutils'require 'find'require 'stringio'require 'rubygems/specification'require 'rubygems/security'module Gem# Wrapper for FileUtils meant to provide logging and additional operations if# needed.class FileOperations    extend FileUtils    class << self            # additional methods not implemented in FileUtils    end    def initialize(logger = nil)        @logger = logger    end    def method_missing(meth, *args, &block)        case        when FileUtils.respond_to?(meth)            @logger.log "#{meth}: #{args}" if @logger            FileUtils.send meth, *args, &block        when FileOperations.respond_to?(meth)            @logger.log "#{meth}: #{args}" if @logger            FileOperations.send meth, *args, &block        else            super        end    endendmodule Packageclass NonSeekableIO < StandardError; endclass ArgumentError < ::ArgumentError; endclass ClosedIO < StandardError; endclass BadCheckSum < StandardError; endclass TooLongFileName < StandardError; endmodule FSyncDir    private    def fsync_dir(dirname)            # make sure this hits the disc        begin            dir = open(dirname, "r")            dir.fsync        rescue # ignore IOError if it's an unpatched (old) Ruby        ensure            dir.close if dir rescue nil         end    endendclass TarHeader    FIELDS = [:name, :mode, :uid, :gid, :size, :mtime, :checksum, :typeflag,            :linkname, :magic, :version, :uname, :gname, :devmajor,             :devminor, :prefix]    FIELDS.each {|x| attr_reader x}    def self.new_from_stream(stream)        data = stream.read(512)        fields = data.unpack( "A100" + # record name                             "A8A8A8" +        # mode, uid, gid                             "A12A12" +        # size, mtime                             "A8A" +           # checksum, typeflag                             "A100" +          # linkname                             "A6A2" +          # magic, version                             "A32" +           # uname                             "A32" +           # gname                             "A8A8" +          # devmajor, devminor                             "A155"            # prefix                            )        name = fields.shift        mode = fields.shift.oct        uid = fields.shift.oct        gid = fields.shift.oct        size = fields.shift.oct        mtime = fields.shift.oct        checksum = fields.shift.oct        typeflag = fields.shift        linkname = fields.shift        magic = fields.shift        version = fields.shift.oct        uname = fields.shift        gname = fields.shift        devmajor = fields.shift.oct        devminor = fields.shift.oct        prefix = fields.shift        empty = (data == "\0" * 512)                new(:name=>name, :mode=>mode, :uid=>uid, :gid=>gid, :size=>size,             :mtime=>mtime, :checksum=>checksum, :typeflag=>typeflag, :magic=>magic,            :version=>version, :uname=>uname, :gname=>gname, :devmajor=>devmajor,            :devminor=>devminor, :prefix=>prefix, :empty => empty )    end        def initialize(vals)        unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]            raise Package::ArgumentError        end        vals[:uid] ||= 0        vals[:gid] ||= 0        vals[:mtime] ||= 0        vals[:checksum] ||= ""        vals[:typeflag] ||= "0"        vals[:magic] ||= "ustar"        vals[:version] ||= "00"        vals[:uname] ||= "wheel"        vals[:gname] ||= "wheel"        vals[:devmajor] ||= 0        vals[:devminor] ||= 0        FIELDS.each {|x| instance_variable_set "@#{x.to_s}", vals[x]}        @empty = vals[:empty]    end    def empty?        @empty    end    def to_s        update_checksum        header(checksum)    end    def update_checksum        h = header(" " * 8)        @checksum = oct(calculate_checksum(h), 6)    end    private    def oct(num, len)        "%0#{len}o" % num    end    def calculate_checksum(hdr)        hdr.unpack("C*").inject{|a,b| a+b}    end    def header(chksum)#           struct tarfile_entry_posix {#             char name[100];   # ASCII + (Z unless filled)#             char mode[8];     # 0 padded, octal, null#             char uid[8];      # ditto#             char gid[8];      # ditto#             char size[12];    # 0 padded, octal, null#             char mtime[12];   # 0 padded, octal, null#             char checksum[8]; # 0 padded, octal, null, space#             char typeflag[1]; # file: "0"  dir: "5" #             char linkname[100]; # ASCII + (Z unless filled)#             char magic[6];      # "ustar\0"#             char version[2];    # "00"#             char uname[32];     # ASCIIZ#             char gname[32];     # ASCIIZ#             char devmajor[8];   # 0 padded, octal, null#             char devminor[8];   # o padded, octal, null#             char prefix[155];   # ASCII + (Z unless filled)#           };        arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),                oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,                uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]        str = arr.pack("a100a8a8a8a12a12" + # name, mode, uid, gid, size, mtime                       "a7aaa100a6a2" + # chksum, typeflag, linkname, magic, version                       "a32a32a8a8a155") # uname, gname, devmajor, devminor, prefix        str + "\0" * ((512 - str.size) % 512)    endendclass TarWriter    class FileOverflow < StandardError; end    class BlockNeeded < StandardError; end    class BoundedStream        attr_reader :limit, :written        def initialize(io, limit)            @io = io            @limit = limit            @written = 0        end        def write(data)            if data.size + @written > @limit                raise FileOverflow,                     "You tried to feed more data than fits in the file."             end            @io.write data            @written += data.size            data.size        end    end    class RestrictedStream        def initialize(anIO)            @io = anIO        end        def write(data)            @io.write data        end    end    def self.new(anIO)        writer = super(anIO)        return writer unless block_given?        begin            yield writer        ensure            writer.close        end        nil    end    def initialize(anIO)        @io = anIO        @closed = false    end    def add_file_simple(name, mode, size)        raise BlockNeeded unless block_given?        raise ClosedIO if @closed        name, prefix = split_name(name)        header = TarHeader.new(:name => name, :mode => mode,                                :size => size, :prefix => prefix).to_s        @io.write header        os = BoundedStream.new(@io, size)        yield os        #FIXME: what if an exception is raised in the block?        min_padding = size - os.written         @io.write("\0" * min_padding)        remainder = (512 - (size % 512)) % 512        @io.write("\0" * remainder)    end    def add_file(name, mode)        raise BlockNeeded unless block_given?        raise ClosedIO if @closed        raise NonSeekableIO unless @io.respond_to? :pos=        name, prefix = split_name(name)        init_pos = @io.pos        @io.write "\0" * 512 # placeholder for the header        yield RestrictedStream.new(@io)        #FIXME: what if an exception is raised in the block?        #FIXME: what if an exception is raised in the block?        size = @io.pos - init_pos - 512        remainder = (512 - (size % 512)) % 512        @io.write("\0" * remainder)        final_pos = @io.pos        @io.pos = init_pos        header = TarHeader.new(:name => name, :mode => mode,                                :size => size, :prefix => prefix).to_s        @io.write header        @io.pos = final_pos     end    def mkdir(name, mode)        raise ClosedIO if @closed        name, prefix = split_name(name)        header = TarHeader.new(:name => name, :mode => mode, :typeflag => "5",                               :size => 0, :prefix => prefix).to_s        @io.write header        nil    end    def flush        raise ClosedIO if @closed        @io.flush if @io.respond_to? :flush    end    def close        #raise ClosedIO if @closed        return if @closed        @io.write "\0" * 1024        @closed = true    end    private    def split_name name        raise TooLongFileName if name.size > 256         if name.size <= 100            prefix = ""        else            parts = name.split(/\//)            newname = parts.pop            nxt = ""            loop do                nxt = parts.pop                break if newname.size + 1 + nxt.size > 100                newname = nxt + "/" + newname            end            prefix = (parts + [nxt]).join "/"            name = newname            raise TooLongFileName if name.size > 100 || prefix.size > 155        end        return name, prefix    endend class TarReader    include Gem::Package    class UnexpectedEOF < StandardError; end    module InvalidEntry        def read(len=nil); raise ClosedIO; end        def getc; raise ClosedIO;  end        def rewind; raise ClosedIO;  end    end    class Entry        TarHeader::FIELDS.each{|x| attr_reader x}        def initialize(header, anIO)            @io = anIO            @name = header.name            @mode = header.mode            @uid = header.uid            @gid = header.gid            @size = header.size            @mtime = header.mtime            @checksum = header.checksum            @typeflag = header.typeflag            @linkname = header.linkname            @magic = header.magic            @version = header.version            @uname = header.uname            @gname = header.gname            @devmajor = header.devmajor            @devminor = header.devminor            @prefix = header.prefix            @read = 0            @orig_pos = @io.pos        end        def read(len = nil)            return nil if @read >= @size            len ||= @size - @read            max_read = [len, @size - @read].min            ret = @io.read(max_read)            @read += ret.size            ret        end        def getc            return nil if @read >= @size            ret = @io.getc            @read += 1 if ret            ret        end        def is_directory?            @typeflag == "5"        end        def is_file?            @typeflag == "0"        end        def eof?            @read >= @size        end        def pos            @read        end        def rewind            raise NonSeekableIO unless @io.respond_to? :pos=            @io.pos = @orig_pos            @read = 0        end        alias_method :is_directory, :is_directory?        alias_method :is_file, :is_file        def bytes_read            @read        end        def full_name            if @prefix != ""                File.join(@prefix, @name)            else                @name            end        end        def close            invalidate        end        private        def invalidate            extend InvalidEntry        end    end    def self.new(anIO)        reader = super(anIO)        return reader unless block_given?        begin            yield reader        ensure            reader.close        end        nil    end    def initialize(anIO)        @io = anIO        @init_pos = anIO.pos    end    def each(&block)        each_entry(&block)    end    # do not call this during a #each or #each_entry iteration

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?