From 6cce517f1a78df885a1574252b3db9886185159d Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 3 Jul 2011 18:55:04 -0400 Subject: lib/rawstr: borrow raw string functions from curl We'll need these functions to do locale agnostic and case insensitive string comparisons. Signed-off-by: Dave Reisner --- lib/libalpm/Makefile.am | 1 + lib/libalpm/rawstr.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/util.h | 2 + 3 files changed, 138 insertions(+) create mode 100644 lib/libalpm/rawstr.c diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index b2b6d0d2..c863fa9b 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -41,6 +41,7 @@ libalpm_la_SOURCES = \ log.h log.c \ package.h package.c \ pkghash.h pkghash.c \ + rawstr.c \ remove.h remove.c \ signing.c signing.h \ sync.h sync.c \ diff --git a/lib/libalpm/rawstr.c b/lib/libalpm/rawstr.c new file mode 100644 index 00000000..69224cbc --- /dev/null +++ b/lib/libalpm/rawstr.c @@ -0,0 +1,135 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* These functions are borrowed from libcurl's lib/rawstr.c with minor + * modifications to style and naming. Curl_raw_equal and Curl_raw_nequal are + * further modified to be true cmp style functions, returning negative, zero, + * or positive. */ + +#include + +/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because + its behavior is altered by the current locale. */ +static char raw_toupper(char in) +{ + switch(in) { + case 'a': + return 'A'; + case 'b': + return 'B'; + case 'c': + return 'C'; + case 'd': + return 'D'; + case 'e': + return 'E'; + case 'f': + return 'F'; + case 'g': + return 'G'; + case 'h': + return 'H'; + case 'i': + return 'I'; + case 'j': + return 'J'; + case 'k': + return 'K'; + case 'l': + return 'L'; + case 'm': + return 'M'; + case 'n': + return 'N'; + case 'o': + return 'O'; + case 'p': + return 'P'; + case 'q': + return 'Q'; + case 'r': + return 'R'; + case 's': + return 'S'; + case 't': + return 'T'; + case 'u': + return 'U'; + case 'v': + return 'V'; + case 'w': + return 'W'; + case 'x': + return 'X'; + case 'y': + return 'Y'; + case 'z': + return 'Z'; + } + return in; +} + +/* + * _alpm_raw_cmp() is for doing "raw" case insensitive strings. This is meant + * to be locale independent and only compare strings we know are safe for + * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * some further explanation to why this function is necessary. + * + * The function is capable of comparing a-z case insensitively even for + * non-ascii. + */ + +int _alpm_raw_cmp(const char *first, const char *second) +{ + while(*first && *second) { + if(raw_toupper(*first) != raw_toupper(*second)) { + /* get out of the loop as soon as they don't match */ + break; + } + first++; + second++; + } + /* we do the comparison here (possibly again), just to make sure that if the + loop above is skipped because one of the strings reached zero, we must not + return this as a successful match */ + return (raw_toupper(*first) - raw_toupper(*second)); +} + +int _alpm_raw_ncmp(const char *first, const char *second, size_t max) +{ + while(*first && *second && max) { + if(raw_toupper(*first) != raw_toupper(*second)) { + break; + } + max--; + first++; + second++; + } + if(0 == max) { + /* they are equal this far */ + return 0; + } + + return (raw_toupper(*first) - raw_toupper(*second)); +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index fd97824a..450dac9b 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -113,6 +113,8 @@ int _alpm_splitname(const char *target, char **name, char **version, unsigned long *name_hash); unsigned long _alpm_hash_sdbm(const char *str); long _alpm_parsedate(const char *line); +int _alpm_raw_cmp(const char *first, const char *second); +int _alpm_raw_ncmp(const char *first, const char *second, size_t max); #ifndef HAVE_STRSEP char *strsep(char **, const char *); -- cgit v1.2.3-70-g09d2 From 44889da5b704483b7ee013ec828ff64b64980de8 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 3 Jul 2011 19:58:19 -0400 Subject: dload: rearrange code to avoid extra cpp block Signed-off-by: Dave Reisner --- lib/libalpm/dload.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 4b4d8dff..b93182f3 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -42,10 +42,6 @@ #include "util.h" #include "handle.h" -#ifdef HAVE_LIBCURL -static double prevprogress; /* last download amount */ -#endif - static const char *get_filename(const char *url) { char *filename = strrchr(url, '/'); @@ -56,6 +52,8 @@ static const char *get_filename(const char *url) } #ifdef HAVE_LIBCURL +static double prevprogress; /* last download amount */ + static char *get_fullpath(const char *path, const char *filename, const char *suffix) { -- cgit v1.2.3-70-g09d2 From 6c9b82e72ac067207b1d66a3112485ad8d690f32 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sat, 11 Jun 2011 12:50:15 -0400 Subject: dload: handle irregular URLs URLs might end with a slash and follow redirects, or could be a generated by a script such as /getpkg.php?id=12345. In both cases, we may have a better filename that we can write to, taken from either content-disposition header, or the effective URL. Specific to the first case, we write to a temporary file of the format 'alpmtmp.XXXXXX', where XXXXXX is randomized by mkstemp(3). Since this is a randomly generated file, we cannot support resuming and the file is unlinked in the event of an interrupt. We also run into the possibility of changing out the filename from under alpm on a -U operation, so callers of _alpm_download can optionally pass a pointer to a *char to be filled in by curl_download_internal with the actual filename we wrote to. Any sync operation will pass a NULL pointer here, as we rely on specific names for packages from a mirror. Fixes FS#22645. Signed-off-by: Dave Reisner --- lib/libalpm/be_sync.c | 4 +- lib/libalpm/dload.c | 131 ++++++++++++++++++++++++++++++++++++++++++-------- lib/libalpm/dload.h | 3 +- lib/libalpm/sync.c | 2 +- 4 files changed, 116 insertions(+), 24 deletions(-) diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index e3871001..a784536b 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -181,7 +181,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(fileurl, len, "%s/%s.db", server, db->treename); - ret = _alpm_download(handle, fileurl, syncpath, force, 0, 0); + ret = _alpm_download(handle, fileurl, syncpath, NULL, force, 0, 0); if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ @@ -197,7 +197,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* if we downloaded a DB, we want the .sig from the same server */ snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename); - sig_ret = _alpm_download(handle, fileurl, syncpath, 1, 0, errors_ok); + sig_ret = _alpm_download(handle, fileurl, syncpath, NULL, 1, 0, errors_ok); /* errors_ok suppresses error messages, but not the return code */ sig_ret = errors_ok ? 0 : sig_ret; } diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index b93182f3..e9ff6213 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -146,16 +146,46 @@ static int utimes_long(const char *path, long seconds) return 0; } +static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) +{ + size_t realsize = size * nmemb; + const char *fptr, *endptr = NULL; + const char * const cd_header = "Content-Disposition:"; + const char * const fn_key = "filename="; + struct fileinfo **dlfile = (struct fileinfo**)user; + + if(_alpm_raw_ncmp(cd_header, ptr, strlen(cd_header)) == 0) { + if((fptr = strstr(ptr, fn_key))) { + fptr += strlen(fn_key); + + /* find the end of the field, which is either a semi-colon, or the end of + * the data. As per curl_easy_setopt(3), we cannot count on headers being + * null terminated, so we look for the closing \r\n */ + endptr = fptr + strcspn(fptr, ";\r\n") - 1; + + /* remove quotes */ + if(*fptr == '"' && *endptr == '"') { + fptr++; + endptr--; + } + + STRNDUP((*dlfile)->cd_filename, fptr, endptr - fptr + 1, + RET_ERR((*dlfile)->handle, ALPM_ERR_MEMORY, realsize)); + } + } -static int curl_download_internal(alpm_handle_t *handle, - const char *url, const char *localpath, - int force, int allow_resume, int errors_ok) + return realsize; +} + +static int curl_download_internal(alpm_handle_t *handle, const char *url, + const char *localpath, char **final_file, int force, int allow_resume, + int errors_ok) { - int ret = -1; + int ret = -1, should_unlink = 0; FILE *localf = NULL; const char *useragent; const char *open_mode = "wb"; - char *destfile, *tempfile; + char *destfile = NULL, *tempfile = NULL, *effective_url; /* RFC1123 states applications should support this length */ char hostname[256]; char error_buffer[CURL_ERROR_SIZE]; @@ -168,15 +198,39 @@ static int curl_download_internal(alpm_handle_t *handle, dlfile.handle = handle; dlfile.initial_size = 0.0; dlfile.filename = get_filename(url); + dlfile.cd_filename = NULL; if(!dlfile.filename || curl_gethost(url, hostname) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), url); RET_ERR(handle, ALPM_ERR_SERVER_BAD_URL, -1); } - destfile = get_fullpath(localpath, dlfile.filename, ""); - tempfile = get_fullpath(localpath, dlfile.filename, ".part"); - if(!destfile || !tempfile) { - goto cleanup; + if(strlen(dlfile.filename) > 0 && strcmp(dlfile.filename, ".sig") != 0) { + destfile = get_fullpath(localpath, dlfile.filename, ""); + tempfile = get_fullpath(localpath, dlfile.filename, ".part"); + if(!destfile || !tempfile) { + goto cleanup; + } + } else { + /* URL isn't to a file and ended with a slash */ + int fd; + char randpath[PATH_MAX]; + + /* we can't support resuming this kind of download, so a partial transfer + * will be destroyed */ + should_unlink = 1; + + /* create a random filename, which is opened with O_EXCL */ + snprintf(randpath, PATH_MAX, "%salpmtmp.XXXXXX", localpath); + if((fd = mkstemp(randpath)) == -1 || !(localf = fdopen(fd, open_mode))) { + unlink(randpath); + close(fd); + _alpm_log(handle, ALPM_LOG_ERROR, + _("failed to create temporary file for download\n")); + goto cleanup; + } + /* localf now points to our alpmtmp.XXXXXX */ + STRDUP(tempfile, randpath, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + dlfile.filename = strrchr(randpath, '/') + 1; } error_buffer[0] = '\0'; @@ -195,6 +249,8 @@ static int curl_download_internal(alpm_handle_t *handle, curl_easy_setopt(handle->curl, CURLOPT_PROGRESSDATA, (void *)&dlfile); curl_easy_setopt(handle->curl, CURLOPT_LOW_SPEED_LIMIT, 1024L); curl_easy_setopt(handle->curl, CURLOPT_LOW_SPEED_TIME, 10L); + curl_easy_setopt(handle->curl, CURLOPT_HEADERFUNCTION, parse_headers); + curl_easy_setopt(handle->curl, CURLOPT_WRITEHEADER, &dlfile); useragent = getenv("HTTP_USER_AGENT"); if(useragent != NULL) { @@ -213,9 +269,11 @@ static int curl_download_internal(alpm_handle_t *handle, dlfile.initial_size = (double)st.st_size; } - localf = fopen(tempfile, open_mode); if(localf == NULL) { - goto cleanup; + localf = fopen(tempfile, open_mode); + if(localf == NULL) { + goto cleanup; + } } curl_easy_setopt(handle->curl, CURLOPT_WRITEDATA, localf); @@ -262,6 +320,7 @@ static int curl_download_internal(alpm_handle_t *handle, curl_easy_getinfo(handle->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &remote_size); curl_easy_getinfo(handle->curl, CURLINFO_SIZE_DOWNLOAD, &bytes_dl); curl_easy_getinfo(handle->curl, CURLINFO_CONDITION_UNMET, &timecond); + curl_easy_getinfo(handle->curl, CURLINFO_EFFECTIVE_URL, &effective_url); /* time condition was met and we didn't download anything. we need to * clean up the 0 byte .part file that's left behind. */ @@ -282,6 +341,26 @@ static int curl_download_internal(alpm_handle_t *handle, goto cleanup; } + if(dlfile.cd_filename) { + /* content-disposition header has a better name for our file */ + free(destfile); + destfile = get_fullpath(localpath, dlfile.cd_filename, ""); + } else { + const char *effective_filename = strrchr(effective_url, '/'); + if(effective_filename) { + effective_filename++; + + /* if destfile was never set, we wrote to a tempfile. even if destfile is + * set, we may have followed some redirects and the effective url may + * have a better suggestion as to what to name our file. in either case, + * refactor destfile to this newly derived name. */ + if(!destfile || strcmp(effective_filename, strrchr(destfile, '/') + 1) != 0) { + free(destfile); + destfile = get_fullpath(localpath, effective_filename, ""); + } + } + } + ret = 0; cleanup: @@ -292,10 +371,18 @@ cleanup: if(ret == 0) { rename(tempfile, destfile); + if(final_file) { + *final_file = strdup(strrchr(destfile, '/') + 1); + } + } + + if(dload_interrupted && should_unlink) { + unlink(tempfile); } FREE(tempfile); FREE(destfile); + FREE(dlfile.cd_filename); /* restore the old signal handlers */ sigaction(SIGINT, &sig_int[OLD], NULL); @@ -314,18 +401,19 @@ cleanup: * @param handle the context handle * @param url the file's URL * @param localpath the directory to save the file in + * @param final_file the real name of the downloaded file (may be NULL) * @param force force download even if there is an up-to-date local copy * @param allow_resume allow a partial download to be resumed * @param errors_ok do not log errors (but still return them) * @return 0 on success, -1 on error (pm_errno is set accordingly if errors_ok == 0) */ int _alpm_download(alpm_handle_t *handle, const char *url, const char *localpath, - int force, int allow_resume, int errors_ok) + char **final_file, int force, int allow_resume, int errors_ok) { if(handle->fetchcb == NULL) { #ifdef HAVE_LIBCURL - return curl_download_internal(handle, url, localpath, - force, allow_resume, errors_ok); + return curl_download_internal(handle, url, localpath, final_file, force, + allow_resume, errors_ok); #else RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); #endif @@ -342,18 +430,17 @@ int _alpm_download(alpm_handle_t *handle, const char *url, const char *localpath char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) { char *filepath; - const char *filename, *cachedir; + const char *cachedir; + char *final_file = NULL; int ret; CHECK_HANDLE(handle, return NULL); - filename = get_filename(url); - /* find a valid cache dir to download to */ cachedir = _alpm_filecache_setup(handle); /* download the file */ - ret = _alpm_download(handle, url, cachedir, 0, 1, 0); + ret = _alpm_download(handle, url, cachedir, &final_file, 0, 1, 0); if(ret == -1) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); return NULL; @@ -363,6 +450,7 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) /* attempt to download the signature */ if(ret == 0 && (handle->siglevel & ALPM_SIG_PACKAGE)) { char *sig_url; + char *sig_final_file = NULL; size_t len; int errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); @@ -370,7 +458,7 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) CALLOC(sig_url, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); snprintf(sig_url, len, "%s.sig", url); - ret = _alpm_download(handle, sig_url, cachedir, 1, 0, errors_ok); + ret = _alpm_download(handle, sig_url, cachedir, &sig_final_file, 1, 0, errors_ok); if(ret == -1 && !errors_ok) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), sig_url); /* Warn now, but don't return NULL. We will fail later during package @@ -379,10 +467,13 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", sig_url); } FREE(sig_url); + FREE(sig_final_file); } /* we should be able to find the file the second time around */ - filepath = _alpm_filecache_find(handle, filename); + filepath = _alpm_filecache_find(handle, final_file); + FREE(final_file); + return filepath; } diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index 0cdd9001..351b2b30 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -29,11 +29,12 @@ struct fileinfo { alpm_handle_t *handle; const char *filename; + char *cd_filename; double initial_size; }; int _alpm_download(alpm_handle_t *handle, const char *url, const char *localpath, - int force, int allow_resume, int errors_ok); + char **final_file, int force, int allow_resume, int errors_ok); #endif /* _ALPM_DLOAD_H */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 1d712797..54b96a7a 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -805,7 +805,7 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(fileurl, len, "%s/%s", server_url, filename); - ret = _alpm_download(handle, fileurl, cachedir, 0, 1, 0); + ret = _alpm_download(handle, fileurl, cachedir, NULL, 0, 1, 0); FREE(fileurl); if(ret != -1) { break; -- cgit v1.2.3-70-g09d2 From 6dc71926f9b16ebcf11b924941092d6eab204224 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Fri, 24 Jun 2011 00:18:01 -0400 Subject: lib/dload: prevent large file attacks This means creating a new struct which can pass more descriptive data from the back end sync functions to the downloader. In particular, we're interested in the download size read from the sync DB. When the remote server reports a size larger than this (via a content-length header), abort the transfer. In cases where the size is unknown, we set a hard upper limit of: * 25MiB for a sync DB * 16KiB for a signature For reference, 25MiB is more than twice the size of all of the current binary repos (with files) combined, and 16KiB is a truly gargantuan signature. Signed-off-by: Dave Reisner --- lib/libalpm/be_sync.c | 22 ++++++++++++++------- lib/libalpm/dload.c | 55 +++++++++++++++++++++++++++++++++++---------------- lib/libalpm/dload.h | 13 ++++++++++-- lib/libalpm/sync.c | 37 +++++++++++++++++++++------------- 4 files changed, 87 insertions(+), 40 deletions(-) diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index a784536b..f681fc8e 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -172,16 +172,21 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) for(i = db->servers; i; i = i->next) { const char *server = i->data; - char *fileurl; + struct dload_payload *payload; size_t len; int sig_ret = 0; + CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + + /* set hard upper limit of 25MiB */ + payload->max_size = 25 * 1024 * 1024; + /* print server + filename into a buffer (leave space for .sig) */ len = strlen(server) + strlen(db->treename) + 9; - CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - snprintf(fileurl, len, "%s/%s.db", server, db->treename); + CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + snprintf(payload->fileurl, len, "%s/%s.db", server, db->treename); - ret = _alpm_download(handle, fileurl, syncpath, NULL, force, 0, 0); + ret = _alpm_download(handle, payload, syncpath, NULL, force, 0, 0); if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ @@ -195,14 +200,17 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) int errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* if we downloaded a DB, we want the .sig from the same server */ - snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename); + snprintf(payload->fileurl, len, "%s/%s.db.sig", server, db->treename); + + /* set hard upper limit of 16KiB */ + payload->max_size = 16 * 1024; - sig_ret = _alpm_download(handle, fileurl, syncpath, NULL, 1, 0, errors_ok); + sig_ret = _alpm_download(handle, payload, syncpath, NULL, 1, 0, errors_ok); /* errors_ok suppresses error messages, but not the return code */ sig_ret = errors_ok ? 0 : sig_ret; } - FREE(fileurl); + _alpm_dload_payload_free(payload); if(ret != -1 && sig_ret != -1) { break; } diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index e9ff6213..1f0ea9ce 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -177,7 +177,7 @@ static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) return realsize; } -static int curl_download_internal(alpm_handle_t *handle, const char *url, +static int curl_download_internal(alpm_handle_t *handle, struct dload_payload *payload, const char *localpath, char **final_file, int force, int allow_resume, int errors_ok) { @@ -197,10 +197,10 @@ static int curl_download_internal(alpm_handle_t *handle, const char *url, dlfile.handle = handle; dlfile.initial_size = 0.0; - dlfile.filename = get_filename(url); + dlfile.filename = payload->filename ? payload->filename : get_filename(payload->fileurl); dlfile.cd_filename = NULL; - if(!dlfile.filename || curl_gethost(url, hostname) != 0) { - _alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), url); + if(!dlfile.filename || curl_gethost(payload->fileurl, hostname) != 0) { + _alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), payload->fileurl); RET_ERR(handle, ALPM_ERR_SERVER_BAD_URL, -1); } @@ -238,7 +238,7 @@ static int curl_download_internal(alpm_handle_t *handle, const char *url, /* the curl_easy handle is initialized with the alpm handle, so we only need * to reset the curl handle set parameters for each time it's used. */ curl_easy_reset(handle->curl); - curl_easy_setopt(handle->curl, CURLOPT_URL, url); + curl_easy_setopt(handle->curl, CURLOPT_URL, payload->fileurl); curl_easy_setopt(handle->curl, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(handle->curl, CURLOPT_ERRORBUFFER, error_buffer); curl_easy_setopt(handle->curl, CURLOPT_CONNECTTIMEOUT, 10L); @@ -252,6 +252,10 @@ static int curl_download_internal(alpm_handle_t *handle, const char *url, curl_easy_setopt(handle->curl, CURLOPT_HEADERFUNCTION, parse_headers); curl_easy_setopt(handle->curl, CURLOPT_WRITEHEADER, &dlfile); + if(payload->max_size) { + curl_easy_setopt(handle->curl, CURLOPT_MAXFILESIZE, payload->max_size); + } + useragent = getenv("HTTP_USER_AGENT"); if(useragent != NULL) { curl_easy_setopt(handle->curl, CURLOPT_USERAGENT, useragent); @@ -407,18 +411,19 @@ cleanup: * @param errors_ok do not log errors (but still return them) * @return 0 on success, -1 on error (pm_errno is set accordingly if errors_ok == 0) */ -int _alpm_download(alpm_handle_t *handle, const char *url, const char *localpath, - char **final_file, int force, int allow_resume, int errors_ok) +int _alpm_download(alpm_handle_t *handle, struct dload_payload *payload, + const char *localpath, char **final_file, int force, int allow_resume, + int errors_ok) { if(handle->fetchcb == NULL) { #ifdef HAVE_LIBCURL - return curl_download_internal(handle, url, localpath, final_file, force, + return curl_download_internal(handle, payload, localpath, final_file, force, allow_resume, errors_ok); #else RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); #endif } else { - int ret = handle->fetchcb(url, localpath, force); + int ret = handle->fetchcb(payload->fileurl, localpath, force); if(ret == -1 && !errors_ok) { RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); } @@ -432,6 +437,7 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) char *filepath; const char *cachedir; char *final_file = NULL; + struct dload_payload *payload; int ret; CHECK_HANDLE(handle, return NULL); @@ -439,8 +445,11 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) /* find a valid cache dir to download to */ cachedir = _alpm_filecache_setup(handle); + CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + payload->fileurl = strdup(url); + /* download the file */ - ret = _alpm_download(handle, url, cachedir, &final_file, 0, 1, 0); + ret = _alpm_download(handle, payload, cachedir, &final_file, 0, 1, 0); if(ret == -1) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); return NULL; @@ -449,32 +458,44 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) /* attempt to download the signature */ if(ret == 0 && (handle->siglevel & ALPM_SIG_PACKAGE)) { - char *sig_url; char *sig_final_file = NULL; size_t len; int errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); + struct dload_payload *sig_payload; + CALLOC(sig_payload, 1, sizeof(*sig_payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); len = strlen(url) + 5; - CALLOC(sig_url, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); - snprintf(sig_url, len, "%s.sig", url); + CALLOC(sig_payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + snprintf(sig_payload->fileurl, len, "%s.sig", url); + sig_payload->max_size = 1024 * 16; - ret = _alpm_download(handle, sig_url, cachedir, &sig_final_file, 1, 0, errors_ok); + ret = _alpm_download(handle, sig_payload, cachedir, &sig_final_file, 1, 0, errors_ok); if(ret == -1 && !errors_ok) { - _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), sig_url); + _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), sig_payload->fileurl); /* Warn now, but don't return NULL. We will fail later during package * load time. */ } else if(ret == 0) { - _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", sig_url); + _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", sig_payload->fileurl); } - FREE(sig_url); FREE(sig_final_file); + _alpm_dload_payload_free(sig_payload); } /* we should be able to find the file the second time around */ filepath = _alpm_filecache_find(handle, final_file); FREE(final_file); + _alpm_dload_payload_free(payload); return filepath; } +void _alpm_dload_payload_free(struct dload_payload *payload) { + struct dload_payload *load = (struct dload_payload *)payload; + + ASSERT(load, return); + + FREE(load->fileurl); + FREE(load); +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index 351b2b30..6a2dd392 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -33,8 +33,17 @@ struct fileinfo { double initial_size; }; -int _alpm_download(alpm_handle_t *handle, const char *url, const char *localpath, - char **final_file, int force, int allow_resume, int errors_ok); +struct dload_payload { + char *filename; + char *fileurl; + long max_size; +}; + +void _alpm_dload_payload_free(struct dload_payload *payload); + +int _alpm_download(alpm_handle_t *handle, struct dload_payload *payload, + const char *localpath, char **final_file, int force, int allow_resume, + int errors_ok); #endif /* _ALPM_DLOAD_H */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 54b96a7a..969af3c0 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -765,10 +765,6 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) alpm_pkg_t *spkg = j->data; if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) { - const char *fname = NULL; - - fname = alpm_pkg_get_filename(spkg); - ASSERT(fname != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); alpm_list_t *delta_path = spkg->delta_path; if(delta_path) { /* using deltas */ @@ -776,14 +772,27 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) for(dlts = delta_path; dlts; dlts = dlts->next) { alpm_delta_t *delta = dlts->data; if(delta->download_size != 0) { - files = alpm_list_add(files, strdup(delta->delta)); + struct dload_payload *dpayload; + + CALLOC(dpayload, 1, sizeof(*dpayload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + STRDUP(dpayload->filename, delta->delta, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + dpayload->max_size = delta->download_size; + + files = alpm_list_add(files, dpayload); } /* keep a list of all the delta files for md5sums */ *deltas = alpm_list_add(*deltas, delta); } } else if(spkg->download_size != 0) { - files = alpm_list_add(files, strdup(fname)); + struct dload_payload *payload; + + ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); + CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + STRDUP(payload->filename, spkg->filename, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + payload->max_size = alpm_pkg_get_size(spkg); + + files = alpm_list_add(files, payload); } } @@ -792,21 +801,19 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) if(files) { EVENT(handle->trans, ALPM_TRANS_EVT_RETRIEVE_START, current->treename, NULL); for(j = files; j; j = j->next) { - const char *filename = j->data; + struct dload_payload *payload = j->data; alpm_list_t *server; int ret = -1; for(server = current->servers; server; server = server->next) { const char *server_url = server->data; - char *fileurl; size_t len; /* print server + filename into a buffer */ - len = strlen(server_url) + strlen(filename) + 2; - CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - snprintf(fileurl, len, "%s/%s", server_url, filename); + len = strlen(server_url) + strlen(payload->filename) + 2; + CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + snprintf(payload->fileurl, len, "%s/%s", server_url, payload->filename); - ret = _alpm_download(handle, fileurl, cachedir, NULL, 0, 1, 0); - FREE(fileurl); + ret = _alpm_download(handle, payload, cachedir, NULL, 0, 1, 0); if(ret != -1) { break; } @@ -816,7 +823,9 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) } } - FREELIST(files); + alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_free); + alpm_list_free(files); + files = NULL; if(errors) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files from %s\n"), current->treename); -- cgit v1.2.3-70-g09d2 From 3eec745910bb908717a8b4ed7f5b630a92a5c9eb Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Thu, 30 Jun 2011 21:19:25 -0400 Subject: absorb some _alpm_download params into payload struct Restore some sanity to the number of arguments passed to _alpm_download and curl_download_internal. Signed-off-by: Dave Reisner --- lib/libalpm/be_sync.c | 12 ++++++++---- lib/libalpm/dload.c | 46 +++++++++++++++++++++++----------------------- lib/libalpm/dload.h | 9 ++++++--- lib/libalpm/sync.c | 4 +++- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index f681fc8e..d7e14ba3 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -185,8 +185,10 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) len = strlen(server) + strlen(db->treename) + 9; CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload->fileurl, len, "%s/%s.db", server, db->treename); + payload->handle = handle; + payload->force = force; - ret = _alpm_download(handle, payload, syncpath, NULL, force, 0, 0); + ret = _alpm_download(payload, syncpath, NULL); if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ @@ -198,16 +200,18 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) unlink(sigpath); free(sigpath); - int errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* if we downloaded a DB, we want the .sig from the same server */ snprintf(payload->fileurl, len, "%s/%s.db.sig", server, db->treename); + payload->handle = handle; + payload->force = 1; + payload->errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* set hard upper limit of 16KiB */ payload->max_size = 16 * 1024; - sig_ret = _alpm_download(handle, payload, syncpath, NULL, 1, 0, errors_ok); + sig_ret = _alpm_download(payload, syncpath, NULL); /* errors_ok suppresses error messages, but not the return code */ - sig_ret = errors_ok ? 0 : sig_ret; + sig_ret = payload->errors_ok ? 0 : sig_ret; } _alpm_dload_payload_free(payload); diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 1f0ea9ce..4aaebefe 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -177,9 +177,8 @@ static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) return realsize; } -static int curl_download_internal(alpm_handle_t *handle, struct dload_payload *payload, - const char *localpath, char **final_file, int force, int allow_resume, - int errors_ok) +static int curl_download_internal(struct dload_payload *payload, + const char *localpath, char **final_file) { int ret = -1, should_unlink = 0; FILE *localf = NULL; @@ -194,6 +193,8 @@ static int curl_download_internal(alpm_handle_t *handle, struct dload_payload *p double remote_size, bytes_dl; struct sigaction sig_pipe[2], sig_int[2]; struct fileinfo dlfile; + /* shortcut to our handle within the payload */ + alpm_handle_t *handle = payload->handle; dlfile.handle = handle; dlfile.initial_size = 0.0; @@ -261,11 +262,11 @@ static int curl_download_internal(alpm_handle_t *handle, struct dload_payload *p curl_easy_setopt(handle->curl, CURLOPT_USERAGENT, useragent); } - if(!allow_resume && !force && stat(destfile, &st) == 0) { + if(!payload->allow_resume && !payload->force && stat(destfile, &st) == 0) { /* start from scratch, but only download if our local is out of date. */ curl_easy_setopt(handle->curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); curl_easy_setopt(handle->curl, CURLOPT_TIMEVALUE, (long)st.st_mtime); - } else if(stat(tempfile, &st) == 0 && allow_resume) { + } else if(stat(tempfile, &st) == 0 && payload->allow_resume) { /* a previous partial download exists, resume from end of file. */ open_mode = "ab"; curl_easy_setopt(handle->curl, CURLOPT_RESUME_FROM, (long)st.st_size); @@ -307,7 +308,7 @@ static int curl_download_internal(alpm_handle_t *handle, struct dload_payload *p if(handle->curlerr == CURLE_ABORTED_BY_CALLBACK) { goto cleanup; } else if(handle->curlerr != CURLE_OK) { - if(!errors_ok) { + if(!payload->errors_ok) { handle->pm_errno = ALPM_ERR_LIBCURL; _alpm_log(handle, ALPM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"), dlfile.filename, hostname, error_buffer); @@ -402,29 +403,25 @@ cleanup: /** Download a file given by a URL to a local directory. * Does not overwrite an existing file if the download fails. - * @param handle the context handle - * @param url the file's URL + * @param payload the payload context * @param localpath the directory to save the file in * @param final_file the real name of the downloaded file (may be NULL) - * @param force force download even if there is an up-to-date local copy - * @param allow_resume allow a partial download to be resumed - * @param errors_ok do not log errors (but still return them) * @return 0 on success, -1 on error (pm_errno is set accordingly if errors_ok == 0) */ -int _alpm_download(alpm_handle_t *handle, struct dload_payload *payload, - const char *localpath, char **final_file, int force, int allow_resume, - int errors_ok) +int _alpm_download(struct dload_payload *payload, const char *localpath, + char **final_file) { + alpm_handle_t *handle = payload->handle; + if(handle->fetchcb == NULL) { #ifdef HAVE_LIBCURL - return curl_download_internal(handle, payload, localpath, final_file, force, - allow_resume, errors_ok); + return curl_download_internal(payload, localpath, final_file); #else RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); #endif } else { - int ret = handle->fetchcb(payload->fileurl, localpath, force); - if(ret == -1 && !errors_ok) { + int ret = handle->fetchcb(payload->fileurl, localpath, payload->force); + if(ret == -1 && !payload->errors_ok) { RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); } return ret; @@ -446,10 +443,12 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) cachedir = _alpm_filecache_setup(handle); CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + payload->handle = handle; payload->fileurl = strdup(url); + payload->allow_resume = 1; /* download the file */ - ret = _alpm_download(handle, payload, cachedir, &final_file, 0, 1, 0); + ret = _alpm_download(payload, cachedir, &final_file); if(ret == -1) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); return NULL; @@ -460,17 +459,18 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) if(ret == 0 && (handle->siglevel & ALPM_SIG_PACKAGE)) { char *sig_final_file = NULL; size_t len; - int errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); struct dload_payload *sig_payload; CALLOC(sig_payload, 1, sizeof(*sig_payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); len = strlen(url) + 5; CALLOC(sig_payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); snprintf(sig_payload->fileurl, len, "%s.sig", url); - sig_payload->max_size = 1024 * 16; + sig_payload->handle = handle; + sig_payload->force = 1; + sig_payload->errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); - ret = _alpm_download(handle, sig_payload, cachedir, &sig_final_file, 1, 0, errors_ok); - if(ret == -1 && !errors_ok) { + ret = _alpm_download(sig_payload, cachedir, &sig_final_file); + if(ret == -1 && !sig_payload->errors_ok) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), sig_payload->fileurl); /* Warn now, but don't return NULL. We will fail later during package * load time. */ diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index 6a2dd392..3945d245 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -34,16 +34,19 @@ struct fileinfo { }; struct dload_payload { + alpm_handle_t *handle; char *filename; char *fileurl; long max_size; + int force; + int allow_resume; + int errors_ok; }; void _alpm_dload_payload_free(struct dload_payload *payload); -int _alpm_download(alpm_handle_t *handle, struct dload_payload *payload, - const char *localpath, char **final_file, int force, int allow_resume, - int errors_ok); +int _alpm_download(struct dload_payload *payload, const char *localpath, + char **final_file); #endif /* _ALPM_DLOAD_H */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 969af3c0..ca7e6579 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -812,8 +812,10 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) len = strlen(server_url) + strlen(payload->filename) + 2; CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload->fileurl, len, "%s/%s", server_url, payload->filename); + payload->handle = handle; + payload->allow_resume = 1; - ret = _alpm_download(handle, payload, cachedir, NULL, 0, 1, 0); + ret = _alpm_download(payload, cachedir, NULL); if(ret != -1) { break; } -- cgit v1.2.3-70-g09d2 From 57eac093c40b0a54ab5d9f14519b9e44140e0c3d Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Thu, 30 Jun 2011 22:00:07 -0400 Subject: absorb fileinfo struct into dload_payload This transitional struct becomes delicious noms for dload_payload. Signed-off-by: Dave Reisner --- lib/libalpm/dload.c | 54 ++++++++++++++++++++++++++--------------------------- lib/libalpm/dload.h | 10 ++-------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 4aaebefe..23b8db72 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -78,7 +78,7 @@ static void inthandler(int UNUSED signum) static int curl_progress(void *file, double dltotal, double dlnow, double UNUSED ultotal, double UNUSED ulnow) { - struct fileinfo *dlfile = (struct fileinfo *)file; + struct dload_payload *payload = (struct dload_payload *)file; double current_size, total_size; /* SIGINT sent, abort by alerting curl */ @@ -87,12 +87,12 @@ static int curl_progress(void *file, double dltotal, double dlnow, } /* none of what follows matters if the front end has no callback */ - if(dlfile->handle->dlcb == NULL) { + if(payload->handle->dlcb == NULL) { return 0; } - current_size = dlfile->initial_size + dlnow; - total_size = dlfile->initial_size + dltotal; + current_size = payload->initial_size + dlnow; + total_size = payload->initial_size + dltotal; if(DOUBLE_EQ(dltotal, 0) || DOUBLE_EQ(prevprogress, total_size)) { return 0; @@ -101,10 +101,10 @@ static int curl_progress(void *file, double dltotal, double dlnow, /* initialize the progress bar here to avoid displaying it when * a repo is up to date and nothing gets downloaded */ if(DOUBLE_EQ(prevprogress, 0)) { - dlfile->handle->dlcb(dlfile->filename, 0, (long)dltotal); + payload->handle->dlcb(payload->filename, 0, (long)dltotal); } - dlfile->handle->dlcb(dlfile->filename, (long)current_size, (long)total_size); + payload->handle->dlcb(payload->filename, (long)current_size, (long)total_size); prevprogress = current_size; @@ -152,7 +152,7 @@ static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) const char *fptr, *endptr = NULL; const char * const cd_header = "Content-Disposition:"; const char * const fn_key = "filename="; - struct fileinfo **dlfile = (struct fileinfo**)user; + struct dload_payload *payload = (struct dload_payload *)user; if(_alpm_raw_ncmp(cd_header, ptr, strlen(cd_header)) == 0) { if((fptr = strstr(ptr, fn_key))) { @@ -169,8 +169,8 @@ static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) endptr--; } - STRNDUP((*dlfile)->cd_filename, fptr, endptr - fptr + 1, - RET_ERR((*dlfile)->handle, ALPM_ERR_MEMORY, realsize)); + STRNDUP(payload->cd_filename, fptr, endptr - fptr + 1, + RET_ERR(payload->handle, ALPM_ERR_MEMORY, realsize)); } } @@ -192,22 +192,20 @@ static int curl_download_internal(struct dload_payload *payload, long timecond, remote_time = -1; double remote_size, bytes_dl; struct sigaction sig_pipe[2], sig_int[2]; - struct fileinfo dlfile; /* shortcut to our handle within the payload */ alpm_handle_t *handle = payload->handle; - dlfile.handle = handle; - dlfile.initial_size = 0.0; - dlfile.filename = payload->filename ? payload->filename : get_filename(payload->fileurl); - dlfile.cd_filename = NULL; - if(!dlfile.filename || curl_gethost(payload->fileurl, hostname) != 0) { + if(!payload->filename) { + payload->filename = get_filename(payload->fileurl); + } + if(!payload->filename || curl_gethost(payload->fileurl, hostname) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), payload->fileurl); RET_ERR(handle, ALPM_ERR_SERVER_BAD_URL, -1); } - if(strlen(dlfile.filename) > 0 && strcmp(dlfile.filename, ".sig") != 0) { - destfile = get_fullpath(localpath, dlfile.filename, ""); - tempfile = get_fullpath(localpath, dlfile.filename, ".part"); + if(strlen(payload->filename) > 0 && strcmp(payload->filename, ".sig") != 0) { + destfile = get_fullpath(localpath, payload->filename, ""); + tempfile = get_fullpath(localpath, payload->filename, ".part"); if(!destfile || !tempfile) { goto cleanup; } @@ -231,7 +229,7 @@ static int curl_download_internal(struct dload_payload *payload, } /* localf now points to our alpmtmp.XXXXXX */ STRDUP(tempfile, randpath, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - dlfile.filename = strrchr(randpath, '/') + 1; + payload->filename = strrchr(randpath, '/') + 1; } error_buffer[0] = '\0'; @@ -247,11 +245,11 @@ static int curl_download_internal(struct dload_payload *payload, curl_easy_setopt(handle->curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(handle->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(handle->curl, CURLOPT_PROGRESSFUNCTION, curl_progress); - curl_easy_setopt(handle->curl, CURLOPT_PROGRESSDATA, (void *)&dlfile); + curl_easy_setopt(handle->curl, CURLOPT_PROGRESSDATA, (void *)payload); curl_easy_setopt(handle->curl, CURLOPT_LOW_SPEED_LIMIT, 1024L); curl_easy_setopt(handle->curl, CURLOPT_LOW_SPEED_TIME, 10L); curl_easy_setopt(handle->curl, CURLOPT_HEADERFUNCTION, parse_headers); - curl_easy_setopt(handle->curl, CURLOPT_WRITEHEADER, &dlfile); + curl_easy_setopt(handle->curl, CURLOPT_WRITEHEADER, (void *)payload); if(payload->max_size) { curl_easy_setopt(handle->curl, CURLOPT_MAXFILESIZE, payload->max_size); @@ -271,7 +269,7 @@ static int curl_download_internal(struct dload_payload *payload, open_mode = "ab"; curl_easy_setopt(handle->curl, CURLOPT_RESUME_FROM, (long)st.st_size); _alpm_log(handle, ALPM_LOG_DEBUG, "tempfile found, attempting continuation\n"); - dlfile.initial_size = (double)st.st_size; + payload->initial_size = (double)st.st_size; } if(localf == NULL) { @@ -311,10 +309,10 @@ static int curl_download_internal(struct dload_payload *payload, if(!payload->errors_ok) { handle->pm_errno = ALPM_ERR_LIBCURL; _alpm_log(handle, ALPM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"), - dlfile.filename, hostname, error_buffer); + payload->filename, hostname, error_buffer); } else { _alpm_log(handle, ALPM_LOG_DEBUG, "failed retrieving file '%s' from %s : %s\n", - dlfile.filename, hostname, error_buffer); + payload->filename, hostname, error_buffer); } unlink(tempfile); goto cleanup; @@ -342,14 +340,14 @@ static int curl_download_internal(struct dload_payload *payload, !DOUBLE_EQ(bytes_dl, remote_size)) { handle->pm_errno = ALPM_ERR_RETRIEVE; _alpm_log(handle, ALPM_LOG_ERROR, _("%s appears to be truncated: %jd/%jd bytes\n"), - dlfile.filename, (intmax_t)bytes_dl, (intmax_t)remote_size); + payload->filename, (intmax_t)bytes_dl, (intmax_t)remote_size); goto cleanup; } - if(dlfile.cd_filename) { + if(payload->cd_filename) { /* content-disposition header has a better name for our file */ free(destfile); - destfile = get_fullpath(localpath, dlfile.cd_filename, ""); + destfile = get_fullpath(localpath, payload->cd_filename, ""); } else { const char *effective_filename = strrchr(effective_url, '/'); if(effective_filename) { @@ -387,7 +385,6 @@ cleanup: FREE(tempfile); FREE(destfile); - FREE(dlfile.cd_filename); /* restore the old signal handlers */ sigaction(SIGINT, &sig_int[OLD], NULL); @@ -495,6 +492,7 @@ void _alpm_dload_payload_free(struct dload_payload *payload) { ASSERT(load, return); FREE(load->fileurl); + FREE(load->cd_filename); FREE(load); } diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index 3945d245..341a4a1a 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -25,18 +25,12 @@ #include -/* internal structure for communicating with curl progress callback */ -struct fileinfo { +struct dload_payload { alpm_handle_t *handle; const char *filename; char *cd_filename; - double initial_size; -}; - -struct dload_payload { - alpm_handle_t *handle; - char *filename; char *fileurl; + double initial_size; long max_size; int force; int allow_resume; -- cgit v1.2.3-70-g09d2