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 result = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0); 94 95 result = curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, 96 &_TransferCallback); 97 if (result != CURLE_OK) 98 return B_BAD_VALUE; 99 100 result = curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); 101 if (result != CURLE_OK) 102 return B_ERROR; 103 104 result = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, 105 &_WriteCallback); 106 if (result != CURLE_OK) 107 return B_ERROR; 108 109 result = curl_easy_setopt(handle, CURLOPT_WRITEDATA, this); 110 if (result != CURLE_OK) 111 return B_ERROR; 112 113 result = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 114 if (result != CURLE_OK) 115 return B_ERROR; 116 117 result = curl_easy_setopt(handle, CURLOPT_URL, fFileURL.String()); 118 if (result != CURLE_OK) 119 return B_ERROR; 120 121 result = curl_easy_perform(handle); 122 curl_easy_cleanup(handle); 123 if (result != CURLE_OK) { 124 // TODO: map more curl error codes to ours for more 125 // precise error reporting 126 return B_ERROR; 127 } 128 #endif /* !HAIKU_BOOTSTRAP_BUILD */ 129 130 return B_OK; 131 } 132 133 134 int 135 FetchFileJob::_TransferCallback(void* _job, off_t downloadTotal, 136 off_t downloaded, off_t uploadTotal, off_t uploaded) 137 { 138 FetchFileJob* job = reinterpret_cast<FetchFileJob*>(_job); 139 if (downloadTotal != 0) { 140 job->fBytes = downloaded; 141 job->fTotalBytes = downloadTotal; 142 job->fDownloadProgress = (float)downloaded / downloadTotal; 143 job->NotifyStateListeners(); 144 } 145 return 0; 146 } 147 148 149 size_t 150 FetchFileJob::_WriteCallback(void *buffer, size_t size, size_t nmemb, 151 void *userp) 152 { 153 FetchFileJob* job = reinterpret_cast<FetchFileJob*>(userp); 154 ssize_t dataWritten = job->fTargetFile.Write(buffer, size * nmemb); 155 return size_t(dataWritten); 156 } 157 158 159 void 160 FetchFileJob::Cleanup(status_t jobResult) 161 { 162 if (jobResult != B_OK) 163 fTargetEntry.Remove(); 164 } 165 166 167 } // namespace BPrivate 168 169 } // namespace BPackageKit 170