1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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 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#include "setup.h" 23 24#include <curl/curl.h> 25 26#define ENABLE_CURLX_PRINTF 27/* use our own printf() functions */ 28#include "curlx.h" 29 30#include "tool_cfgable.h" 31#include "tool_msgs.h" 32#include "tool_cb_wrt.h" 33 34#include "memdebug.h" /* keep this as LAST include */ 35 36/* 37** callback for CURLOPT_WRITEFUNCTION 38*/ 39 40size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) 41{ 42 size_t rc; 43 struct OutStruct *outs = userdata; 44 struct Configurable *config = outs->config; 45 46 /* 47 * Once that libcurl has called back tool_write_cb() the returned value 48 * is checked against the amount that was intended to be written, if 49 * it does not match then it fails with CURLE_WRITE_ERROR. So at this 50 * point returning a value different from sz*nmemb indicates failure. 51 */ 52 const size_t failure = (sz * nmemb) ? 0 : 1; 53 54 if(!config) 55 return failure; 56 57#ifdef DEBUGBUILD 58 if(config->include_headers) { 59 if(sz * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { 60 warnf(config, "Header data size exceeds single call write limit!\n"); 61 return failure; 62 } 63 } 64 else { 65 if(sz * nmemb > (size_t)CURL_MAX_WRITE_SIZE) { 66 warnf(config, "Data size exceeds single call write limit!\n"); 67 return failure; 68 } 69 } 70 71 { 72 /* Some internal congruency checks on received OutStruct */ 73 bool check_fails = FALSE; 74 if(outs->filename) { 75 /* regular file */ 76 if(!*outs->filename) 77 check_fails = TRUE; 78 if(!outs->s_isreg) 79 check_fails = TRUE; 80 if(outs->fopened && !outs->stream) 81 check_fails = TRUE; 82 if(!outs->fopened && outs->stream) 83 check_fails = TRUE; 84 if(!outs->fopened && outs->bytes) 85 check_fails = TRUE; 86 } 87 else { 88 /* standard stream */ 89 if(!outs->stream || outs->s_isreg || outs->fopened) 90 check_fails = TRUE; 91 if(outs->alloc_filename || outs->init) 92 check_fails = TRUE; 93 } 94 if(check_fails) { 95 warnf(config, "Invalid output struct data for write callback\n"); 96 return failure; 97 } 98 } 99#endif 100 101 if(!outs->stream) { 102 FILE *file; 103 104 if(!outs->filename || !*outs->filename) { 105 warnf(config, "Remote filename has no length!\n"); 106 return failure; 107 } 108 109 if(config->content_disposition) { 110 /* don't overwrite existing files */ 111 file = fopen(outs->filename, "rb"); 112 if(file) { 113 fclose(file); 114 warnf(config, "Refusing to overwrite %s: %s\n", outs->filename, 115 strerror(EEXIST)); 116 return failure; 117 } 118 } 119 120 /* open file for writing */ 121 file = fopen(outs->filename, "wb"); 122 if(!file) { 123 warnf(config, "Failed to create the file %s: %s\n", outs->filename, 124 strerror(errno)); 125 return failure; 126 } 127 outs->s_isreg = TRUE; 128 outs->fopened = TRUE; 129 outs->stream = file; 130 outs->bytes = 0; 131 outs->init = 0; 132 } 133 134 rc = fwrite(buffer, sz, nmemb, outs->stream); 135 136 if((sz * nmemb) == rc) 137 /* we added this amount of data to the output */ 138 outs->bytes += (sz * nmemb); 139 140 if(config->readbusy) { 141 config->readbusy = FALSE; 142 curl_easy_pause(config->easy, CURLPAUSE_CONT); 143 } 144 145 if(config->nobuffer) { 146 /* output buffering disabled */ 147 int res = fflush(outs->stream); 148 if(res) 149 return failure; 150 } 151 152 return rc; 153} 154 155