C# SFTP Upload from Byte[]

This example demonstrates how to open a remote file on an SSH/SFTP server,
write to the file, and then close it.  This is analogous to opening a local file,
writing to it, and closing it.  The SFTP protocol (i.e. Secure File Transfer over SSH),
follows the same concepts as typical file I/O programming -- i.e. open a file,
read, write, close, etc.).

// Assume at this point we already have a Chilkat.SFtp object
// connected to a server, authenticated, and InitializeSftp has
// already been called..


// To upload a binary file from Byte[], the procedure is to open the remote file,
// write the data, and then close the file.

// Open a remote file, returning a handle to the open file.
string handle = sftp.OpenFile("test.dat", "readWrite", "createTruncate");
if (!sftp.LastMethodSuccess)
    {
    textBox2.Text = sftp.LastErrorText;
    return;
    }

string text = "To live is the rarest thing in the world. Most people exist, that is all. -- Oscar Wilde\r\n";
byte[] bytes= System.Text.Encoding.UTF8.GetBytes(text);

// Write some data to the file.
bool success;
for (int i = 0; i < 20; i++)
    {
    // It is possible to write bytes:
    success = sftp.WriteFileBytes(handle, bytes);
    // It is also possible to write the string:
    if (success) success = sftp.WriteFileText(handle, "utf-8", text);

    if (!success)
        {
        textBox2.Text = sftp.LastErrorText;
        return;
        }
    }

// Close the remote file.
if (!sftp.CloseHandle(handle))
    {
    textBox2.Text = sftp.LastErrorText;
    return;
    }
 

How to know that SFTP Upload was Transferred Successfully?

Question:

In the online reference documentation, it says that “bool UploadFileByName(string remoteFilePath, string localFilePath)” will return true if success or false for failure.

My question is that how does your component know that the file had been transferred successfully? Does it get ACK from SFTP server or that only means that client had sent the file successfully but not guarantee that SFTP server had received the file successfully?

Answer:

The SFTP Specifications are such that each data packet must be acknowledged by the server with a response message.  The upload is successful after all packets have been sent and all responses (acks) have been received.

SFTP vs. FTPS

Clarification on the acronyms “SFTP” and “FTPS”

“SFTP” is the Secure File Transfer Protocol over SSH.  It is a protocol unrelated to the FTP protocol. (It is actually a subsystem of SSH.)  The Chilkat SSH / SFTP component is used for “SFTP”.  SFTP is achieved by connecting to an SSH server at port 22.

On the other hand, the Chilkat FTP2 component is for FTP.   FTP servers listen at port 21 (non-SSL/TLS) and port 990 (SSL).  FTP over SSL (i.e. port 990) is called “FTPS”.

SSH/SFTP RemoveFile: “Permission Denied”

If the SFTP server responds to a request to delete a file with the error “Permission Denied”, it means the SSH/SFTP user account does not have permission to delete the file. Here is a sample LastErrorText that shows the path of the remote file to be deleted, and the “Permission Denied” response from the server.

ChilkatLog:
  RemoveFile:
    DllDate: Jan 19 2012
    UnlockPrefix: abcxyz
    Username: abcxyz
    Architecture: Little Endian; 64-bit
    Language: .NET 2.0 / x64
    SshVersion: SSH-2.0-CoreFTP-0.2.3
    SftpVersion: 3
    filename: /something1/something2/something.dat
    StatusResponse:
      Request: FXP_REMOVE
      StatusCode: 3
      StatusMessage: Permission denied
    Failed.

The LastErrorText shows the exact path of the file passed to the server.  In the case above, it is an absolute path.  If a relative path was passed, it would be relative to the HOME directory of the SSH/SFTP user account.  The “Permission denied” response from the server indicates that the FXP_REMOVE message was properly formatted and correctly sent to the server.  It was received correctly by the server, but the SSH/SFTP user account does not have permission to delete the requested file.  The fix to this problem is not on the client-side (unless a mistake in the file path was made).  The fix is on the server-side to give the SSH/SFTP user account permission to delete the requested file.

