cURL / Mailing Lists / curl-library / Single Mail

curl-library

AW: libcurl SFTP file upload

From: Mueller, Alexander <am_at_a-m-i.de>
Date: Sat, 5 Apr 2008 10:44:46 +0200

At first thanks to Daniel and Dan for responding, I continued researching.

Dan wrote:

>>>>
As Daniel said, "put" isn't a valid quote command, it's not how to do an upload, and this bug was fixed in 7.18.1. Uploads are done in the normal curl way, e.g.
  curl -u user -T file-to-load sftp://host/absolute/path/new-file
<<<<

This looks for me rather like a command-line call ... I use the C-API and search for a way to do the SFTP Upload with this.
I tried this call (see code below) as quoted command, but also got errors.

>>>>
The SFTP URL scheme is documented at
http://curl.haxx.se/rfc/draft-ietf-secsh-scp-sftp-ssh-uri-04.txt
<<<

I really appreciate your help, but this document didn't clear the scheme for me. When using WinSCP, I can access our host (treuehandy.de) via SFTP, and there I descend down to a subfolder "treuehandy.de" and then to folder "csv", this is the structure how it should work. I tried using the "~" symbol as proposed by Daniel, but this seems to symbolize a "user home directory", it didn't work, ans in WinSCP this was also not necessary so I wonder if this leads to success.

>>>>
They are documented in the curl man page, the curl_easy_setopt man page and curl --manual.
<<<<

I have read the documentation of "curl_easy_setopt(CURLOPT_PREQOUTE / CURLOPT_QOUTE / CURLOPT_POSTQUOTE)" several times, but I still don't get it running. My code example (see below) ran with POSTQUOTE, like in the official FTP upload example. When I run it with "CURLOPT_QOUTE" I get the described infinite loop.

What irritates me most: I cannot find out the "PUT" command. The documentation of curl_easy_setopt(CURLOPT_QOUTE) says: "The valid SFTP commands are: chgrp, chmod, chown, ln, mkdir, pwd, rename, rm, rmdir, symlink. (SFTP support added in 7.16.3)". But these are all no upload commands ! So I tried the documented SFTP-Upload command, "put", with the described infinite loop. So what is the upload command ? The one from Dan (see above) also doesn't work, I tried it in my code which follows.

So, here comes the full code as my experimental state is at this moment (only user name was x-ed out):

