curl-library
AW: libcurl SFTP file upload
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