metalink: build fixes and adjustments II
Additionally, make hash checking ability mandatory in order to allow metalink support in curl. A command line option could be introduced to skip hash checking at runtime, but the ability to check hashes should always be built-in when providing metalink support.
This commit is contained in:
@@ -39,11 +39,11 @@
|
|||||||
#include "tool_help.h"
|
#include "tool_help.h"
|
||||||
#include "tool_helpers.h"
|
#include "tool_helpers.h"
|
||||||
#include "tool_libinfo.h"
|
#include "tool_libinfo.h"
|
||||||
|
#include "tool_metalink.h"
|
||||||
#include "tool_msgs.h"
|
#include "tool_msgs.h"
|
||||||
#include "tool_paramhlp.h"
|
#include "tool_paramhlp.h"
|
||||||
#include "tool_parsecfg.h"
|
#include "tool_parsecfg.h"
|
||||||
#include "tool_version.h"
|
#include "tool_version.h"
|
||||||
#include "tool_metalink.h"
|
|
||||||
|
|
||||||
#include "memdebug.h" /* keep this as LAST include */
|
#include "memdebug.h" /* keep this as LAST include */
|
||||||
|
|
||||||
|
@@ -21,26 +21,43 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "tool_setup.h"
|
#include "tool_setup.h"
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_FCNTL_H
|
|
||||||
# include <fcntl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_METALINK
|
#ifdef USE_METALINK
|
||||||
|
|
||||||
#include <metalink/metalink_parser.h>
|
#include <metalink/metalink_parser.h>
|
||||||
|
|
||||||
|
#ifdef USE_SSLEAY
|
||||||
|
# ifdef USE_OPENSSL
|
||||||
|
# include <openssl/md5.h>
|
||||||
|
# include <openssl/sha.h>
|
||||||
|
# else
|
||||||
|
# include <md5.h>
|
||||||
|
# include <sha.h>
|
||||||
|
# endif
|
||||||
|
#elif defined(USE_GNUTLS_NETTLE)
|
||||||
|
# include <nettle/md5.h>
|
||||||
|
# include <nettle/sha.h>
|
||||||
|
# define MD5_CTX struct md5_ctx
|
||||||
|
# define SHA_CTX struct sha1_ctx
|
||||||
|
# define SHA256_CTX struct sha256_ctx
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
# include <gcrypt.h>
|
||||||
|
# define MD5_CTX gcry_md_hd_t
|
||||||
|
# define SHA_CTX gcry_md_hd_t
|
||||||
|
# define SHA256_CTX gcry_md_hd_t
|
||||||
|
#else
|
||||||
|
# error "Can't compile METALINK support without a crypto library."
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "rawstr.h"
|
#include "rawstr.h"
|
||||||
|
|
||||||
#include "tool_metalink.h"
|
#define ENABLE_CURLX_PRINTF
|
||||||
|
/* use our own printf() functions */
|
||||||
|
#include "curlx.h"
|
||||||
|
|
||||||
#include "tool_getparam.h"
|
#include "tool_getparam.h"
|
||||||
#include "tool_paramhlp.h"
|
#include "tool_paramhlp.h"
|
||||||
#include "tool_cfgable.h"
|
#include "tool_cfgable.h"
|
||||||
|
#include "tool_metalink.h"
|
||||||
|
|
||||||
#include "memdebug.h" /* keep this as LAST include */
|
#include "memdebug.h" /* keep this as LAST include */
|
||||||
|
|
||||||
@@ -56,151 +73,6 @@
|
|||||||
return PARAM_NO_MEM; \
|
return PARAM_NO_MEM; \
|
||||||
} WHILE_FALSE
|
} WHILE_FALSE
|
||||||
|
|
||||||
#ifdef USE_GNUTLS_NETTLE
|
|
||||||
|
|
||||||
#include <nettle/md5.h>
|
|
||||||
#include <nettle/sha.h>
|
|
||||||
|
|
||||||
typedef struct md5_ctx MD5_CTX;
|
|
||||||
|
|
||||||
static void MD5_Init(MD5_CTX * ctx)
|
|
||||||
{
|
|
||||||
md5_init(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MD5_Update(MD5_CTX * ctx,
|
|
||||||
const unsigned char * input,
|
|
||||||
unsigned int inputLen)
|
|
||||||
{
|
|
||||||
md5_update(ctx, inputLen, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
|
|
||||||
{
|
|
||||||
md5_digest(ctx, 16, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct sha1_ctx SHA_CTX;
|
|
||||||
|
|
||||||
static void SHA1_Init(SHA_CTX *ctx)
|
|
||||||
{
|
|
||||||
sha1_init(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA1_Update(SHA_CTX *ctx,
|
|
||||||
const unsigned char * input,
|
|
||||||
unsigned int inputLen)
|
|
||||||
{
|
|
||||||
sha1_update(ctx, inputLen, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA1_Final(unsigned char digest[20], SHA_CTX * ctx)
|
|
||||||
{
|
|
||||||
sha1_digest(ctx, 20, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct sha256_ctx SHA256_CTX;
|
|
||||||
|
|
||||||
static void SHA256_Init(SHA256_CTX *ctx)
|
|
||||||
{
|
|
||||||
sha256_init(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA256_Update(SHA256_CTX *ctx,
|
|
||||||
const unsigned char * input,
|
|
||||||
unsigned int inputLen)
|
|
||||||
{
|
|
||||||
sha256_update(ctx, inputLen, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
|
|
||||||
{
|
|
||||||
sha256_digest(ctx, 32, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifdef USE_GNUTLS
|
|
||||||
|
|
||||||
#include <gcrypt.h>
|
|
||||||
|
|
||||||
typedef gcry_md_hd_t MD5_CTX;
|
|
||||||
|
|
||||||
static void MD5_Init(MD5_CTX * ctx)
|
|
||||||
{
|
|
||||||
gcry_md_open(ctx, GCRY_MD_MD5, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MD5_Update(MD5_CTX * ctx,
|
|
||||||
const unsigned char * input,
|
|
||||||
unsigned int inputLen)
|
|
||||||
{
|
|
||||||
gcry_md_write(*ctx, input, inputLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
|
|
||||||
{
|
|
||||||
memcpy(digest, gcry_md_read(*ctx, 0), 16);
|
|
||||||
gcry_md_close(*ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef gcry_md_hd_t SHA_CTX;
|
|
||||||
|
|
||||||
static void SHA1_Init(SHA_CTX * ctx)
|
|
||||||
{
|
|
||||||
gcry_md_open(ctx, GCRY_MD_SHA1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA1_Update(SHA_CTX * ctx,
|
|
||||||
const unsigned char * input,
|
|
||||||
unsigned int inputLen)
|
|
||||||
{
|
|
||||||
gcry_md_write(*ctx, input, inputLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA1_Final(unsigned char digest[20], SHA_CTX * ctx)
|
|
||||||
{
|
|
||||||
memcpy(digest, gcry_md_read(*ctx, 0), 20);
|
|
||||||
gcry_md_close(*ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef gcry_md_hd_t SHA256_CTX;
|
|
||||||
|
|
||||||
static void SHA256_Init(SHA256_CTX * ctx)
|
|
||||||
{
|
|
||||||
gcry_md_open(ctx, GCRY_MD_SHA256, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA256_Update(SHA256_CTX * ctx,
|
|
||||||
const unsigned char * input,
|
|
||||||
unsigned int inputLen)
|
|
||||||
{
|
|
||||||
gcry_md_write(*ctx, input, inputLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
|
|
||||||
{
|
|
||||||
memcpy(digest, gcry_md_read(*ctx, 0), 32);
|
|
||||||
gcry_md_close(*ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
# include <openssl/md5.h>
|
|
||||||
# include <openssl/sha.h>
|
|
||||||
#else /* USE_OPENSSL */
|
|
||||||
|
|
||||||
/* TODO hash functions for other libraries here */
|
|
||||||
|
|
||||||
#endif /* USE_OPENSSL */
|
|
||||||
|
|
||||||
#endif /* USE_GNUTLS */
|
|
||||||
|
|
||||||
#endif /* USE_GNUTLS_NETTLE */
|
|
||||||
|
|
||||||
#ifdef METALINK_HASH_CHECK
|
|
||||||
|
|
||||||
const digest_params MD5_DIGEST_PARAMS[] = {
|
const digest_params MD5_DIGEST_PARAMS[] = {
|
||||||
{
|
{
|
||||||
(Curl_digest_init_func) MD5_Init,
|
(Curl_digest_init_func) MD5_Init,
|
||||||
@@ -231,6 +103,145 @@ const digest_params SHA256_DIGEST_PARAMS[] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const metalink_digest_def SHA256_DIGEST_DEF[] = {
|
||||||
|
{"sha-256", SHA256_DIGEST_PARAMS}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const metalink_digest_def SHA1_DIGEST_DEF[] = {
|
||||||
|
{"sha-1", SHA1_DIGEST_PARAMS}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const metalink_digest_def MD5_DIGEST_DEF[] = {
|
||||||
|
{"md5", MD5_DIGEST_PARAMS}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The alias of supported hash functions in the order by preference
|
||||||
|
* (basically stronger hash comes first). We included "sha-256" and
|
||||||
|
* "sha256". The former is the name defined in the IANA registry named
|
||||||
|
* "Hash Function Textual Names". The latter is widely (and
|
||||||
|
* historically) used in Metalink version 3.
|
||||||
|
*/
|
||||||
|
static const metalink_digest_alias digest_aliases[] = {
|
||||||
|
{"sha-256", SHA256_DIGEST_DEF},
|
||||||
|
{"sha256", SHA256_DIGEST_DEF},
|
||||||
|
{"sha-1", SHA1_DIGEST_DEF},
|
||||||
|
{"sha1", SHA1_DIGEST_DEF},
|
||||||
|
{"md5", MD5_DIGEST_DEF},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef USE_GNUTLS_NETTLE
|
||||||
|
|
||||||
|
static void MD5_Init(MD5_CTX *ctx)
|
||||||
|
{
|
||||||
|
md5_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MD5_Update(MD5_CTX *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned int inputLen)
|
||||||
|
{
|
||||||
|
md5_update(ctx, inputLen, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
|
||||||
|
{
|
||||||
|
md5_digest(ctx, 16, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA1_Init(SHA_CTX *ctx)
|
||||||
|
{
|
||||||
|
sha1_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA1_Update(SHA_CTX *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned int inputLen)
|
||||||
|
{
|
||||||
|
sha1_update(ctx, inputLen, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
|
||||||
|
{
|
||||||
|
sha1_digest(ctx, 20, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA256_Init(SHA256_CTX *ctx)
|
||||||
|
{
|
||||||
|
sha256_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA256_Update(SHA256_CTX *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned int inputLen)
|
||||||
|
{
|
||||||
|
sha256_update(ctx, inputLen, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
|
||||||
|
{
|
||||||
|
sha256_digest(ctx, 32, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
|
||||||
|
static void MD5_Init(MD5_CTX *ctx)
|
||||||
|
{
|
||||||
|
gcry_md_open(ctx, GCRY_MD_MD5, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MD5_Update(MD5_CTX *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned int inputLen)
|
||||||
|
{
|
||||||
|
gcry_md_write(*ctx, input, inputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
|
||||||
|
{
|
||||||
|
memcpy(digest, gcry_md_read(*ctx, 0), 16);
|
||||||
|
gcry_md_close(*ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA1_Init(SHA_CTX *ctx)
|
||||||
|
{
|
||||||
|
gcry_md_open(ctx, GCRY_MD_SHA1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA1_Update(SHA_CTX *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned int inputLen)
|
||||||
|
{
|
||||||
|
gcry_md_write(*ctx, input, inputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
|
||||||
|
{
|
||||||
|
memcpy(digest, gcry_md_read(*ctx, 0), 20);
|
||||||
|
gcry_md_close(*ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA256_Init(SHA256_CTX *ctx)
|
||||||
|
{
|
||||||
|
gcry_md_open(ctx, GCRY_MD_SHA256, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA256_Update(SHA256_CTX *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned int inputLen)
|
||||||
|
{
|
||||||
|
gcry_md_write(*ctx, input, inputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
|
||||||
|
{
|
||||||
|
memcpy(digest, gcry_md_read(*ctx, 0), 32);
|
||||||
|
gcry_md_close(*ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CRYPTO LIBS */
|
||||||
|
|
||||||
digest_context *Curl_digest_init(const digest_params *dparams)
|
digest_context *Curl_digest_init(const digest_params *dparams)
|
||||||
{
|
{
|
||||||
digest_context *ctxt;
|
digest_context *ctxt;
|
||||||
@@ -274,34 +285,6 @@ int Curl_digest_final(digest_context *context, unsigned char *result)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const metalink_digest_def SHA256_DIGEST_DEF[] = {
|
|
||||||
{"sha-256", SHA256_DIGEST_PARAMS}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const metalink_digest_def SHA1_DIGEST_DEF[] = {
|
|
||||||
{"sha-1", SHA1_DIGEST_PARAMS}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const metalink_digest_def MD5_DIGEST_DEF[] = {
|
|
||||||
{"md5", MD5_DIGEST_PARAMS}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The alias of supported hash functions in the order by preference
|
|
||||||
* (basically stronger hash comes first). We included "sha-256" and
|
|
||||||
* "sha256". The former is the name defined in the IANA registry named
|
|
||||||
* "Hash Function Textual Names". The latter is widely (and
|
|
||||||
* historically) used in Metalink version 3.
|
|
||||||
*/
|
|
||||||
static const metalink_digest_alias digest_aliases[] = {
|
|
||||||
{"sha-256", SHA256_DIGEST_DEF},
|
|
||||||
{"sha256", SHA256_DIGEST_DEF},
|
|
||||||
{"sha-1", SHA1_DIGEST_DEF},
|
|
||||||
{"sha1", SHA1_DIGEST_DEF},
|
|
||||||
{"md5", MD5_DIGEST_DEF},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static unsigned char hex_to_uint(const char *s)
|
static unsigned char hex_to_uint(const char *s)
|
||||||
{
|
{
|
||||||
int v[2];
|
int v[2];
|
||||||
@@ -414,10 +397,6 @@ int metalink_check_hash(struct Configurable *config,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* METALINK_HASH_CHECK */
|
|
||||||
|
|
||||||
#ifdef USE_METALINK
|
|
||||||
|
|
||||||
static metalink_checksum *new_metalink_checksum(const char *hash_name,
|
static metalink_checksum *new_metalink_checksum(const char *hash_name,
|
||||||
const char *hash_value)
|
const char *hash_value)
|
||||||
{
|
{
|
||||||
@@ -538,8 +517,6 @@ int parse_metalink(struct Configurable *config, const char *infile)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* USE_METALINK */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns nonzero if content_type includes mediatype.
|
* Returns nonzero if content_type includes mediatype.
|
||||||
*/
|
*/
|
||||||
|
@@ -23,13 +23,6 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "tool_setup.h"
|
#include "tool_setup.h"
|
||||||
|
|
||||||
struct Configurable;
|
|
||||||
|
|
||||||
#if defined(USE_OPENSSL) || defined(USE_GNUTLS)
|
|
||||||
/* Define 1 if hash check is enabled in Metalink transfer */
|
|
||||||
# define METALINK_HASH_CHECK 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct metalink_checksum {
|
typedef struct metalink_checksum {
|
||||||
struct metalink_checksum *next;
|
struct metalink_checksum *next;
|
||||||
char *hash_name;
|
char *hash_name;
|
||||||
@@ -49,17 +42,13 @@ typedef struct metalinkfile {
|
|||||||
metalink_resource *resource;
|
metalink_resource *resource;
|
||||||
} metalinkfile;
|
} metalinkfile;
|
||||||
|
|
||||||
|
#ifdef USE_METALINK
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Counts the resource in the metalinkfile.
|
* Counts the resource in the metalinkfile.
|
||||||
*/
|
*/
|
||||||
#ifdef USE_METALINK
|
|
||||||
int count_next_metalink_resource(metalinkfile *mlfile);
|
int count_next_metalink_resource(metalinkfile *mlfile);
|
||||||
void clean_metalink(struct Configurable *config);
|
void clean_metalink(struct Configurable *config);
|
||||||
#else
|
|
||||||
#define count_next_metalink_resource(x) 0
|
|
||||||
#define clean_metalink(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int parse_metalink(struct Configurable *config, const char *infile);
|
int parse_metalink(struct Configurable *config, const char *infile);
|
||||||
|
|
||||||
@@ -126,4 +115,11 @@ int metalink_check_hash(struct Configurable *config,
|
|||||||
metalinkfile *mlfile,
|
metalinkfile *mlfile,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
|
#else /* USE_METALINK */
|
||||||
|
|
||||||
|
#define count_next_metalink_resource(x) 0
|
||||||
|
#define clean_metalink(x) Curl_nop_stmt
|
||||||
|
|
||||||
|
#endif /* USE_METALINK */
|
||||||
|
|
||||||
#endif /* HEADER_CURL_TOOL_METALINK_H */
|
#endif /* HEADER_CURL_TOOL_METALINK_H */
|
||||||
|
@@ -65,6 +65,7 @@
|
|||||||
#include "tool_homedir.h"
|
#include "tool_homedir.h"
|
||||||
#include "tool_libinfo.h"
|
#include "tool_libinfo.h"
|
||||||
#include "tool_main.h"
|
#include "tool_main.h"
|
||||||
|
#include "tool_metalink.h"
|
||||||
#include "tool_msgs.h"
|
#include "tool_msgs.h"
|
||||||
#include "tool_operate.h"
|
#include "tool_operate.h"
|
||||||
#include "tool_operhlp.h"
|
#include "tool_operhlp.h"
|
||||||
@@ -1577,14 +1578,12 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
fprintf(config->errors, "Could not parse Metalink file.\n");
|
fprintf(config->errors, "Could not parse Metalink file.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# ifdef METALINK_HASH_CHECK
|
|
||||||
else if(metalink && res == CURLE_OK && !metalink_next_res) {
|
else if(metalink && res == CURLE_OK && !metalink_next_res) {
|
||||||
int rv = metalink_check_hash(config, mlfile, outs.filename);
|
int rv = metalink_check_hash(config, mlfile, outs.filename);
|
||||||
if(rv == 0) {
|
if(rv == 0) {
|
||||||
metalink_next_res = 1;
|
metalink_next_res = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# endif /* METALINK_HASH_CHECK */
|
|
||||||
#endif /* USE_METALINK */
|
#endif /* USE_METALINK */
|
||||||
|
|
||||||
/* No more business with this output struct */
|
/* No more business with this output struct */
|
||||||
|
Reference in New Issue
Block a user