summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libalpm/alpm.h7
-rw-r--r--lib/libalpm/dload.c33
-rw-r--r--src/pacman/callback.c30
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 {