9 #include "libwfut/IO.h" 10 #include "libwfut/Encoder.h" 11 #include "libwfut/platform.h" 19 static const bool debug =
false;
23 static int createParentDirs(
const std::string &filename) {
27 size_t pos = filename.find_last_of(
"\\/");
30 if (pos == std::string::npos || pos == 0)
return 0;
32 const std::string &path = filename.substr(0, pos);
34 if ((err = createParentDirs(path))) {
40 DIR *d = opendir(path.c_str());
51 static int copy_file(FILE *fp,
const std::string &target_filename) {
53 if (createParentDirs(target_filename)) {
55 fprintf(stderr,
"There was an error creating the required directory tree for %s.\n", target_filename.c_str());
58 FILE *tp = fopen(target_filename.c_str(),
"wb");
68 while ((num = fread(buf,
sizeof(
char), 1024, fp)) != 0) {
69 fwrite(buf,
sizeof(
char), num, tp);
81 static size_t write_data(
void *buffer,
size_t size,
size_t nmemb,
void *userp) {
82 assert(userp != NULL);
83 DataStruct *ds =
reinterpret_cast<DataStruct*
>(userp);
88 ds->fp = os_create_tmpfile();
91 fprintf(stderr,
"Error opening file for writing\n");
95 ds->actual_crc32 = crc32(0L, Z_NULL, 0);
98 assert(ds->fp != NULL);
101 ds->actual_crc32 = crc32(ds->actual_crc32, reinterpret_cast<Bytef*>(buffer), size * nmemb);
104 return fwrite(buffer, size, nmemb, ds->fp);
110 static int setDefaultOpts(CURL *handle) {
111 curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
112 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
113 curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
118 assert (m_initialised ==
false);
120 curl_global_init(CURL_GLOBAL_ALL);
122 m_mhandle = curl_multi_init();
123 #ifdef HAVE_CURL_MULTI_PIPELINING 124 curl_multi_setopt(m_mhandle, CURLMOPT_PIPELINING, 1);
127 m_initialised =
true;
133 assert (m_initialised ==
true);
135 curl_multi_cleanup(m_mhandle);
138 while (!m_files.empty()) {
142 curl_easy_cleanup(ds->handle);
150 m_files.erase(m_files.begin());
153 curl_global_cleanup();
155 m_initialised =
false;
160 int IO::downloadFile(
const std::string &filename,
const std::string &url, uLong expected_crc32) {
165 ds.filename = filename;
166 ds.executable =
false;
167 ds.actual_crc32 = crc32(0L, Z_NULL, 0);
168 ds.expected_crc32 = expected_crc32;
169 ds.handle = curl_easy_init();
171 setDefaultOpts(ds.handle);
172 curl_easy_setopt(ds.handle, CURLOPT_URL, ds.url.c_str());
173 curl_easy_setopt(ds.handle, CURLOPT_WRITEDATA, &ds);
175 CURLcode err = curl_easy_perform(ds.handle);
182 if (copy_file(ds.fp, ds.filename) == 0) {
187 if (ds.fp) fclose(ds.fp);
188 curl_easy_cleanup(ds.handle);
199 ds.executable =
false;
201 ds.actual_crc32 = crc32(0L, Z_NULL, 0);
202 ds.expected_crc32 = expected_crc32;
203 ds.handle = curl_easy_init();
205 setDefaultOpts(ds.handle);
206 curl_easy_setopt(ds.handle, CURLOPT_URL, ds.url.c_str());
207 curl_easy_setopt(ds.handle, CURLOPT_WRITEDATA, &ds);
208 CURLcode err = curl_easy_perform(ds.handle);
210 curl_easy_cleanup(ds.handle);
221 int IO::queueFile(
const std::string &path,
const std::string &filename,
const std::string &url, uLong expected_crc32,
bool executable) {
222 if (m_files.find(url) != m_files.end()) {
223 fprintf(stderr,
"Error file is already in queue\n");
231 ds->filename = filename;
233 ds->executable = executable;
234 ds->actual_crc32 = crc32(0L, Z_NULL, 0);
235 ds->expected_crc32 = expected_crc32;
236 ds->handle = curl_easy_init();
238 m_files[ds->url] = ds;
239 setDefaultOpts(ds->handle);
240 curl_easy_setopt(ds->handle, CURLOPT_URL, ds->url.c_str());
241 curl_easy_setopt(ds->handle, CURLOPT_WRITEDATA, ds);
242 curl_easy_setopt(ds->handle, CURLOPT_PRIVATE, ds);
246 m_handles.push_back(ds->handle);
254 curl_multi_perform(m_mhandle, &num_handles);
256 struct CURLMsg *msg = NULL;
260 while ((msg = curl_multi_info_read(m_mhandle, &msgs)) != NULL) {
263 int err = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &ds);
264 if (err != CURLE_OK) {
266 fprintf(stderr,
"Got some error on curl_easy_getinfo (%d)\n", err);
271 std::string errormsg =
"Unknown failure";
274 if (msg->data.result == CURLE_OK) {
276 if (ds->expected_crc32 == 0L ||
277 ds->expected_crc32 == ds->actual_crc32) {
281 if (copy_file(ds->fp, ds->path +
"/" + ds->filename)) {
282 errormsg =
"Error copying file to target location.\n";
287 if (ds->executable) {
288 os_set_executable(ds->path +
"/" + ds->filename);
293 errormsg =
"CRC32 mismatch";
298 errormsg =
"There was an error downloading the requested file: " 299 + std::string(curl_easy_strerror(msg->data.result));
306 errormsg =
"There was an unknown error downloading the requested file";
309 if (debug) printf(
"Removing Handle\n");
312 curl_multi_remove_handle(m_mhandle, msg->easy_handle);
316 if (ds->fp) os_free_tmpfile(ds->fp);
319 if (debug) printf(
"Download Failed\n");
322 if (debug) printf(
"Download Complete\n");
325 m_files.erase(m_files.find(ds->url));
326 curl_easy_cleanup(ds->handle);
332 int diff = m_num_to_process - num_handles;
336 if (!m_handles.empty()) {
338 curl_multi_add_handle(m_mhandle, m_handles.front());
339 m_handles.pop_front();
353 while (!m_files.empty()) {
357 m_files.erase(m_files.begin());
365 std::map<std::string, DataStruct*>::iterator I = m_files.find(filename);
367 if (I != m_files.end()) {
379 std::deque<CURL*>::iterator I = std::find(m_handles.begin(), m_handles.end(), ds->handle);
381 if (I != m_handles.end()) {
384 curl_multi_remove_handle(m_mhandle, ds->handle);
388 curl_easy_cleanup(ds->handle);
394 os_free_tmpfile(ds->fp);
void abortDownload(const std::string &)
static std::string encodeURL(const std::string &str)
sigc::signal< void, const std::string &, const std::string &, const std::string & > DownloadFailed
int queueFile(const std::string &path, const std::string &filename, const std::string &url, uLong expected_crc32, bool executable)
sigc::signal< void, const std::string &, const std::string & > DownloadComplete
int downloadFile(const std::string &filename, const std::string &url, uLong expected_crc32)