Module: Rmega::Nodes::Downloadable
Instance Method Summary collapse
-
#allocate(path) ⇒ Object
Creates the local file allocating filesize-n bytes (of /dev/zero) for it.
- #allocated?(path) ⇒ Boolean
- #calculate_chunck_mac(data) ⇒ Object
- #decrypt_chunk(start, data) ⇒ Object
- #download(path) ⇒ Object
-
#download_chunk(start, size) ⇒ Object
Downloads a part of the remote file, starting from the start-n byte and ending after size-n bytes.
- #file_io_synchronize(&block) ⇒ Object
- #read_chunk(start, size) ⇒ Object
-
#write_chunk(start, buffer) ⇒ Object
Writes a buffer in the local file, starting from the start-n byte.
Methods included from Options
Methods included from Rmega::Net
#http_get_content, #http_post, #survive
Methods included from Loggable
Instance Method Details
#allocate(path) ⇒ Object
Creates the local file allocating filesize-n bytes (of /dev/zero) for it. Opens the local file to start writing from the beginning of it.
9 10 11 12 13 14 15 16 17 |
# File 'lib/rmega/nodes/downloadable.rb', line 9 def allocate(path) unless allocated?(path) `dd if=/dev/zero of="#{path}" bs=1 count=0 seek=#{filesize} > /dev/null 2>&1` raise "Unable to allocate space for file #{path}" if ::File.size(path) != filesize end @file = ::File.open(path, 'r+b') @file.rewind end |
#allocated?(path) ⇒ Boolean
24 25 26 |
# File 'lib/rmega/nodes/downloadable.rb', line 24 def allocated?(path) ::File.exists?(path) and ::File.size(path) == filesize end |
#calculate_chunck_mac(data) ⇒ Object
63 64 65 66 |
# File 'lib/rmega/nodes/downloadable.rb', line 63 def calculate_chunck_mac(data) mac_iv = @node_key.ctr_nonce * 2 return aes_cbc_mac(@node_key.aes_key, data, mac_iv) end |
#decrypt_chunk(start, data) ⇒ Object
58 59 60 61 |
# File 'lib/rmega/nodes/downloadable.rb', line 58 def decrypt_chunk(start, data) iv = @node_key.ctr_nonce + [start/0x1000000000, start/0x10].pack('l>*') return aes_ctr_decrypt(@node_key.aes_key, data, iv) end |
#download(path) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/rmega/nodes/downloadable.rb', line 68 def download(path) path = ::File.(path) path = Dir.exists?(path) ? ::File.join(path, name) : path progress = Progress.new(filesize, caption: 'Allocate', filename: self.name) pool = Pool.new @resumed_download = allocated?(path) allocate(path) @node_key = NodeKey.load(decrypted_file_key) chunk_macs = {} each_chunk do |start, size| pool.process do data = @resumed_download ? read_chunk(start, size) : nil if data chunk_macs[start] = calculate_chunck_mac(data) if .file_integrity_check progress.increment(size, real: false, caption: "Verify") else data = decrypt_chunk(start, download_chunk(start, size)) chunk_macs[start] = calculate_chunck_mac(data) if .file_integrity_check write_chunk(start, data) progress.increment(size, caption: "Download") end end end # waits for the last running threads to finish pool.shutdown if .file_integrity_check file_mac = aes_cbc_mac(@node_key.aes_key, chunk_macs.sort.map(&:last).join, "\x0"*16) if Utils.compact_to_8_bytes(file_mac) != @node_key. raise("Checksum failed. File corrupted?") end end return nil ensure @file.close rescue nil end |
#download_chunk(start, size) ⇒ Object
Downloads a part of the remote file, starting from the start-n byte and ending after size-n bytes.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/rmega/nodes/downloadable.rb', line 47 def download_chunk(start, size) stop = start + size - 1 url = "#{storage_url}/#{start}-#{stop}" survive do data = http_get_content(url) raise("Unexpected data length") if data.size != size return data end end |
#file_io_synchronize(&block) ⇒ Object
19 20 21 22 |
# File 'lib/rmega/nodes/downloadable.rb', line 19 def file_io_synchronize(&block) @file_io_mutex ||= Mutex.new @file_io_mutex.synchronize(&block) end |
#read_chunk(start, size) ⇒ Object
36 37 38 39 40 41 42 43 |
# File 'lib/rmega/nodes/downloadable.rb', line 36 def read_chunk(start, size) file_io_synchronize do @file.seek(start) data = @file.read(size) @file.seek(start) return (data == "\x0"*size) ? nil : data end end |
#write_chunk(start, buffer) ⇒ Object
Writes a buffer in the local file, starting from the start-n byte.
29 30 31 32 33 34 |
# File 'lib/rmega/nodes/downloadable.rb', line 29 def write_chunk(start, buffer) file_io_synchronize do @file.seek(start) @file.write(buffer) end end |