Class: ZKSync::CryptoFile
- Inherits:
-
Object
- Object
- ZKSync::CryptoFile
- Defined in:
- lib/zksync/crypto_file.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#archive ⇒ Object
readonly
Returns the value of attribute archive.
-
#archive_path ⇒ Object
readonly
Returns the value of attribute archive_path.
Instance Method Summary collapse
- #__read_page_keep_padding(page_num) ⇒ Object
- #file_key ⇒ Object
-
#initialize(archive_path, archive) ⇒ CryptoFile
constructor
A new instance of CryptoFile.
- #inode ⇒ Object
- #make_parent_directories(path) ⇒ Object
- #page_count ⇒ Object
- #page_matches?(pagefile_path, key) ⇒ Boolean
- #page_path(page_num) ⇒ Object
- #page_physical_size ⇒ Object
- #page_size ⇒ Object
- #read ⇒ Object
- #read_page(page_num) ⇒ Object
- #size ⇒ Object
-
#trim_to_size(size) ⇒ Object
call me before updating inode size ensure excess pages are pruned if a file shrinks.
- #valid? ⇒ Boolean
- #write(in_stream, mtime) ⇒ Object
- #write_page(page_num, page_plaintext) ⇒ Object
Constructor Details
#initialize(archive_path, archive) ⇒ CryptoFile
Returns a new instance of CryptoFile.
22 23 24 25 |
# File 'lib/zksync/crypto_file.rb', line 22 def initialize(archive_path, archive) @archive = archive @archive_path = archive_path end |
Instance Attribute Details
#archive ⇒ Object (readonly)
Returns the value of attribute archive.
20 21 22 |
# File 'lib/zksync/crypto_file.rb', line 20 def archive @archive end |
#archive_path ⇒ Object (readonly)
Returns the value of attribute archive_path.
20 21 22 |
# File 'lib/zksync/crypto_file.rb', line 20 def archive_path @archive_path end |
Instance Method Details
#__read_page_keep_padding(page_num) ⇒ Object
71 72 73 74 75 |
# 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 ⇒ Object
47 48 49 |
# File 'lib/zksync/crypto_file.rb', line 47 def file_key @file_key ||= archive.keystore.file_key(archive_path) end |
#inode ⇒ Object
43 44 45 |
# File 'lib/zksync/crypto_file.rb', line 43 def inode @inode ||= archive.file_index.inode_for_path(archive_path) end |
#make_parent_directories(path) ⇒ Object
83 84 85 |
# File 'lib/zksync/crypto_file.rb', line 83 def make_parent_directories(path) FileUtils.mkdir_p(File.dirname(path)) end |
#page_count ⇒ Object
39 40 41 |
# File 'lib/zksync/crypto_file.rb', line 39 def page_count (size.to_f/page_size).ceil end |
#page_matches?(pagefile_path, key) ⇒ Boolean
87 88 89 90 |
# 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) ⇒ Object
51 52 53 54 |
# 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 ⇒ Object
27 28 29 |
# File 'lib/zksync/crypto_file.rb', line 27 def page_physical_size 65536 end |
#page_size ⇒ Object
31 32 33 |
# File 'lib/zksync/crypto_file.rb', line 31 def page_size page_physical_size - Key.write_size - 1 end |
#read ⇒ Object
65 66 67 68 69 |
# 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) ⇒ Object
77 78 79 80 81 |
# 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 ⇒ Object
35 36 37 |
# File 'lib/zksync/crypto_file.rb', line 35 def size inode.size end |
#trim_to_size(size) ⇒ Object
call me before updating inode size ensure excess pages are pruned if a file shrinks
128 129 130 131 132 133 134 135 136 137 |
# 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? ⇒ Boolean
56 57 58 59 60 61 62 63 |
# 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) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# 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) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# 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 |