1 /*****************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * $Id: ftpuploadresume.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
10 * Upload to FTP, resuming failed transfers
12 * Compile for MinGW like this:
13 * gcc -Wall -pedantic -std=c99 ftpuploadwithresume.c -o ftpuploadresume.exe
16 * Written by Philip Bock
22 #include <curl/curl.h>
24 #if defined(_MSC_VER) && (_MSC_VER < 1300)
25 # error _snscanf requires MSVC 7.0 or later.
28 /* The MinGW headers are missing a few Win32 function definitions,
29 you shouldn't need this if you use VC++ */
31 int __cdecl
_snscanf(const char * input
, size_t length
, const char * format
, ...);
35 /* parse headers for Content-Length */
36 size_t getcontentlengthfunc(void *ptr
, size_t size
, size_t nmemb
, void *stream
) {
40 /* _snscanf() is Win32 specific */
41 r
= _snscanf(ptr
, size
* nmemb
, "Content-Length: %ld\n", &len
);
43 if (r
) /* Microsoft: we don't read the specs */
44 *((long *) stream
) = len
;
49 /* discard downloaded data */
50 size_t discardfunc(void *ptr
, size_t size
, size_t nmemb
, void *stream
) {
54 /* read data to upload */
55 size_t readfunc(void *ptr
, size_t size
, size_t nmemb
, void *stream
)
61 return CURL_READFUNC_ABORT
;
63 n
= fread(ptr
, size
, nmemb
, f
) * size
;
69 int upload(CURL
*curlhandle
, const char * remotepath
, const char * localpath
,
70 long timeout
, long tries
)
73 long uploaded_len
= 0;
74 CURLcode r
= CURLE_GOT_NOTHING
;
77 f
= fopen(localpath
, "rb");
83 curl_easy_setopt(curlhandle
, CURLOPT_UPLOAD
, 1L);
85 curl_easy_setopt(curlhandle
, CURLOPT_URL
, remotepath
);
88 curl_easy_setopt(curlhandle
, CURLOPT_FTP_RESPONSE_TIMEOUT
, timeout
);
90 curl_easy_setopt(curlhandle
, CURLOPT_HEADERFUNCTION
, getcontentlengthfunc
);
91 curl_easy_setopt(curlhandle
, CURLOPT_HEADERDATA
, &uploaded_len
);
93 curl_easy_setopt(curlhandle
, CURLOPT_WRITEFUNCTION
, discardfunc
);
95 curl_easy_setopt(curlhandle
, CURLOPT_READFUNCTION
, readfunc
);
96 curl_easy_setopt(curlhandle
, CURLOPT_READDATA
, f
);
98 curl_easy_setopt(curlhandle
, CURLOPT_FTPPORT
, "-"); /* disable passive mode */
99 curl_easy_setopt(curlhandle
, CURLOPT_FTP_CREATE_MISSING_DIRS
, 1L);
101 curl_easy_setopt(curlhandle
, CURLOPT_VERBOSE
, 1L);
103 for (c
= 0; (r
!= CURLE_OK
) && (c
< tries
); c
++) {
104 /* are we resuming? */
106 /* determine the length of the file already written */
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
116 curl_easy_setopt(curlhandle
, CURLOPT_NOBODY
, 1L);
117 curl_easy_setopt(curlhandle
, CURLOPT_HEADER
, 1L);
119 r
= curl_easy_perform(curlhandle
);
123 curl_easy_setopt(curlhandle
, CURLOPT_NOBODY
, 0L);
124 curl_easy_setopt(curlhandle
, CURLOPT_HEADER
, 0L);
126 fseek(f
, uploaded_len
, SEEK_SET
);
128 curl_easy_setopt(curlhandle
, CURLOPT_APPEND
, 1L);
131 curl_easy_setopt(curlhandle
, CURLOPT_APPEND
, 0L);
134 r
= curl_easy_perform(curlhandle
);
142 fprintf(stderr
, "%s\n", curl_easy_strerror(r
));
147 int main(int c
, char **argv
) {
148 CURL
*curlhandle
= NULL
;
150 curl_global_init(CURL_GLOBAL_ALL
);
151 curlhandle
= curl_easy_init();
153 upload(curlhandle
, "ftp://user:pass@host/path/file", "C:\\file", 0, 3);
155 curl_easy_cleanup(curlhandle
);
156 curl_global_cleanup();