0

I'm using the Java implementation of SSH, JSCH to do an scp from remote to local. Following the JSCH example code to scpfrom I'm able to receive files. I've used the same implementation as in the above link.

Problem: Compressed files/photos sent are corrupt. Text files appear the same. However, when I send a binary (like a .tgz), the decompresser complains the file is corrupt. I suspect this is a binary vs ascii issue. Is this because of the way I am writing the data to file in Java? How do I properly receive and write binary files using JSCH?

The code I've written -

private void executeCommand(String username, String pwd, String hostname, int port)
        throws JSchException, IOException {
    JSch jSch = new JSch();
    Session session = jSch.getSession(username, hostname, port);
    session.setPassword(pwd);

    Properties properties = new Properties();
    properties.put("StrictHostKeyChecking", "no");
    session.setConfig(properties);

    session.connect();

    ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
    channelExec.setCommand("scp -f /home/rish/haha.txt");

    OutputStream outputStream = channelExec.getOutputStream();
    DataInputStream inputStream = new DataInputStream(channelExec.getInputStream());
    DataOutputStream fos;

    channelExec.connect();

    byte[] buf = new byte[1024];

    buf[0] = 0;
    outputStream.write(buf, 0, 1);
    outputStream.flush();

    while (true) {
        int c = checkAck(inputStream);
        if (c != 'C') {
            break;
        }

        // read '0644 '
        inputStream.read(buf, 0, 5);

        long filesize = 0L;
        while (true) {
            if (inputStream.read(buf, 0, 1) < 0) {
                // error
                break;
            }
            if (buf[0] == ' ') break;
            filesize = filesize * 10L + (long) (buf[0] - '0');
        }

        String file = null;
        for (int i = 0; ; i++) {
            inputStream.read(buf, i, 1);
            if (buf[i] == (byte) 0x0a) {
                file = new String(buf, 0, i);
                break;
            }
        }

        // send '\0'
        buf[0] = 0;
        outputStream.write(buf, 0, 1);
        outputStream.flush();

        // String fileName = "/data/data/" + getPackageName() + "/crearofile" + new Random().nextInt(100) + ".txt";
        String fileName = "/data/data/rish.crearo.trial/haha.txt";

        File file1 = new File(fileName);
        if (file1.exists()) file1.delete();
        if (file1.createNewFile()) Log.d(TAG, "File created");
        else Log.d(TAG, "File not created");

        // read a content of lfile
        fos = new DataOutputStream(new FileOutputStream(fileName));

        String count;
        while ((count = inputStream.readUTF()) != null) {
            System.out.println(count);
            fos.writeBytes(count);
        }
        fos.close();

        if (checkAck(inputStream) != 0) {
            System.exit(0);
        }

        inputStream.close();
        // send '\0'
        buf[0] = 0;
        outputStream.write(buf, 0, 1);
        outputStream.flush();
    }

    session.disconnect();
}
Crearo Rotar
  • 559
  • 7
  • 23
  • To add to the above, I've tried wrapping my inputstreams and outputstreams around a DataInputStream/DataOutputStream. Didn't help! – Crearo Rotar Apr 02 '17 at 16:13
  • Please, provide exact minimum piece of code + data sources / files that reproduces your problem – Ivan Pronin Apr 02 '17 at 16:59
  • Did you see http://stackoverflow.com/questions/40066370/jsch-scp-file-transfer-using-exec-channel? –  Apr 02 '17 at 18:05
  • I've added the code if that will help. Do notice the datainputstream and dataoutputstreams. – Crearo Rotar Apr 02 '17 at 18:06

1 Answers1

0

The code you have posted is not the same as in ScpFrom.java example.

You obviously cannot use inputStream.readUTF() on binary files. UTF is text encoding. Any attempt to interpret binary files using any encoding will corrupt it (or actually in this case, the UTF decoder breaks on binary data, terminating the file transfer prematurely).

Actually that code cannot even work for text files, as you do not check a size of the downloaded data (you never use the filesize value). So you may read beyond the file end. Though it can possibly work by chance, as the UTF decoder may break upon NULL-terminator after the file contents.

(I understand that this was probably actually you attempt to workaround some another problem)

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992