1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
22 #include "tool_setup.h"
34 # include <openssl/md5.h>
35 # include <openssl/sha.h>
40 #elif defined(USE_GNUTLS_NETTLE)
41 # include <nettle/md5.h>
42 # include <nettle/sha.h>
43 # define MD5_CTX struct md5_ctx
44 # define SHA_CTX struct sha1_ctx
45 # define SHA256_CTX struct sha256_ctx
46 #elif defined(USE_GNUTLS)
48 # define MD5_CTX gcry_md_hd_t
49 # define SHA_CTX gcry_md_hd_t
50 # define SHA256_CTX gcry_md_hd_t
51 #elif defined(USE_NSS)
54 # define MD5_CTX void *
55 # define SHA_CTX void *
56 # define SHA256_CTX void *
57 static NSSInitContext *nss_context;
58 #elif defined(USE_POLARSSL)
59 # include <polarssl/md5.h>
60 # include <polarssl/sha1.h>
61 # include <polarssl/sha256.h>
62 # define MD5_CTX md5_context
63 # define SHA_CTX sha1_context
64 # define SHA256_CTX sha256_context
65 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
66 (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
67 (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
68 (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
69 /* For Apple operating systems: CommonCrypto has the functions we need.
70 The library's headers are even backward-compatible with OpenSSL's
71 headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
73 These functions are available on Tiger and later, as well as iOS 2.0
74 and later. If you're building for an older cat, well, sorry. */
75 # define COMMON_DIGEST_FOR_OPENSSL
76 # include <CommonCrypto/CommonDigest.h>
78 /* For Windows: If no other crypto library is provided, we fallback
79 to the hash functions provided within the Microsoft Windows CryptoAPI */
80 # include <wincrypt.h>
81 /* Custom structure in order to store the required provider and hash handle */
82 struct win32_crypto_hash {
83 HCRYPTPROV hCryptProv;
86 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
87 # ifndef ALG_SID_SHA_256
88 # define ALG_SID_SHA_256 12
91 # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
93 # define MD5_CTX struct win32_crypto_hash
94 # define SHA_CTX struct win32_crypto_hash
95 # define SHA256_CTX struct win32_crypto_hash
97 # error "Can't compile METALINK support without a crypto library."
102 #define ENABLE_CURLX_PRINTF
103 /* use our own printf() functions */
106 #include "tool_getparam.h"
107 #include "tool_paramhlp.h"
108 #include "tool_cfgable.h"
109 #include "tool_metalink.h"
110 #include "tool_msgs.h"
112 #include "memdebug.h" /* keep this as LAST include */
114 /* Copied from tool_getparam.c */
115 #define GetStr(str,val) do { \
121 *(str) = strdup((val)); \
123 return PARAM_NO_MEM; \
126 #ifdef USE_GNUTLS_NETTLE
128 static int MD5_Init(MD5_CTX *ctx)
134 static void MD5_Update(MD5_CTX *ctx,
135 const unsigned char *input,
136 unsigned int inputLen)
138 md5_update(ctx, inputLen, input);
141 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
143 md5_digest(ctx, 16, digest);
146 static int SHA1_Init(SHA_CTX *ctx)
152 static void SHA1_Update(SHA_CTX *ctx,
153 const unsigned char *input,
154 unsigned int inputLen)
156 sha1_update(ctx, inputLen, input);
159 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
161 sha1_digest(ctx, 20, digest);
164 static int SHA256_Init(SHA256_CTX *ctx)
170 static void SHA256_Update(SHA256_CTX *ctx,
171 const unsigned char *input,
172 unsigned int inputLen)
174 sha256_update(ctx, inputLen, input);
177 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
179 sha256_digest(ctx, 32, digest);
182 #elif defined(USE_GNUTLS)
184 static int MD5_Init(MD5_CTX *ctx)
186 gcry_md_open(ctx, GCRY_MD_MD5, 0);
190 static void MD5_Update(MD5_CTX *ctx,
191 const unsigned char *input,
192 unsigned int inputLen)
194 gcry_md_write(*ctx, input, inputLen);
197 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
199 memcpy(digest, gcry_md_read(*ctx, 0), 16);
203 static int SHA1_Init(SHA_CTX *ctx)
205 gcry_md_open(ctx, GCRY_MD_SHA1, 0);
209 static void SHA1_Update(SHA_CTX *ctx,
210 const unsigned char *input,
211 unsigned int inputLen)
213 gcry_md_write(*ctx, input, inputLen);
216 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
218 memcpy(digest, gcry_md_read(*ctx, 0), 20);
222 static int SHA256_Init(SHA256_CTX *ctx)
224 gcry_md_open(ctx, GCRY_MD_SHA256, 0);
228 static void SHA256_Update(SHA256_CTX *ctx,
229 const unsigned char *input,
230 unsigned int inputLen)
232 gcry_md_write(*ctx, input, inputLen);
235 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
237 memcpy(digest, gcry_md_read(*ctx, 0), 32);
241 #elif defined(USE_NSS)
243 static int nss_hash_init(void **pctx, SECOidTag hash_alg)
247 /* we have to initialize NSS if not initialized alraedy */
248 if(!NSS_IsInitialized() && !nss_context) {
249 static NSSInitParameters params;
250 params.length = sizeof params;
251 nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY
252 | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
253 | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
256 ctx = PK11_CreateDigestContext(hash_alg);
258 return /* failure */ 0;
260 if(PK11_DigestBegin(ctx) != SECSuccess) {
261 PK11_DestroyContext(ctx, PR_TRUE);
262 return /* failure */ 0;
266 return /* success */ 1;
269 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
271 PK11Context *ctx = *pctx;
273 PK11_DigestFinal(ctx, out, &outlen, len);
274 PK11_DestroyContext(ctx, PR_TRUE);
277 static int MD5_Init(MD5_CTX *pctx)
279 return nss_hash_init(pctx, SEC_OID_MD5);
282 static void MD5_Update(MD5_CTX *pctx,
283 const unsigned char *input,
284 unsigned int input_len)
286 PK11_DigestOp(*pctx, input, input_len);
289 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
291 nss_hash_final(pctx, digest, 16);
294 static int SHA1_Init(SHA_CTX *pctx)
296 return nss_hash_init(pctx, SEC_OID_SHA1);
299 static void SHA1_Update(SHA_CTX *pctx,
300 const unsigned char *input,
301 unsigned int input_len)
303 PK11_DigestOp(*pctx, input, input_len);
306 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
308 nss_hash_final(pctx, digest, 20);
311 static int SHA256_Init(SHA256_CTX *pctx)
313 return nss_hash_init(pctx, SEC_OID_SHA256);
316 static void SHA256_Update(SHA256_CTX *pctx,
317 const unsigned char *input,
318 unsigned int input_len)
320 PK11_DigestOp(*pctx, input, input_len);
323 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
325 nss_hash_final(pctx, digest, 32);
328 #elif defined(USE_POLARSSL)
330 static int MD5_Init(MD5_CTX *ctx)
336 static void MD5_Update(MD5_CTX *ctx,
337 const unsigned char *input,
338 unsigned int inputLen)
340 md5_update(ctx, input, inputLen);
343 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
345 md5_finish(ctx, digest);
348 static int SHA1_Init(SHA_CTX *ctx)
354 static void SHA1_Update(SHA_CTX *ctx,
355 const unsigned char *input,
356 unsigned int inputLen)
358 sha1_update(ctx, input, inputLen);
361 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
363 sha1_finish(ctx, digest);
366 static int SHA256_Init(SHA256_CTX *ctx)
368 sha256_starts(ctx, 0); /* 0 = sha256 */
372 static void SHA256_Update(SHA256_CTX *ctx,
373 const unsigned char *input,
374 unsigned int inputLen)
376 sha256_update(ctx, input, inputLen);
379 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
381 sha256_finish(ctx, digest);
384 #elif defined(_WIN32) && !defined(USE_SSLEAY)
386 static void win32_crypto_final(struct win32_crypto_hash *ctx,
387 unsigned char *digest,
388 unsigned int digestLen)
390 unsigned long length;
391 CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
392 if(length == digestLen)
393 CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
395 CryptDestroyHash(ctx->hHash);
397 CryptReleaseContext(ctx->hCryptProv, 0);
400 static int MD5_Init(MD5_CTX *ctx)
402 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
403 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
404 CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
409 static void MD5_Update(MD5_CTX *ctx,
410 const unsigned char *input,
411 unsigned int inputLen)
413 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
416 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
418 win32_crypto_final(ctx, digest, 16);
421 static int SHA1_Init(SHA_CTX *ctx)
423 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
424 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
425 CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
430 static void SHA1_Update(SHA_CTX *ctx,
431 const unsigned char *input,
432 unsigned int inputLen)
434 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
437 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
439 win32_crypto_final(ctx, digest, 20);
442 static int SHA256_Init(SHA256_CTX *ctx)
444 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
445 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
446 CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
451 static void SHA256_Update(SHA256_CTX *ctx,
452 const unsigned char *input,
453 unsigned int inputLen)
455 CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
458 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
460 win32_crypto_final(ctx, digest, 32);
463 #endif /* CRYPTO LIBS */
465 const digest_params MD5_DIGEST_PARAMS[] = {
467 (Curl_digest_init_func) MD5_Init,
468 (Curl_digest_update_func) MD5_Update,
469 (Curl_digest_final_func) MD5_Final,
475 const digest_params SHA1_DIGEST_PARAMS[] = {
477 (Curl_digest_init_func) SHA1_Init,
478 (Curl_digest_update_func) SHA1_Update,
479 (Curl_digest_final_func) SHA1_Final,
485 const digest_params SHA256_DIGEST_PARAMS[] = {
487 (Curl_digest_init_func) SHA256_Init,
488 (Curl_digest_update_func) SHA256_Update,
489 (Curl_digest_final_func) SHA256_Final,
495 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
496 {"sha-256", SHA256_DIGEST_PARAMS}
499 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
500 {"sha-1", SHA1_DIGEST_PARAMS}
503 static const metalink_digest_def MD5_DIGEST_DEF[] = {
504 {"md5", MD5_DIGEST_PARAMS}
508 * The alias of supported hash functions in the order by preference
509 * (basically stronger hash comes first). We included "sha-256" and
510 * "sha256". The former is the name defined in the IANA registry named
511 * "Hash Function Textual Names". The latter is widely (and
512 * historically) used in Metalink version 3.
514 static const metalink_digest_alias digest_aliases[] = {
515 {"sha-256", SHA256_DIGEST_DEF},
516 {"sha256", SHA256_DIGEST_DEF},
517 {"sha-1", SHA1_DIGEST_DEF},
518 {"sha1", SHA1_DIGEST_DEF},
519 {"md5", MD5_DIGEST_DEF},
523 digest_context *Curl_digest_init(const digest_params *dparams)
525 digest_context *ctxt;
527 /* Create digest context */
528 ctxt = malloc(sizeof *ctxt);
533 ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
535 if(!ctxt->digest_hashctx) {
540 ctxt->digest_hash = dparams;
542 if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
550 int Curl_digest_update(digest_context *context,
551 const unsigned char *data,
554 (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
559 int Curl_digest_final(digest_context *context, unsigned char *result)
561 (*context->digest_hash->digest_final)(result, context->digest_hashctx);
563 free(context->digest_hashctx);
569 static unsigned char hex_to_uint(const char *s)
573 for(i = 0; i < 2; ++i) {
574 v[i] = Curl_raw_toupper(s[i]);
575 if('0' <= v[i] && v[i] <= '9') {
578 else if('A' <= v[i] && v[i] <= 'Z') {
582 return (unsigned char)((v[0] << 4) | v[1]);
586 * Check checksum of file denoted by filename. The expected hash value
587 * is given in hex_hash which is hex-encoded string.
589 * This function returns 1 if it succeeds or one of the following
593 * Checksum didn't match.
595 * Could not open file; or could not read data from file.
597 * Hash algorithm not available.
599 static int check_hash(const char *filename,
600 const metalink_digest_def *digest_def,
601 const unsigned char *digest, FILE *error)
603 unsigned char *result;
604 digest_context *dctx;
605 int check_ok, flags, fd;
609 /* O_BINARY is required in order to avoid binary EOF in text mode */
613 fd = open(filename, flags);
615 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
616 digest_def->hash_name, strerror(errno));
620 dctx = Curl_digest_init(digest_def->dparams);
622 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
623 digest_def->hash_name, "failed to initialize hash algorithm");
628 result = malloc(digest_def->dparams->digest_resultlen);
630 unsigned char buf[4096];
631 ssize_t len = read(fd, buf, sizeof(buf));
636 fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
637 digest_def->hash_name, strerror(errno));
638 Curl_digest_final(dctx, result);
642 Curl_digest_update(dctx, buf, (unsigned int)len);
644 Curl_digest_final(dctx, result);
645 check_ok = memcmp(result, digest,
646 digest_def->dparams->digest_resultlen) == 0;
647 /* sha*sum style verdict output */
649 fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
650 digest_def->hash_name);
652 fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
653 filename, digest_def->hash_name);
660 int metalink_check_hash(struct GlobalConfig *config,
661 metalinkfile *mlfile,
662 const char *filename)
665 fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
666 if(mlfile->checksum == NULL) {
667 fprintf(config->errors,
668 "Metalink: validating (%s) FAILED (digest missing)\n", filename);
671 rv = check_hash(filename, mlfile->checksum->digest_def,
672 mlfile->checksum->digest, config->errors);
676 static metalink_checksum *new_metalink_checksum_from_hex_digest
677 (const metalink_digest_def *digest_def, const char *hex_digest)
679 metalink_checksum *chksum;
680 unsigned char *digest;
682 size_t len = strlen(hex_digest);
683 digest = malloc(len/2);
684 for(i = 0; i < len; i += 2) {
685 digest[i/2] = hex_to_uint(hex_digest+i);
687 chksum = malloc(sizeof(metalink_checksum));
688 chksum->digest_def = digest_def;
689 chksum->digest = digest;
693 static metalink_resource *new_metalink_resource(const char *url)
695 metalink_resource *res;
696 res = malloc(sizeof(metalink_resource));
698 res->url = strdup(url);
702 /* Returns nonzero if hex_digest is properly formatted; that is each
703 letter is in [0-9A-Za-z] and the length of the string equals to the
704 result length of digest * 2. */
705 static int check_hex_digest(const char *hex_digest,
706 const metalink_digest_def *digest_def)
709 for(i = 0; hex_digest[i]; ++i) {
710 char c = hex_digest[i];
711 if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
712 ('A' <= c && c <= 'Z'))) {
716 return digest_def->dparams->digest_resultlen * 2 == i;
719 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
722 f = (metalinkfile*)malloc(sizeof(metalinkfile));
724 f->filename = strdup(fileinfo->name);
727 if(fileinfo->checksums) {
728 const metalink_digest_alias *digest_alias;
729 for(digest_alias = digest_aliases; digest_alias->alias_name;
731 metalink_checksum_t **p;
732 for(p = fileinfo->checksums; *p; ++p) {
733 if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
734 check_hex_digest((*p)->hash, digest_alias->digest_def)) {
736 new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
746 if(fileinfo->resources) {
747 metalink_resource_t **p;
748 metalink_resource root, *tail;
751 for(p = fileinfo->resources; *p; ++p) {
752 metalink_resource *res;
753 /* Filter by type if it is non-NULL. In Metalink v3, type
754 includes the type of the resource. In curl, we are only
755 interested in HTTP, HTTPS and FTP. In addition to them,
756 Metalink v3 file may contain bittorrent type URL, which
757 points to the BitTorrent metainfo file. We ignore it here.
758 In Metalink v4, type was deprecated and all
759 fileinfo->resources point to the target file. BitTorrent
760 metainfo file URL may be appeared in fileinfo->metaurls.
762 if((*p)->type == NULL ||
763 Curl_raw_equal((*p)->type, "http") ||
764 Curl_raw_equal((*p)->type, "https") ||
765 Curl_raw_equal((*p)->type, "ftp") ||
766 Curl_raw_equal((*p)->type, "ftps")) {
767 res = new_metalink_resource((*p)->url);
772 f->resource = root.next;
777 int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
778 const char *metalink_url)
781 metalink_t* metalink;
782 metalink_file_t **files;
783 bool warnings = FALSE;
785 /* metlaink_parse_final deletes outs->metalink_parser */
786 r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
787 outs->metalink_parser = NULL;
791 if(metalink->files == NULL) {
792 fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
793 "(missing or invalid file name)\n",
795 metalink_delete(metalink);
798 for(files = metalink->files; *files; ++files) {
800 /* Skip an entry which has no resource. */
801 if(!(*files)->resources) {
802 fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
803 "(missing or invalid resource)\n",
804 metalink_url, (*files)->name);
807 if(config->url_get ||
808 ((config->url_get = config->url_list) != NULL)) {
809 /* there's a node here, if it already is filled-in continue to
810 find an "empty" node */
811 while(config->url_get && (config->url_get->flags & GETOUT_URL))
812 config->url_get = config->url_get->next;
815 /* now there might or might not be an available node to fill in! */
819 url = config->url_get;
821 /* there was no free node, create one! */
822 url = new_getout(config);
825 metalinkfile *mlfile;
826 mlfile = new_metalinkfile(*files);
827 if(!mlfile->checksum) {
829 fprintf(config->global->errors,
830 "Metalink: parsing (%s) WARNING (digest missing)\n",
833 /* Set name as url */
834 GetStr(&url->url, mlfile->filename);
836 /* set flag metalink here */
837 url->flags |= GETOUT_URL | GETOUT_METALINK;
839 if(config->metalinkfile_list) {
840 config->metalinkfile_last->next = mlfile;
841 config->metalinkfile_last = mlfile;
844 config->metalinkfile_list = config->metalinkfile_last = mlfile;
848 metalink_delete(metalink);
849 return (warnings) ? -2 : 0;
852 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
855 struct OutStruct *outs = userdata;
856 struct OperationConfig *config = outs->config;
860 * Once that libcurl has called back tool_write_cb() the returned value
861 * is checked against the amount that was intended to be written, if
862 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
863 * point returning a value different from sz*nmemb indicates failure.
865 const size_t failure = (sz * nmemb) ? 0 : 1;
870 rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
874 fprintf(config->global->errors, "Metalink: parsing FAILED\n");
880 * Returns nonzero if content_type includes mediatype.
882 static int check_content_type(const char *content_type, const char *media_type)
884 const char *ptr = content_type;
885 size_t media_type_len = strlen(media_type);
886 for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
890 return Curl_raw_nequal(ptr, media_type, media_type_len) &&
891 (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
892 *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
895 int check_metalink_content_type(const char *content_type)
897 return check_content_type(content_type, "application/metalink+xml");
900 int count_next_metalink_resource(metalinkfile *mlfile)
903 metalink_resource *res;
904 for(res = mlfile->resource; res; res = res->next, ++count);
908 static void delete_metalink_checksum(metalink_checksum *chksum)
913 Curl_safefree(chksum->digest);
914 Curl_safefree(chksum);
917 static void delete_metalink_resource(metalink_resource *res)
922 Curl_safefree(res->url);
926 static void delete_metalinkfile(metalinkfile *mlfile)
928 metalink_resource *res;
932 Curl_safefree(mlfile->filename);
933 delete_metalink_checksum(mlfile->checksum);
934 for(res = mlfile->resource; res;) {
935 metalink_resource *next;
937 delete_metalink_resource(res);
940 Curl_safefree(mlfile);
943 void clean_metalink(struct OperationConfig *config)
945 while(config->metalinkfile_list) {
946 metalinkfile *mlfile = config->metalinkfile_list;
947 config->metalinkfile_list = config->metalinkfile_list->next;
948 delete_metalinkfile(mlfile);
950 config->metalinkfile_last = 0;
953 void metalink_cleanup(void)
957 NSS_ShutdownContext(nss_context);
963 #endif /* USE_METALINK */