STDMETHODIMP CFtpTransfer::Upload(/*[in]*/ BSTR bsFilename, /*[in]*/ BSTR bsSourcePath, /*[in]*/ BSTR bsFtpSiteWithPath,
                                                  /*[in]*/ BSTR bsUser, /*[in]*/ BSTR bsPassword, /*[out]*/ BSTR * pbsFehlermeldung)
{
        USES_CONVERSION;

        *pbsFehlermeldung = NULL;

        HANDLE hFile = NULL;
        char * lpszCurlErrorBuffer[CURL_ERROR_SIZE];
        CURLcode nCurlResult = CURL_LAST;

        curl_global_init(CURL_GLOBAL_ALL);

        CURL * hCurl = curl_easy_init();

        if (!hCurl)
        {
                curl_global_cleanup();
                *pbsFehlermeldung = SysAllocString(L"Fehler bei der Initialisierung der CURL-Library");
                return S_FALSE;
        }

        DWORD dwLastError;

        // Prüfung, ob die zu transferierende Datei existiert, und ich Schreibrecht habe
        {
                wchar_t lpszSourceFileWithPath[256];
                swprintf(lpszSourceFileWithPath, L"%s\\%s", bsSourcePath, bsFilename);
                hFile = CreateFileW(lpszSourceFileWithPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

                dwLastError = GetLastError();

                if (hFile == INVALID_HANDLE_VALUE)
                {
                        wchar_t lpszFehlermeldung[512];
                        swprintf(lpszFehlermeldung, L"Fehler %ld beim Lesen der Datei:\n%s", dwLastError, lpszSourceFileWithPath);
                        *pbsFehlermeldung = SysAllocString(lpszFehlermeldung);
                        curl_global_cleanup();
                        return S_FALSE;
                }
        }

        {
                struct curl_slist * headerlist = NULL;

                wchar_t lpszCommandBuffer[512], lpszTarget[512], lpszUserPassword[256];

                if (SysStringLen(bsFtpSiteWithPath) >= 4)
                {
                        if (_wcsnicmp(bsFtpSiteWithPath, L"SFTP", 4) == 0)
                        {
                                wchar_t lpszSourcePathUnixFormat[512];
                                memset(lpszSourcePathUnixFormat, 0, sizeof(lpszSourcePathUnixFormat));

                                for (unsigned int i = 0; i < SysStringLen(bsSourcePath); i++)
                                        if (bsSourcePath[i] == L'\\')
                                                lpszSourcePathUnixFormat[i] = L'/';
                                        else
                                                lpszSourcePathUnixFormat[i] = bsSourcePath[i];

                                swprintf(lpszCommandBuffer, L"curl -u xxxxxxxx -T C:/test.txt sftp://treuehandy.de/treuehandy.de/csv/test.txt");
                                //swprintf(lpszCommandBuffer, L"put C:/test.txt test.txt");
                                //swprintf(lpszCommandBuffer, L"put %s %s", lpszSourcePathUnixFormat, bsFilename);
                        }
                        else
                                swprintf(lpszCommandBuffer, L"RNFR %s", bsFilename);
                }
                else
                        swprintf(lpszCommandBuffer, L"RNFR %s", bsFilename);

                swprintf(lpszTarget, L"%s/%s", bsFtpSiteWithPath, bsFilename);

                /* enable error buffer */
                curl_easy_setopt(hCurl, CURLOPT_ERRORBUFFER, lpszCurlErrorBuffer) ;
                curl_easy_setopt(hCurl, CURLOPT_VERBOSE , 1);
                curl_easy_setopt(hCurl, CURLOPT_DEBUGFUNCTION, my_curl_debug_callback);

                /* enable uploading */
/* Im Fall von SFTP auskommentieren !*/ curl_easy_setopt(hCurl, CURLOPT_UPLOAD, TRUE) ;
 
                /* specify target */
                //curl_easy_setopt(hCurl, CURLOPT_URL, W2CA(lpszTarget));
                curl_easy_setopt(hCurl, CURLOPT_URL, "sftp://treuehandy.de/treuehandy.de/csv/");
                //curl_easy_setopt(hCurl, CURLOPT_URL, "sftp://treuehandy.de/");
 
                /* build a list of commands to pass to libcurl */
                headerlist = curl_slist_append(headerlist, W2CA(lpszCommandBuffer));
 
                /* we want to use our own read function */
                curl_easy_setopt(hCurl, CURLOPT_READFUNCTION, read_callback);
 
                /* pass in that last of FTP commands to run after the transfer */
                curl_easy_setopt(hCurl, CURLOPT_POSTQUOTE, headerlist);
 
                /* now specify which file to upload */
                curl_easy_setopt(hCurl, CURLOPT_READDATA, hFile);

                swprintf(lpszUserPassword, L"%s:%s", bsUser, bsPassword);
                curl_easy_setopt(hCurl, CURLOPT_USERPWD, W2CA(lpszUserPassword)); // user : password

                // SSL verpflichtend machen
                //curl_easy_setopt(hCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL);

                /* Now run off and do what you've been told! */
                nCurlResult = curl_easy_perform(hCurl);

                /* clean up the FTP commands list */
                curl_slist_free_all (headerlist);

                /* always cleanup */
                curl_easy_cleanup(hCurl);
        }

        CloseHandle(hFile);

        curl_global_cleanup();

        if (nCurlResult == CURLE_OK)
                return S_OK;
        else
        {
                wchar_t lpszFehlermeldung[64];
                swprintf(lpszFehlermeldung, L"FTP-Operation ergab Fehler Nr. %ld", nCurlResult);
                *pbsFehlermeldung = SysAllocString(lpszFehlermeldung);
                return S_FALSE;
        }
}

nCurlResult yields "CULRE_SSH", and this is the debug result:

  Trying 80.67.26.55... connected
Connected to treuehandy.de (80.67.26.55) port 22 (#0)
SSH authentication methods available: publickey,password,keyboard-interactive
Using ssh public key file id_dsa.pub
Using ssh private key file id_dsa
Initialized password authentication
Authentication complete
Upload failed: Operation failed
Connection #0 to host treuehandy.de left intact
Closing connection #0

Thanks for any hint!

Alex
Received on 2008-04-05