1 /* 2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler <axeld@pinc-software.de> 7 * Rene Gollent <rene@gollent.com> 8 * Oliver Tappe <zooey@hirschkaefer.de> 9 */ 10 11 12 #include <package/FetchFileJob.h> 13 14 #include <stdio.h> 15 #ifndef HAIKU_BOOTSTRAP_BUILD 16 #include <curl/curl.h> 17 #endif 18 #include <sys/wait.h> 19 20 #include <Path.h> 21 22 23 namespace BPackageKit { 24 25 namespace BPrivate { 26 27 28 FetchFileJob::FetchFileJob(const BContext& context, const BString& title, 29 const BString& fileURL, const BEntry& targetEntry) 30 : 31 inherited(context, title), 32 fFileURL(fileURL), 33 fTargetEntry(targetEntry), 34 fTargetFile(&targetEntry, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY), 35 fDownloadProgress(0.0) 36 { 37 } 38 39 40 FetchFileJob::~FetchFileJob() 41 { 42 } 43 44 45 float 46 FetchFileJob::DownloadProgress() const 47 { 48 return fDownloadProgress; 49 } 50 51 52 const char* 53 FetchFileJob::DownloadURL() const 54 { 55 return fFileURL.String(); 56 } 57 58 59 const char* 60 FetchFileJob::DownloadFileName() const 61 { 62 return fTargetEntry.Name(); 63 } 64 65 66 off_t 67 FetchFileJob::DownloadBytes() const 68 { 69 return fBytes; 70 } 71 72 73 off_t 74 FetchFileJob::DownloadTotalBytes() const 75 { 76 return fTotalBytes; 77 } 78 79 80 status_t 81 FetchFileJob::Execute() 82 { 83 status_t result = fTargetFile.InitCheck(); 84 if (result != B_OK) 85 return result; 86 87 #ifndef HAIKU_BOOTSTRAP_BUILD 88 CURL* handle = curl_easy_init(); 89 90 if (handle == NULL) 91 return B_NO_MEMORY; 92 93 #if LIBCURL_VERSION_MAJOR > 7 \ 94 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 32) 95 result = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0); 96 97 result = curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, 98 &_TransferCallback); 99 if (result != CURLE_OK) 100 return B_BAD_VALUE; 101 #endif 102 103 result = curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); 104 if (result != CURLE_OK) 105 return B_ERROR; 106 107 result = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, 108 &_WriteCallback); 109 if (result != CURLE_OK) 110 return B_ERROR; 111 112 result = curl_easy_setopt(handle, CURLOPT_WRITEDATA, this); 113 if (result != CURLE_OK) 114 return B_ERROR; 115 116 result = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 117 if (result != CURLE_OK) 118 return B_ERROR; 119 120 result = curl_easy_setopt(handle, CURLOPT_URL, fFileURL.String()); 121 if (result != CURLE_OK) 122 return B_ERROR; 123 124 result = curl_easy_perform(handle); 125 curl_easy_cleanup(handle); 126 127 switch (result) { 128 case CURLE_OK: 129 return B_OK; 130 case CURLE_UNSUPPORTED_PROTOCOL: 131 return EPROTONOSUPPORT; 132 case CURLE_FAILED_INIT: 133 return B_NO_INIT; 134 case CURLE_URL_MALFORMAT: 135 return B_BAD_VALUE; 136 case CURLE_NOT_BUILT_IN: 137 return B_NOT_SUPPORTED; 138 case CURLE_COULDNT_RESOLVE_PROXY: 139 case CURLE_COULDNT_RESOLVE_HOST: 140 return B_NAME_NOT_FOUND; 141 case CURLE_COULDNT_CONNECT: 142 return ECONNREFUSED; 143 case CURLE_FTP_WEIRD_SERVER_REPLY: 144 return B_BAD_DATA; 145 case CURLE_REMOTE_ACCESS_DENIED: 146 return B_NOT_ALLOWED; 147 case CURLE_PARTIAL_FILE: 148 return B_PARTIAL_READ; 149 case CURLE_OUT_OF_MEMORY: 150 return B_NO_MEMORY; 151 case CURLE_OPERATION_TIMEDOUT: 152 return B_TIMED_OUT; 153 case CURLE_SSL_CONNECT_ERROR: 154 return B_BAD_REPLY; 155 default: 156 // TODO: map more curl error codes to ours for more 157 // precise error reporting 158 return B_ERROR; 159 } 160 161 #endif /* !HAIKU_BOOTSTRAP_BUILD */ 162 163 return B_OK; 164 } 165 166 167 int 168 FetchFileJob::_TransferCallback(void* _job, off_t downloadTotal, 169 off_t downloaded, off_t uploadTotal, off_t uploaded) 170 { 171 FetchFileJob* job = reinterpret_cast<FetchFileJob*>(_job); 172 if (downloadTotal != 0) { 173 job->fBytes = downloaded; 174 job->fTotalBytes = downloadTotal; 175 job->fDownloadProgress = (float)downloaded / downloadTotal; 176 job->NotifyStateListeners(); 177 } 178 return 0; 179 } 180 181 182 size_t 183 FetchFileJob::_WriteCallback(void *buffer, size_t size, size_t nmemb, 184 void *userp) 185 { 186 FetchFileJob* job = reinterpret_cast<FetchFileJob*>(userp); 187 ssize_t dataWritten = job->fTargetFile.Write(buffer, size * nmemb); 188 return size_t(dataWritten); 189 } 190 191 192 void 193 FetchFileJob::Cleanup(status_t jobResult) 194 { 195 if (jobResult != B_OK) 196 fTargetEntry.Remove(); 197 } 198 199 200 } // namespace BPrivate 201 202 } // namespace BPackageKit 203