Home | History | Annotate | Download | only in examples
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at http://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 /* Upload to FTP, resuming failed transfers
     23  *
     24  * Compile for MinGW like this:
     25  *  gcc -Wall -pedantic -std=c99 ftpuploadwithresume.c -o ftpuploadresume.exe
     26  *  -lcurl -lmsvcr70
     27  *
     28  * Written by Philip Bock
     29  */
     30 
     31 #include <stdlib.h>
     32 #include <stdio.h>
     33 
     34 #include <curl/curl.h>
     35 
     36 #if defined(_MSC_VER) && (_MSC_VER < 1300)
     37 #  error _snscanf requires MSVC 7.0 or later.
     38 #endif
     39 
     40 /* The MinGW headers are missing a few Win32 function definitions,
     41    you shouldn't need this if you use VC++ */
     42 #if defined(__MINGW32__) && !defined(__MINGW64__)
     43 int __cdecl _snscanf(const char * input, size_t length, const char * format, ...);
     44 #endif
     45 
     46 
     47 /* parse headers for Content-Length */
     48 size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream)
     49 {
     50   int r;
     51   long len = 0;
     52 
     53   /* _snscanf() is Win32 specific */
     54   r = _snscanf(ptr, size * nmemb, "Content-Length: %ld\n", &len);
     55 
     56   if (r) /* Microsoft: we don't read the specs */
     57     *((long *) stream) = len;
     58 
     59   return size * nmemb;
     60 }
     61 
     62 /* discard downloaded data */
     63 size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *stream)
     64 {
     65   return size * nmemb;
     66 }
     67 
     68 /* read data to upload */
     69 size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
     70 {
     71   FILE *f = stream;
     72   size_t n;
     73 
     74   if (ferror(f))
     75     return CURL_READFUNC_ABORT;
     76 
     77   n = fread(ptr, size, nmemb, f) * size;
     78 
     79   return n;
     80 }
     81 
     82 
     83 int upload(CURL *curlhandle, const char * remotepath, const char * localpath,
     84            long timeout, long tries)
     85 {
     86   FILE *f;
     87   long uploaded_len = 0;
     88   CURLcode r = CURLE_GOT_NOTHING;
     89   int c;
     90 
     91   f = fopen(localpath, "rb");
     92   if (f == NULL) {
     93     perror(NULL);
     94     return 0;
     95   }
     96 
     97   curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);
     98 
     99   curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);
    100 
    101   if (timeout)
    102     curl_easy_setopt(curlhandle, CURLOPT_FTP_RESPONSE_TIMEOUT, timeout);
    103 
    104   curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
    105   curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &uploaded_len);
    106 
    107   curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, discardfunc);
    108 
    109   curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);
    110   curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);
    111 
    112   curl_easy_setopt(curlhandle, CURLOPT_FTPPORT, "-"); /* disable passive mode */
    113   curl_easy_setopt(curlhandle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
    114 
    115   curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);
    116 
    117   for (c = 0; (r != CURLE_OK) && (c < tries); c++) {
    118     /* are we resuming? */
    119     if (c) { /* yes */
    120       /* determine the length of the file already written */
    121 
    122       /*
    123        * With NOBODY and NOHEADER, libcurl will issue a SIZE
    124        * command, but the only way to retrieve the result is
    125        * to parse the returned Content-Length header. Thus,
    126        * getcontentlengthfunc(). We need discardfunc() above
    127        * because HEADER will dump the headers to stdout
    128        * without it.
    129        */
    130       curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 1L);
    131       curl_easy_setopt(curlhandle, CURLOPT_HEADER, 1L);
    132 
    133       r = curl_easy_perform(curlhandle);
    134       if (r != CURLE_OK)
    135         continue;
    136 
    137       curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 0L);
    138       curl_easy_setopt(curlhandle, CURLOPT_HEADER, 0L);
    139 
    140       fseek(f, uploaded_len, SEEK_SET);
    141 
    142       curl_easy_setopt(curlhandle, CURLOPT_APPEND, 1L);
    143     }
    144     else { /* no */
    145       curl_easy_setopt(curlhandle, CURLOPT_APPEND, 0L);
    146     }
    147 
    148     r = curl_easy_perform(curlhandle);
    149   }
    150 
    151   fclose(f);
    152 
    153   if (r == CURLE_OK)
    154     return 1;
    155   else {
    156     fprintf(stderr, "%s\n", curl_easy_strerror(r));
    157     return 0;
    158   }
    159 }
    160 
    161 int main(int c, char **argv)
    162 {
    163   CURL *curlhandle = NULL;
    164 
    165   curl_global_init(CURL_GLOBAL_ALL);
    166   curlhandle = curl_easy_init();
    167 
    168   upload(curlhandle, "ftp://user:pass@example.com/path/file", "C:\\file", 0, 3);
    169 
    170   curl_easy_cleanup(curlhandle);
    171   curl_global_cleanup();
    172 
    173   return 0;
    174 }
    175