diff options
-rw-r--r-- | lib/libalpm/alpm.h | 7 | ||||
-rw-r--r-- | lib/libalpm/dload.c | 33 | ||||
-rw-r--r-- | src/pacman/callback.c | 30 |
3 files changed, 62 insertions, 8 deletions
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 83bd9f91..aef86d78 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -1172,6 +1172,8 @@ typedef enum _alpm_download_event_type_t { ALPM_DOWNLOAD_INIT, /** A download made progress */ ALPM_DOWNLOAD_PROGRESS, + /** Download will be retried */ + ALPM_DOWNLOAD_RETRY, /** A download completed */ ALPM_DOWNLOAD_COMPLETED } alpm_download_event_type_t; @@ -1190,6 +1192,11 @@ typedef struct _alpm_download_event_progress_t { off_t total; } alpm_download_event_progress_t; +/** Context struct for when a download retries. */ +typedef struct _alpm_download_event_retry_t { + /** If the download will resume or start over */ + int resume; +} alpm_download_event_retry_t; /** Context struct for when a download completes. */ typedef struct _alpm_download_event_completed_t { diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 8fa46bb2..2d8b4d6d 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -408,6 +408,7 @@ static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload { const char *server; size_t len; + struct stat st; alpm_handle_t *handle = payload->handle; while(payload->servers && should_skip_server(handle, payload->servers->data)) { @@ -427,15 +428,31 @@ static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload->fileurl, len, "%s/%s", server, payload->filepath); - if(payload->unlink_on_fail) { + + fflush(payload->localf); + + if(payload->allow_resume && stat(payload->tempfile_name, &st) == 0) { + /* a previous partial download exists, resume from end of file. */ + payload->tempfile_openmode = "ab"; + curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)st.st_size); + _alpm_log(handle, ALPM_LOG_DEBUG, + "%s: tempfile found, attempting continuation from %jd bytes\n", + payload->remote_name, (intmax_t)st.st_size); + payload->initial_size = st.st_size; + } else { /* we keep the file for a new retry but remove its data if any */ - fflush(payload->localf); if(ftruncate(fileno(payload->localf), 0)) { RET_ERR(handle, ALPM_ERR_SYSTEM, -1); } fseek(payload->localf, 0, SEEK_SET); } + if(handle->dlcb && !payload->signature) { + alpm_download_event_retry_t cb_data; + cb_data.resume = payload->allow_resume; + handle->dlcb(handle->dlcb_ctx, payload->remote_name, ALPM_DOWNLOAD_RETRY, &cb_data); + } + /* Set curl with the new URL */ curl_easy_setopt(curl, CURLOPT_URL, payload->fileurl); @@ -483,7 +500,6 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg, _alpm_log(handle, ALPM_LOG_DEBUG, "%s: response code %ld\n", payload->remote_name, payload->respcode); if(payload->respcode >= 400) { - payload->unlink_on_fail = 1; if(!payload->errors_ok) { handle->pm_errno = ALPM_ERR_RETRIEVE; /* non-translated message is same as libcurl */ @@ -498,6 +514,7 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg, (*active_downloads_num)++; return 2; } else { + payload->unlink_on_fail = 1; goto cleanup; } } @@ -515,7 +532,6 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg, } goto cleanup; case CURLE_COULDNT_RESOLVE_HOST: - payload->unlink_on_fail = 1; handle->pm_errno = ALPM_ERR_SERVER_BAD_URL; _alpm_log(handle, ALPM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"), @@ -525,13 +541,10 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg, (*active_downloads_num)++; return 2; } else { + payload->unlink_on_fail = 1; goto cleanup; } default: - /* delete zero length downloads */ - if(fstat(fileno(payload->localf), &st) == 0 && st.st_size == 0) { - payload->unlink_on_fail = 1; - } if(!payload->errors_ok) { handle->pm_errno = ALPM_ERR_LIBCURL; _alpm_log(handle, ALPM_LOG_ERROR, @@ -547,6 +560,10 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg, (*active_downloads_num)++; return 2; } else { + /* delete zero length downloads */ + if(fstat(fileno(payload->localf), &st) == 0 && st.st_size == 0) { + payload->unlink_on_fail = 1; + } goto cleanup; } } diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 98d8c5cf..99ad716e 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -994,6 +994,34 @@ static void dload_progress_event(const char *filename, alpm_download_event_progr fflush(stdout); } +/* download retried */ +static void dload_retry_event(const char *filename, alpm_download_event_retry_t *data) { + if(!dload_progressbar_enabled()) { + return; + } + + int index; + struct pacman_progress_bar *bar; + bool ok = find_bar_for_filename(filename, &index, &bar); + assert(ok); + + if(!data->resume) { + if(total_enabled) { + /* note total download does not reflect partial downloads that are restarted */ + totalbar->xfered -= bar->xfered; + } + } + + bar->xfered = 0; + bar->total_size = 0; + bar->init_time = get_time_ms(); + bar->sync_time = 0; + bar->sync_xfered = 0; + bar->rate = 0.0; + bar->eta = 0.0; +} + + /* download completed */ static void dload_complete_event(const char *filename, alpm_download_event_completed_t *data) { @@ -1090,6 +1118,8 @@ void cb_download(void *ctx, const char *filename, alpm_download_event_type_t eve dload_init_event(filename, data); } else if(event == ALPM_DOWNLOAD_PROGRESS) { dload_progress_event(filename, data); + } else if(event == ALPM_DOWNLOAD_RETRY) { + dload_retry_event(filename, data); } else if(event == ALPM_DOWNLOAD_COMPLETED) { dload_complete_event(filename, data); } else { |