Implement Metalink/XML --directory-prefix option in Metalink module

* NEWS: Mention the effect of --directory-prefix over Metalink
* src/metalink.c (retrieve_from_metalink): Add opt.dir_prefix as
  prefix to the metalink:file name mfile->name
* doc/metalink.txt: Update document. Explain --directory-prefix

When --directory-prefix=<prefix> is used, set the top of the retrieval
tree to prefix. The default is . (the current directory). Metalink/XML
and Metalink/HTTP files will be downloaded under prefix.
This commit is contained in:
Matthew White 2016-08-17 04:45:06 +02:00
parent 666b7862bf
commit 7d4942864b
3 changed files with 40 additions and 32 deletions

3
NEWS
View File

@ -9,6 +9,9 @@ Please send GNU Wget bug reports to <bug-wget@gnu.org>.
* Changes in Wget X.Y.Z * Changes in Wget X.Y.Z
* When processing a Metalink file, --directory-prefix=<prefix> sets
the top of the retrieval tree to prefix for Metalink downloads.
* When processing a Metalink file, reject downloaded files which don't * When processing a Metalink file, reject downloaded files which don't
agree with their own metalink:size value: agree with their own metalink:size value:
https://tools.ietf.org/html/rfc5854#section-4.2.16 https://tools.ietf.org/html/rfc5854#section-4.2.16

View File

@ -157,9 +157,5 @@ References:
'-P prefix' '-P prefix'
'--directory-prefix=prefix' '--directory-prefix=prefix'
Do not apply to Metalink/XML files (aka --input-metalink=<file>). Set the top of the retrieval tree to prefix for both Metalink/XML
and Metalink/HTTP downloads, see wget(1).
Apply to Metalink/HTTP downloads.
The directory prefix is the directory where all other files and
subdirectories will be saved to, see wget(1).

View File

