class ZKSync::CryptoFile
Attributes
archive[R]
archive_path[R]
Public Class Methods
new(archive_path, archive)
click to toggle source
# File lib/zksync/crypto_file.rb, line 22 def initialize(archive_path, archive) @archive = archive @archive_path = archive_path end
Public Instance Methods
__read_page_keep_padding(page_num)
click to toggle source
# File lib/zksync/crypto_file.rb, line 71 def __read_page_keep_padding(page_num) page_encrypted = IO.read(page_path(page_num), page_physical_size) page_key = Key.new(file_key.decrypt(page_encrypted[0...Key.write_size]), type: :literal) page_key.decrypt(page_encrypted[Key.write_size..-1]) end
file_key()
click to toggle source
# File lib/zksync/crypto_file.rb, line 47 def file_key @file_key ||= archive.keystore.file_key(archive_path) end
inode()
click to toggle source
# File lib/zksync/crypto_file.rb, line 43 def inode @inode ||= archive.file_index.inode_for_path(archive_path) end
make_parent_directories(path)
click to toggle source
# File lib/zksync/crypto_file.rb, line 83 def make_parent_directories(path) FileUtils.mkdir_p(File.dirname(path)) end
page_count()
click to toggle source
# File lib/zksync/crypto_file.rb, line 39 def page_count (size.to_f/page_size).ceil end
page_matches?(pagefile_path, key)
click to toggle source
# File lib/zksync/crypto_file.rb, line 87 def page_matches?(pagefile_path, key) return false unless File.exists?(pagefile_path) IO.read(pagefile_path, Key.size) == key.to_b end
page_path(page_num)
click to toggle source
# File lib/zksync/crypto_file.rb, line 51 def page_path(page_num) index_hash = Digest::SHA256.hexdigest(file_key.to_s + ":" + archive_path + ":#{page_num}-") File.join(archive.root, "#{index_hash[0..1]}/#{index_hash[2..3]}/#{index_hash[4..-1]}") end
page_physical_size()
click to toggle source
# File lib/zksync/crypto_file.rb, line 27 def page_physical_size 65536 end
page_size()
click to toggle source
# File lib/zksync/crypto_file.rb, line 31 def page_size page_physical_size - Key.write_size - 1 end
read() { |read_page(n)| ... }
click to toggle source
# File lib/zksync/crypto_file.rb, line 65 def read page_count.times do |n| yield read_page(n) end end
read_page(page_num)
click to toggle source
# File lib/zksync/crypto_file.rb, line 77 def read_page(page_num) plaintext = __read_page_keep_padding(page_num) plaintext = plaintext[0...(size % page_size)] if page_num == page_count-1 plaintext end
size()
click to toggle source
# File lib/zksync/crypto_file.rb, line 35 def size inode.size end
trim_to_size(size)
click to toggle source
call me before updating inode size ensure excess pages are pruned if a file shrinks
# File lib/zksync/crypto_file.rb, line 128 def trim_to_size(size) old_page_count = (inode.size/page_size).ceil new_page_count = (size/page_size).ceil return if new_page_count >= old_page_count (new_page_count .. old_page_count).to_a.each do |page_num| pagefile = page_path(page_num) File.unlink(pagefile) if File.exists? pagefile end end
valid?()
click to toggle source
# File lib/zksync/crypto_file.rb, line 56 def valid? return true if inode.ftype == "directory" raise "No inode" unless inode digest = Digest::SHA256.new read { |page| digest << page } digest.hexdigest == inode.sha256 end
write(in_stream, mtime)
click to toggle source
# File lib/zksync/crypto_file.rb, line 92 def write(in_stream, mtime) page_num = 0 bytes = 0 while page_plaintext = in_stream.read(page_size) do write_page(page_num, page_plaintext) bytes += page_plaintext.length page_num += 1 end trim_to_size(bytes) inode.size = bytes inode.mtime = mtime end
write_page(page_num, page_plaintext)
click to toggle source
# File lib/zksync/crypto_file.rb, line 107 def write_page(page_num, page_plaintext) page_hash = Digest::SHA256.hexdigest(page_plaintext) pagefile_path = page_path(page_num) page_key = archive.keystore.page_key(archive_path, page_num, page_hash) return if page_matches?(pagefile_path, page_key) encrypted_key = file_key.encrypt(page_key.to_b) padding = "\0" * (page_size - page_plaintext.length) encrypted_data = page_key.encrypt(page_plaintext + padding) make_parent_directories(pagefile_path) File.write(pagefile_path, encrypted_key + encrypted_data) ts_digest = "TIMESTAMP:" + page_hash 16.times { ts_digest = Digest::SHA256.digest(ts_digest) } ts = ts_digest[0..3].unpack("L").first & 0x7FFFFFFF File.utime(Time.at(ts), Time.at(ts), pagefile_path) end