Search code examples
javasftpj2ssh

sshtools.SftpClient.put failing with "No such file"


I've inherited a Java based project that includes a cron job to upload a file via SFTP to a third-party server. Here's the relevant code.

String filePath = IUtil.getInstance().getProperties("cheetah_sftp_filepath");
try{
    SshClient ssh = new SshClient();
    ssh.connect(host, port);
    //Authenticate
    PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
    passwordAuthenticationClient.setUsername(userName);
    passwordAuthenticationClient.setPassword(password);
    int result = ssh.authenticate(passwordAuthenticationClient);
    if(result != AuthenticationProtocolState.COMPLETE){
         throw new Exception("Login to " + host + ":" + port + " " + userName + "/" + password + " failed");
    }
    //Open the SFTP channel
    SftpClient client = ssh.openSftpClient();
    client.cd("autoproc");
    client.put(filePath);
    //disconnect
    client.quit();
    ssh.disconnect();
} catch(Exception e) {
    String message = "Failed during sftp: " + e.getMessage();
    addJobMessage(message, JobMessageType.JOB_MESSAGE_TYPE_ERROR);
    e.printStackTrace();
    return false;
}

Pretty straightforward, but it's not working. When client.put() executes, it fails with "java.io.IOException: No such file". Here's the stack trace.

java.io.IOException: No such file
    at com.sshtools.j2ssh.sftp.SftpSubsystemClient.getOKRequestStatus(Unknown Source)
    at com.sshtools.j2ssh.sftp.SftpSubsystemClient.setAttributes(Unknown Source)
    at com.sshtools.j2ssh.sftp.SftpSubsystemClient.changePermissions(Unknown Source)
    at com.sshtools.j2ssh.SftpClient.chmod(Unknown Source)
    at com.sshtools.j2ssh.SftpClient.put(Unknown Source)
    at com.sshtools.j2ssh.SftpClient.put(Unknown Source)
    at com.sshtools.j2ssh.SftpClient.put(Unknown Source)
    at com.sshtools.j2ssh.SftpClient.put(Unknown Source)
    at com.dez.store.scripts.SendEmailShellCommand.sftpToCheetah(SendEmailToCheetahShellCommand.java:99)
    at com.dez.store.scripts.SendEmailShellCommand.execute(SendEmailToCheetahShellCommand.java:34)
    at com.fry.ocp.common.ShellCommandExecutor.main(ShellCommandExecutor.java:90)

filePath is an absolute path to the file. Yes, I've checked the obvious: the path is correct and the file exists. File permissions are 664 so a read shouldn't be failing in any case, but the process is running as root to boot.

I've tried everything I can think of.

  • I've checked read permissions all the way up the directory tree (which is kind of deep).
  • I've tried lcd() to the directory and once I get there lpwd(). That seems fine, but put still fails so a long path name doesn't seem to be the issue.
  • I double checked to make sure the file streams that originally wrote the file were all being closed correctly. I don't see anything that makes me think that could be the issue.
  • I tried creating and instance of j2ssh.sftp.SftpFile with the full path to see if it could access the file and make sure the "No such file" error wasn't related to the remote host. When I execute SftpFile.canRead() I get a null pointer exception, so I'm thinking it's a local problem.

I haven't touched Java in years. To say that I am rusty would be a gross understatement. However, our last "Java guy" just quit and I'm the only person left in my shop who has touched Java ever, so I'm the new "Java guy".

Am I missing something simple? Any other ideas?

-Sean


Solution

  • From the callstack and your description, I would expect the error refers to the remote file.

    The chmod has to be done only after the transfer completes, so I assume the SftpClient believes the transfer is done and it tries to update the remote file permissions. And it seems like it fails, because the file is actually not there. Once you get the error, use SftpClient.ls(), to check, if the file is there. Chances are that you have some remote-side process that takes the file away the moment the upload finishes.

    As a workaround, you can also try to prevent the SftpClient trying to modify the permissions after the upload finishes. I do not know J2SSH. Having a quick look, I have not found any API for this though. Maybe the SftpClient.umask().

    You can try to switch to JSch. It does not seem to do implicit chmod after upload.

    Also it's worth checking the remote server log.