94 lines
2.2 KiB
Ruby
94 lines
2.2 KiB
Ruby
module Zip
|
|
# PKWARE NTFS Extra Field (0x000a)
|
|
# Only Tag 0x0001 is supported
|
|
class ExtraField::NTFS < ExtraField::Generic
|
|
HEADER_ID = [0x000A].pack('v')
|
|
register_map
|
|
|
|
WINDOWS_TICK = 10000000.0
|
|
SEC_TO_UNIX_EPOCH = 11644473600
|
|
|
|
def initialize(binstr = nil)
|
|
@ctime = nil
|
|
@mtime = nil
|
|
@atime = nil
|
|
binstr && merge(binstr)
|
|
end
|
|
|
|
attr_accessor :atime, :ctime, :mtime
|
|
|
|
def merge(binstr)
|
|
return if binstr.empty?
|
|
size, content = initial_parse(binstr)
|
|
(size && content) || return
|
|
|
|
content = content[4..-1]
|
|
tags = parse_tags(content)
|
|
|
|
tag1 = tags[1]
|
|
if tag1
|
|
ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
|
|
ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
|
|
ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
|
|
ntfs_ctime && @ctime ||= from_ntfs_time(ntfs_ctime)
|
|
end
|
|
end
|
|
|
|
def ==(other)
|
|
@mtime == other.mtime &&
|
|
@atime == other.atime &&
|
|
@ctime == other.ctime
|
|
end
|
|
|
|
# Info-ZIP note states this extra field is stored at local header
|
|
def pack_for_local
|
|
pack_for_c_dir
|
|
end
|
|
|
|
# But 7-zip for Windows only stores at central dir
|
|
def pack_for_c_dir
|
|
# reserved 0 and tag 1
|
|
s = [0, 1].pack('Vv')
|
|
|
|
tag1 = ''.force_encoding(Encoding::BINARY)
|
|
if @mtime
|
|
tag1 << [to_ntfs_time(@mtime)].pack('Q<')
|
|
if @atime
|
|
tag1 << [to_ntfs_time(@atime)].pack('Q<')
|
|
if @ctime
|
|
tag1 << [to_ntfs_time(@ctime)].pack('Q<')
|
|
end
|
|
end
|
|
end
|
|
s << [tag1.bytesize].pack('v') << tag1
|
|
s
|
|
end
|
|
|
|
private
|
|
|
|
def parse_tags(content)
|
|
return {} if content.nil?
|
|
tags = {}
|
|
i = 0
|
|
while i < content.bytesize
|
|
tag, size = content[i, 4].unpack('vv')
|
|
i += 4
|
|
break unless tag && size
|
|
value = content[i, size]
|
|
i += size
|
|
tags[tag] = value
|
|
end
|
|
|
|
tags
|
|
end
|
|
|
|
def from_ntfs_time(ntfs_time)
|
|
::Zip::DOSTime.at(ntfs_time / WINDOWS_TICK - SEC_TO_UNIX_EPOCH)
|
|
end
|
|
|
|
def to_ntfs_time(time)
|
|
((time.to_f + SEC_TO_UNIX_EPOCH) * WINDOWS_TICK).to_i
|
|
end
|
|
end
|
|
end
|