downloads: open FILE in advance and use default write handler

Now that the number of pending downloads is kept below a certain limit
(see poll_fewer_than()) it is possible to open files before starting
the transfer. Using the default curl write handler and explicit
open/close of the file makes the code simpler.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
This commit is contained in:
Patrick Ohly
2016-11-15 16:42:51 -08:00
committed by tmarcu
parent e6653ad185
commit 4e35578896
3 changed files with 19 additions and 51 deletions
+2 -3
View File
@@ -91,7 +91,6 @@ struct file {
int last_change;
struct update_stat stat;
unsigned int fd_valid : 1;
unsigned int is_dir : 1;
unsigned int is_file : 1;
unsigned int is_link : 1;
@@ -112,7 +111,7 @@ struct file {
char *staging; /* output name used during download & staging */
CURL *curl; /* curl handle if downloading */
int fd; /* file written into during downloading, unset when fd_valid is false */
FILE *fh; /* file written into during downloading */
};
extern bool download_only;
@@ -232,7 +231,7 @@ extern void swupd_curl_cleanup(void);
extern void swupd_curl_set_current_version(int v);
extern void swupd_curl_set_requested_version(int v);
extern double swupd_query_url_content_size(char *url);
extern size_t swupd_download_file(void *ptr, size_t size, size_t nmemb, void *userdata);
extern CURLcode swupd_download_file_start(struct file *file);
extern CURLcode swupd_download_file_complete(CURLcode curl_ret, struct file *file);
extern int swupd_curl_get_file(const char *url, char *filename, struct file *file,
struct version_container *tmp_version, bool pack);
+13 -46
View File
@@ -158,62 +158,28 @@ static size_t swupd_download_version_to_memory(void *ptr, size_t size, size_t nm
return data_len;
}
/* curl easy CURLOPT_WRITEFUNCTION callback */
size_t swupd_download_file(void *ptr, size_t size, size_t nmemb, void *userdata)
CURLcode swupd_download_file_start(struct file *file)
{
struct file *file = (struct file *)userdata;
const char *outfile;
int fd;
FILE *f;
size_t written, remaining;
outfile = file->staging;
if (file->fd_valid) {
fd = file->fd;
} else {
fd = open(outfile, O_CREAT | O_RDWR | O_CLOEXEC | O_APPEND, 00600);
if (fd < 0) {
fprintf(stderr, "Cannot open file for write \\*outfile=\"%s\",strerror=\"%s\"*\\\n",
outfile, strerror(errno));
return -1;
}
file->fd = fd;
file->fd_valid = 1;
file->fh = fopen(file->staging, "w");
if (!file->fh) {
fprintf(stderr, "Cannot open file for write \\*outfile=\"%s\",strerror=\"%s\"*\\\n",
file->staging, strerror(errno));
return CURLE_WRITE_ERROR;
}
/* handle short writes with repeated write() calls */
for (remaining = size * nmemb; remaining; remaining -= written) {
written = write(fd, ptr, size*nmemb);
if (written < 0) {
if (errno == EINTR) {
written = 0;
continue;
}
fprintf(stderr, "write error \\*outfile=\"%s\",strerror=\"%s\"*\\\n",
outfile, strerror(errno));
return -1;
}
}
if (fdatasync(fd)) {
fprintf(stderr, "fdatasync \\*outfile=\"%s\",strerror=\"%s\"*\\\n", outfile, strerror(errno));
return -1;
}
return size*nmemb;
return CURLE_OK;
}
CURLcode swupd_download_file_complete(CURLcode curl_ret, struct file *file)
{
if (file->fd_valid) {
if (close(file->fd)) {
if (file->fh) {
if (fclose(file->fh)) {
fprintf(stderr, "Cannot close file after write \\*outfile=\"%s\",strerror=\"%s\"*\\\n",
file->staging, strerror(errno));
if (curl_ret == CURLE_OK) {
curl_ret = CURLE_WRITE_ERROR;
}
}
file->fd_valid = 0;
file->fh = NULL;
}
return curl_ret;
}
@@ -246,6 +212,7 @@ int swupd_curl_get_file(const char *url, char *filename, struct file *file,
if (file) {
local = file;
local->fh = NULL;
} else {
local = calloc(1, sizeof(struct file));
if (!local) {
@@ -266,11 +233,11 @@ int swupd_curl_get_file(const char *url, char *filename, struct file *file,
if (curl_ret != CURLE_OK) {
goto exit;
}
curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, swupd_download_file);
curl_ret = swupd_download_file_start(local);
if (curl_ret != CURLE_OK) {
goto exit;
}
curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)local);
curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)local->fh);
if (curl_ret != CURLE_OK) {
goto exit;
}
+4 -2
View File
@@ -525,6 +525,7 @@ void full_download(struct file *file)
CURLMcode curlm_ret = CURLM_OK;
CURLcode curl_ret = CURLE_OK;
file->fh = NULL;
ret = swupd_curl_hashmap_insert(file);
if (ret > 0) { /* no download needed */
/* File already exists - report success */
@@ -567,11 +568,11 @@ void full_download(struct file *file)
if (curl_ret != CURLE_OK) {
goto out_bad;
}
curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, swupd_download_file);
curl_ret = swupd_download_file_start(file);
if (curl_ret != CURLE_OK) {
goto out_bad;
}
curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file);
curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file->fh);
if (curl_ret != CURLE_OK) {
goto out_bad;
}
@@ -597,6 +598,7 @@ void full_download(struct file *file)
goto out_good;
out_bad:
(void) swupd_download_file_complete(CURLE_OK, file);
failed = list_prepend_data(failed, file);
if (curl != NULL) {
/* Must remove handle out of multi queue first!*/