SFTP Open: The meaning of “No Such File”

When an SSH/SFTP server responds to a file open request with the error message “No Such File”, it means that it could not find the file (i.e. there was no such file).

This is a snippet from the LastErrorText property:

...
    OpenRemoteFile:
      filename: something.dat
      access: readOnly
      createDisposition: openExisting
      v3Flags: 0x1
      Sent FXP_OPEN
      StatusResponse:
        Request: FXP_OPEN
        StatusCode: 2
        StatusMessage: No such file
...

If a relative path is used, then the path is relative to the HOME directory of the SSH/SFTP user account.  In the case above, only a filename is provided, and therefore the SSH/SFTP server is expecting to find “something.dat” in the HOME directory of the SSH/SFTP user account.  If the file is not there, the response will be “No Such File”.

If an absolute path is used (i.e. a path starting with “/”), then it is a request to open that exact absolute path (relative to the filesystem’s root “/” directory).  It is likely that if the path is not under the SSH/SFTP user’s home directory, the server will not have permission to access the file and the error returned will be “No Permission” (or something pertaining to not having permission to access a file or directory..)

SFTP Permission Denied w/ OpenFile Method

Question:

We are trying to upload a file to SFTP using private key. We are able to connect and retrieve folder listing. But when we try to upload to one of the folder on the SFTP we get the “Permission denied” error message.

The message is as below.

ChilkatLog:
  OpenFile:
    DllDate: Feb 15 2010
    UnlockPrefix: ****
    Username: joe
    Component: .NET 2.0
    SshVersion: SSH-1.99-OpenSSH_3.8p1
    SftpVersion: 3
    filename: .\Upload\myFiles\test.xml
    access: writeOnly
    createDisposition: createNew
    v3Flags: 0x2a
    Sent FXP_OPEN
    StatusResponse:
      Request: FXP_OPEN
      StatusCode: 3
      StatusMessage: Permission denied
    SshLog:
SFTP> Sending SSH_FXP_OPEN
TRAN> CHANNEL_DATA
TRAN* NumBytes: 44
TRAN< CHANNEL_DATA
SFTP< Received SSH_FXP_STATUS

Answer:

The content of the LastErrorText property (as shown above) provides good information that allows me to suggest some things to try:

  1. I can see by the “DllDate” that the version being used is older.  I would highly recommend updating to the latest version to ensure you’re getting the best information in LastErrorText.  The information in LastErrorText is always being refined and improvedd as Chilkat does user-support day-to-day.
  2. The createDisposition passed to OpenFile in this case is “createNew”.  If the file already exists, then the OpenFile will fail.  It’s possible that the server will indicate the failure as a “Permission denied” error.  Instead, use “createTruncate” for the createDisposition argument.
  3. I see that backslashes are used in the remote file path.  Try using forward slashes instead.
  4. To fully understand the absolute file path of the destination file on the SSH/SFTP server, call RealPath to ask the server to convert a relative path to an absolute path.  Maybe the SSH/SFTP user account’s home directory is something different than expected.

SFTP OpenFile Succeeds, but ReadFileBytes Fails

SSH/SFTP servers are notoriously bad at providing any sort of useful information about the cause of a problem. This is one of those cases. It was discovered that for one particular server, if a remote file is opened (via the OpenFile method) using “readWrite” access, then the OpenFile succeeds, but a subsequent call to a method such as ReadFileBytes fails. The only information from the server is an error code “10”. Gee, thanks! What the #@!$%! is an error code “10”??? (Usually an SSH server will also provide a short and utterly useless 1-line error description, but this particular server was too lazy to even do that.)

In the end, after fiddling around with different access and disposition choices, it was found that using “readOnly” for the access and “openExisting” for the create disposition solved the problem.