@ -87,6 +87,7 @@ retrieve_from_metalink (const metalink_t* metalink)
metalink_file_t *mfile = *mfile_ptr; metalink_file_t *mfile = *mfile_ptr;
metalink_resource_t **mres_ptr; metalink_resource_t **mres_ptr;
char *filename = NULL; char *filename = NULL;
char *destname = NULL;
bool hash_ok = false; bool hash_ok = false;
uerr_t retr_err = METALINK_MISSING_RESOURCE; uerr_t retr_err = METALINK_MISSING_RESOURCE;
@ -100,6 +101,13 @@ retrieve_from_metalink (const metalink_t* metalink)
output_stream = NULL; output_stream = NULL;
/* The directory prefix for opt.metalink_over_http is handled by
src/url.c (url_file_name), do not add it a second time. */
if (!metalink->origin && opt.dir_prefix && strlen (opt.dir_prefix))
filename = aprintf ("%s/%s", opt.dir_prefix, mfile->name);
else
filename = xstrdup (mfile->name);
DEBUGP (("Processing metalink file %s...\n", quote (mfile->name))); DEBUGP (("Processing metalink file %s...\n", quote (mfile->name)));
/* Resources are sorted by priority. */ /* Resources are sorted by priority. */
@ -133,12 +141,12 @@ retrieve_from_metalink (const metalink_t* metalink)
fclose (output_stream); fclose (output_stream);
output_stream = NULL; output_stream = NULL;
badhash_or_remove (filename); badhash_or_remove (destname);
xfree (filename); xfree (destname);
} }
else if (!output_stream && filename) else if (!output_stream && destname)
{ {
xfree (filename); xfree (destname);
} }
retr_err = METALINK_RETR_ERROR; retr_err = METALINK_RETR_ERROR;
@ -180,10 +188,10 @@ retrieve_from_metalink (const metalink_t* metalink)
after we are finished with the file. */ after we are finished with the file. */
if (opt.always_rest) if (opt.always_rest)
/* continue previous download */ /* continue previous download */
output_stream = fopen (mfile->name, "ab"); output_stream = fopen (filename, "ab");
else else
/* create a file with an unique name */ /* create a file with an unique name */
output_stream = unique_create (mfile->name, true, &filename); output_stream = unique_create (filename, true, &destname);
} }
output_stream_regular = true; output_stream_regular = true;
@ -203,27 +211,27 @@ retrieve_from_metalink (const metalink_t* metalink)
* src/http.c (open_output_stream): If output_stream is * src/http.c (open_output_stream): If output_stream is
NULL, create the opt.output_document "path/file" NULL, create the opt.output_document "path/file"
*/ */
if (!filename) if (!destname)
filename = xstrdup (mfile->name); destname = xstrdup (filename);
/* Store the real file name for displaying in messages, /* Store the real file name for displaying in messages,
and for proper RFC5854 "path/file" handling. */ and for proper RFC5854 "path/file" handling. */
opt.output_document = filename; opt.output_document = destname;
opt.metalink_over_http = false; opt.metalink_over_http = false;
DEBUGP (("Storing to %s\n", filename)); DEBUGP (("Storing to %s\n", destname));
retr_err = retrieve_url (url, mres->url, NULL, NULL, retr_err = retrieve_url (url, mres->url, NULL, NULL,
NULL, NULL, opt.recursive, iri, false); NULL, NULL, opt.recursive, iri, false);
opt.metalink_over_http = _metalink_http; opt.metalink_over_http = _metalink_http;
/* /*
Bug: output_stream is NULL, but retrieve_url() somehow Bug: output_stream is NULL, but retrieve_url() somehow
created filename. created destname.
Bugfix: point output_stream to filename if it exists. Bugfix: point output_stream to destname if it exists.
*/ */
if (!output_stream && file_exists_p (filename)) if (!output_stream && file_exists_p (destname))
output_stream = fopen (filename, "ab"); output_stream = fopen (destname, "ab");
} }
url_free (url); url_free (url);
iri_free (iri); iri_free (iri);
@ -233,14 +241,14 @@ retrieve_from_metalink (const metalink_t* metalink)
FILE *local_file; FILE *local_file;
/* Check the digest. */ /* Check the digest. */
local_file = fopen (filename, "rb"); local_file = fopen (destname, "rb");
if (!local_file) if (!local_file)
{ {
logprintf (LOG_NOTQUIET, _("Could not open downloaded file.\n")); logprintf (LOG_NOTQUIET, _("Could not open downloaded file.\n"));
continue; continue;
} }
logprintf (LOG_VERBOSE, _("Computing size for %s\n"), quote (filename)); logprintf (LOG_VERBOSE, _("Computing size for %s\n"), quote (destname));
if (!mfile->size) if (!mfile->size)
{ {
@ -248,7 +256,7 @@ retrieve_from_metalink (const metalink_t* metalink)
} }
else else
{ {
wgint local_file_size = file_size (filename); wgint local_file_size = file_size (destname);
if (local_file_size == -1) if (local_file_size == -1)
{ {
@ -264,7 +272,7 @@ retrieve_from_metalink (const metalink_t* metalink)
if (local_file_size != (wgint) mfile->size) if (local_file_size != (wgint) mfile->size)
{ {
logprintf (LOG_NOTQUIET, _("Size mismatch for file %s.\n"), quote (filename)); logprintf (LOG_NOTQUIET, _("Size mismatch for file %s.\n"), quote (destname));
fclose (local_file); fclose (local_file);
local_file = NULL; local_file = NULL;
continue; continue;
@ -325,7 +333,7 @@ retrieve_from_metalink (const metalink_t* metalink)
} }
logprintf (LOG_VERBOSE, _("Computing checksum for %s\n"), logprintf (LOG_VERBOSE, _("Computing checksum for %s\n"),
quote (filename)); quote (destname));
DEBUGP (("Declared hash: %s\n", mchksum->hash)); DEBUGP (("Declared hash: %s\n", mchksum->hash));
@ -408,7 +416,7 @@ retrieve_from_metalink (const metalink_t* metalink)
{ {
logprintf (LOG_NOTQUIET, logprintf (LOG_NOTQUIET,
_("Checksum mismatch for file %s.\n"), _("Checksum mismatch for file %s.\n"),
quote (filename)); quote (destname));
} }
/* Stop as soon as we checked the supported checksum. */ /* Stop as soon as we checked the supported checksum. */
@ -443,7 +451,7 @@ retrieve_from_metalink (const metalink_t* metalink)
gpgme_check_version (NULL); gpgme_check_version (NULL);
/* Open data file. */ /* Open data file. */
fd = open (filename, O_RDONLY); fd = open (destname, O_RDONLY);
if (fd == -1) if (fd == -1)
{ {
logputs (LOG_NOTQUIET, logputs (LOG_NOTQUIET,
@ -592,14 +600,14 @@ gpg_skip_verification:
if (retr_err != RETROK) if (retr_err != RETROK)
{ {
logprintf (LOG_VERBOSE, _("Failed to download %s. Skipping resource.\n"), logprintf (LOG_VERBOSE, _("Failed to download %s. Skipping resource.\n"),
quote (filename ? filename : mfile->name)); quote (destname ? destname : filename));
} }
else if (!hash_ok) else if (!hash_ok)
{ {
retr_err = METALINK_CHKSUM_ERROR; retr_err = METALINK_CHKSUM_ERROR;
logprintf (LOG_NOTQUIET, logprintf (LOG_NOTQUIET,
_("File %s retrieved but checksum does not match. " _("File %s retrieved but checksum does not match. "
"\n"), quote (filename)); "\n"), quote (destname));
} }
#ifdef HAVE_GPGME #ifdef HAVE_GPGME
/* Signature will be only validated if hash check was successful. */ /* Signature will be only validated if hash check was successful. */
@ -608,7 +616,7 @@ gpg_skip_verification:
retr_err = METALINK_SIG_ERROR; retr_err = METALINK_SIG_ERROR;
logprintf (LOG_NOTQUIET, logprintf (LOG_NOTQUIET,
_("File %s retrieved but signature does not match. " _("File %s retrieved but signature does not match. "
"\n"), quote (filename)); "\n"), quote (destname));
} }
#endif #endif
last_retr_err = retr_err == RETROK ? last_retr_err : retr_err; last_retr_err = retr_err == RETROK ? last_retr_err : retr_err;
@ -617,15 +625,16 @@ gpg_skip_verification:
Note: the file has been downloaded using *_loop. Therefore, it Note: the file has been downloaded using *_loop. Therefore, it
is not necessary to keep the file for continuated download. */ is not necessary to keep the file for continuated download. */
if (((retr_err != RETROK && !opt.always_rest) || opt.delete_after) if (((retr_err != RETROK && !opt.always_rest) || opt.delete_after)
&& filename != NULL && file_exists_p (filename)) && destname != NULL && file_exists_p (destname))
{ {
badhash_or_remove (filename); badhash_or_remove (destname);
} }
if (output_stream) if (output_stream)
{ {
fclose (output_stream); fclose (output_stream);
output_stream = NULL; output_stream = NULL;
} }
xfree (destname);
xfree (filename); xfree (filename);
} /* Iterate over files. */ } /* Iterate over files. */