3

libcurl で C++ を使用して SFTP/FTPS 転送を行っています。ファイルをアップロードする前に、実際にダウンロードせずにファイルが存在するかどうかを確認する必要があります。

ファイルが存在しない場合、次の問題が発生します。

//set up curlhandle for the public/private keys and whatever else first.
curl_easy_setopt(CurlHandle, CURLOPT_URL, "sftp://user@pass:host/nonexistent-file");
curl_easy_setopt(CurlHandle, CURLOPT_NOBODY, 1);
curl_easy_setopt(CurlHandle, CURLOPT_FILETIME, 1);
int result = curl_easy_perform(CurlHandle); 
//result is CURLE_OK, not CURLE_REMOTE_FILE_NOT_FOUND
//using curl_easy_getinfo to get the file time will return -1 for filetime, regardless
//if the file is there or not.

CURLOPT_NOBODY を使用しない場合は動作しますが、CURLE_REMOTE_FILE_NOT_FOUND が発生します。

ただし、ファイルが存在する場合はダウンロードされ、そこにあるかどうかを知りたいだけなので、時間が無駄になります。

私が見逃している他のテクニック/オプションはありますか? ftps でも機能するはずであることに注意してください。


編集: このエラーは sftp で発生します。FTPS/FTP を使用すると、作業できる CURLE_FTP_COULDNT_RETR_FILE を取得できます。

4

2 に答える 2

2

libcurl 7.38.0 でこれをテストしました

curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_HEADER, 1L);

CURLcode iRc = curl_easy_perform(curl);

if (iRc == CURLE_REMOTE_FILE_NOT_FOUND)
  // File doesn't exist
else if (iRc == CURLE_OK)
  // File exists

ただし、以前のバージョンの libcurl にファイルが存在しない場合、SFTP の CURLOPT_NOBODY および CURLOPT_HEADER はエラーを返しません。これを解決する別の解決策:

// Ask for the first byte
curl_easy_setopt(curl, CURLOPT_RANGE,
    (const char *)"0-0");

CURLcode iRc = curl_easy_perform(curl);

if (iRc == CURLE_REMOTE_FILE_NOT_FOUND)
  // File doesn't exist
else if (iRc == CURLE_OK || iRc == CURLE_BAD_DOWNLOAD_RESUME)
  // File exists
于 2015-05-21T18:09:49.570 に答える
0

これを機能させる方法を見つけました。基本的な概念は、ファイルの読み取りを試行し、ファイルが存在する場合は読み取り操作を中止して、ファイル全体のダウンロードを回避することです。そのため、cURL から「ファイルが存在しません」または「データの書き込みエラー」というエラーが返されます。

static size_t abort_read(void *ptr, size_t size, size_t nmemb, void *data)
{
  (void)ptr;
  (void)data;
  /* we are not interested in the data itself,
     so we abort operation ... */ 
  return (size_t)(-1); // produces CURLE_WRITE_ERROR
}
....
curl_easy_setopt(curl,CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, abort_read);
CURLcode res = curl_easy_perform(curl);
/* restore options */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(curl, CURLOPT_URL, NULL);
return (res==CURLE_WRITE_ERROR);
于 2014-01-20T16:09:56.473 に答える