1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@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 https://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 /* <DESC> 23 * Upload to FTP, resuming failed transfers. 24 * </DESC> 25 */ 26 27 #include <stdlib.h> 28 #include <stdio.h> 29 #include <curl/curl.h> 30 31 /* parse headers for Content-Length */ 32 static size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, 33 void *stream) 34 { 35 int r; 36 long len = 0; 37 38 r = sscanf(ptr, "Content-Length: %ld\n", &len); 39 if(r) 40 *((long *) stream) = len; 41 42 return size * nmemb; 43 } 44 45 /* discard downloaded data */ 46 static size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *stream) 47 { 48 (void)ptr; 49 (void)stream; 50 return size * nmemb; 51 } 52 53 /* read data to upload */ 54 static size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream) 55 { 56 FILE *f = stream; 57 size_t n; 58 59 if(ferror(f)) 60 return CURL_READFUNC_ABORT; 61 62 n = fread(ptr, size, nmemb, f) * size; 63 64 return n; 65 } 66 67 68 static int upload(CURL *curlhandle, const char *remotepath, 69 const char *localpath, long timeout, long tries) 70 { 71 FILE *f; 72 long uploaded_len = 0; 73 CURLcode r = CURLE_GOT_NOTHING; 74 int c; 75 76 f = fopen(localpath, "rb"); 77 if(!f) { 78 perror(NULL); 79 return 0; 80 } 81 82 curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L); 83 84 curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath); 85 86 if(timeout) 87 curl_easy_setopt(curlhandle, CURLOPT_FTP_RESPONSE_TIMEOUT, timeout); 88 89 curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc); 90 curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &uploaded_len); 91 92 curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, discardfunc); 93 94 curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc); 95 curl_easy_setopt(curlhandle, CURLOPT_READDATA, f); 96 97 /* disable passive mode */ 98 curl_easy_setopt(curlhandle, CURLOPT_FTPPORT, "-"); 99 curl_easy_setopt(curlhandle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L); 100 101 curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L); 102 103 for(c = 0; (r != CURLE_OK) && (c < tries); c++) { 104 /* are we resuming? */ 105 if(c) { /* yes */ 106 /* determine the length of the file already written */ 107 108 /* 109 * With NOBODY and NOHEADER, libcurl will issue a SIZE 110 * command, but the only way to retrieve the result is 111 * to parse the returned Content-Length header. Thus, 112 * getcontentlengthfunc(). We need discardfunc() above 113 * because HEADER will dump the headers to stdout 114 * without it. 115 */ 116 curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 1L); 117 curl_easy_setopt(curlhandle, CURLOPT_HEADER, 1L); 118 119 r = curl_easy_perform(curlhandle); 120 if(r != CURLE_OK) 121 continue; 122 123 curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 0L); 124 curl_easy_setopt(curlhandle, CURLOPT_HEADER, 0L); 125 126 fseek(f, uploaded_len, SEEK_SET); 127 128 curl_easy_setopt(curlhandle, CURLOPT_APPEND, 1L); 129 } 130 else { /* no */ 131 curl_easy_setopt(curlhandle, CURLOPT_APPEND, 0L); 132 } 133 134 r = curl_easy_perform(curlhandle); 135 } 136 137 fclose(f); 138 139 if(r == CURLE_OK) 140 return 1; 141 else { 142 fprintf(stderr, "%s\n", curl_easy_strerror(r)); 143 return 0; 144 } 145 } 146 147 int main(void) 148 { 149 CURL *curlhandle = NULL; 150 151 curl_global_init(CURL_GLOBAL_ALL); 152 curlhandle = curl_easy_init(); 153 154 upload(curlhandle, "ftp://user:pass@example.com/path/file", "C:\\file", 155 0, 3); 156 157 curl_easy_cleanup(curlhandle); 158 curl_global_cleanup(); 159 160 return 0; 161 } 162