I want to store a binary file using Ruby's Net::FTP class. The content for the file is put into a pipe by a previous process. I need to take the bytes from the pipe (IO class) and store it (on the fly/no temporary file) to the ftp server.
If I do it this way
ftp = Net::FTP.new(@@host, @@user, @@password)
ftp.debug_mode = true
ftp.passive = true
ftp.binary = true
ftp.storbinary("STOR #{name}", pipe, Net::FTP::DEFAULT_BLOCKSIZE)
ftp.close
the size of the stored file is about 500kb smaller than it should be (correct size is about 6,8 MB). The file contains gpg encrypted data. If try to decrypt, I get an error.
Storing directly from the pipe to a local file results in a file with right size and working decryption.
I'm relatively new to ruby, can someone give me a hint? Some idea for debugging? Can I provide additional informations?
Thanks for your help
Debug output from Net::FTP:
put: PASV
get: 227 Entering Passive Mode (80,237,136,162,233,60).
put: STOR test-ftp.tar.gz.gpg
get: 150 Opening BINARY mode data connection for test-ftp.tar.gz.gpg
get: 226 Transfer complete
Ruby version: ruby 2.1.5p273
OS: debian linux
Environment: ruby script is executed directly from bash
Some more code:
p_out, p_in = IO.pipe
@@thread = Thread.new {
cmd = "gpg --no-tty --cipher-algo AES256 --compress-level 0 --passphrase-file #{@@cmd.results[:gpg_passphrase_file]} --symmetric"
# Execute gpg
Open3.popen3 ( cmd ) { |stdin, stdout, stderr, wait_thr|
Thread.new {
cnt = IO::copy_stream pipe, stdin
@@output.debug "GPG_Encryption::execute copied #{(Float(cnt)/1024/1024).round(2)} MiB bytes to gpg"
pipe.close
stdin.close
}
Thread.new {
cnt = IO::copy_stream stdout, p_in
@@output.debug "GPG_Encryption::execute copied #{(Float(cnt)/1024/1024).round(2)} MiB bytes from gpg"
}
# wait for gpg finished
wait_thr.join
# Close pipe (sends eof)
p_in.close
# check result
if 0 == wait_thr.value
@@output.info "gpg finished..."
else
@@output.error "gpg returned an error"
@@output.raw stderr.readlines.join
exit 1
end
}
}
ftp = Net::FTP.new(@@host, @@user, @@password)
ftp.debug_mode = true
ftp.passive = true
ftp.binary = true
ftp.storbinary("STOR #{name}", pipe, Net::FTP::DEFAULT_BLOCKSIZE)
ftp.close