cURL / Mailing Lists / curl-library / Single Mail


AW: libcurl SFTP file upload

From: Mueller, Alexander <>
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

I really appreciate your help, but this document didn't clear the scheme for me. When using WinSCP, I can access our host ( via SFTP, and there I descend down to a subfolder "" 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)

        *pbsFehlermeldung = NULL;

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


        CURL * hCurl = curl_easy_init();

        if (!hCurl)
                *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);
                        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'/';
                                                lpszSourcePathUnixFormat[i] = bsSourcePath[i];

                                swprintf(lpszCommandBuffer, L"curl -u xxxxxxxx -T C:/test.txt s");
                                //swprintf(lpszCommandBuffer, L"put C:/test.txt test.txt");
                                //swprintf(lpszCommandBuffer, L"put %s %s", lpszSourcePathUnixFormat, bsFilename);
                                swprintf(lpszCommandBuffer, L"RNFR %s", bsFilename);
                        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, "s");
                //curl_easy_setopt(hCurl, CURLOPT_URL, "s");
                /* 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 */



        if (nCurlResult == CURLE_OK)
                return S_OK;
                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 connected
Connected to ( port 22 (#0)
SSH authentication methods available: publickey,password,keyboard-interactive
Using ssh public key file
Using ssh private key file id_dsa
Initialized password authentication
Authentication complete
Upload failed: Operation failed
Connection #0 to host left intact
Closing connection #0

Thanks for any hint!

Received on 2008-04-05