rubyzip/lib/zip/extra_field/ntfs.rb

94 lines
2.2 KiB
Ruby
Raw Normal View History

2014-09-12 14:04:23 +08:00
module Zip
# PKWARE NTFS Extra Field (0x000a)
# Only Tag 0x0001 is supported
class ExtraField::NTFS < ExtraField::Generic
HEADER_ID = [0x000A].pack('v')
register_map
2015-03-24 00:23:04 +08:00
WINDOWS_TICK = 10_000_000.0
SEC_TO_UNIX_EPOCH = 11_644_473_600
2014-09-12 14:04:23 +08:00
def initialize(binstr = nil)
@ctime = nil
@mtime = nil
@atime = nil
2015-03-21 15:45:46 +08:00
binstr && merge(binstr)
2014-09-12 14:04:23 +08:00
end
attr_accessor :atime, :ctime, :mtime
def merge(binstr)
return if binstr.empty?
size, content = initial_parse(binstr)
2015-03-21 15:45:46 +08:00
(size && content) || return
2014-09-12 14:04:23 +08:00
content = content[4..-1]
tags = parse_tags(content)
tag1 = tags[1]
if tag1
2015-03-21 16:27:44 +08:00
ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
2015-03-21 15:45:46 +08:00
ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
ntfs_ctime && @ctime ||= from_ntfs_time(ntfs_ctime)
2014-09-12 14:04:23 +08:00
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
2015-03-21 16:27:44 +08:00
s = [0, 1].pack('Vv')
2014-09-12 14:04:23 +08:00
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
2014-09-12 14:04:23 +08:00
def parse_tags(content)
return {} if content.nil?
tags = {}
i = 0
2015-03-21 03:38:09 +08:00
while i < content.bytesize
2014-09-12 14:04:23 +08:00
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