2010-03-19 7 views
3

J'utilise C++ avec libcurl pour effectuer des transferts SFTP/FTPS. Avant de télécharger un fichier, je dois vérifier si le fichier existe sans le télécharger.en utilisant libcurl pour vérifier si un fichier existe sur un site SFTP

Si le fichier n'existe pas, je rencontre les problèmes suivants:

//set up curlhandle for the public/private keys and whatever else first. 
curl_easy_setopt(CurlHandle, CURLOPT_URL, "sftp://[email protected]: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. 

Si je ne l'utilise CURLOPT_NOBODY, cela fonctionne, je reçois CURLE_REMOTE_FILE_NOT_FOUND.

Cependant, si le fichier existe, il est téléchargé, ce qui me fait perdre du temps, puisque je veux juste savoir s'il est là ou non.

Toutes les autres techniques/options qui me manquent? Notez que cela devrait marcher aussi pour les ftps.


Éditer: Cette erreur se produit avec sftp. Avec FTPS/FTP, j'obtiens CURLE_FTP_COULDNT_RETR_FILE, avec lequel je peux travailler.

+0

Avez-vous déjà résolu ce problème? J'ai le même problème. – Lextar

Répondre

0

J'ai trouvé un moyen de faire ce travail. Le concept de base est de tenter de lire le fichier, puis d'annuler l'opération de lecture si le fichier existe, pour éviter de télécharger le fichier entier. Donc, il soit obtenir une erreur renvoyé par cURL pour « fichier n'existe pas », ou « l'écriture de données d'erreur »:

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); 
2

testé ce dans 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 

Cependant, CURLOPT_NOBODY et CURLOPT_HEADER pour SFTP ne renvoie pas une erreur si le fichier n'existe pas dans certaines versions précédentes de libcurl. Une solution alternative pour résoudre ceci:

// 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 
+0

Pourquoi demander 10 octets au lieu de 1 octet? –

+0

@RemyLebeau: Cela n'a pas d'importance. Le but est de télécharger seulement autant pour savoir si le fichier existe. 1 octet ou 10 octets sur un réseau ne fait pratiquement aucune différence. –

+0

@RemyLebeau: En effet, la solution alternative dans sa forme actuelle est imparfaite. S'il s'agit d'un fichier distant de 0 octet, l'erreur renvoyée est CURLE_BAD_DOWNLOAD_RESUME car le décalage spécifié est supérieur à la taille attendue. Modifier ma réponse –