cargo/sources/registry/
download.rs
1use crate::util::interning::InternedString;
7use anyhow::Context as _;
8use cargo_credential::Operation;
9use cargo_util::registry::make_dep_path;
10use cargo_util::Sha256;
11
12use crate::core::global_cache_tracker;
13use crate::core::PackageId;
14use crate::sources::registry::MaybeLock;
15use crate::sources::registry::RegistryConfig;
16use crate::util::auth;
17use crate::util::cache_lock::CacheLockMode;
18use crate::util::errors::CargoResult;
19use crate::util::{Filesystem, GlobalContext};
20use std::fmt::Write as FmtWrite;
21use std::fs::{self, File, OpenOptions};
22use std::io::prelude::*;
23use std::io::SeekFrom;
24use std::str;
25
26const CRATE_TEMPLATE: &str = "{crate}";
27const VERSION_TEMPLATE: &str = "{version}";
28const PREFIX_TEMPLATE: &str = "{prefix}";
29const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}";
30const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}";
31
32pub(super) fn download(
37 cache_path: &Filesystem,
38 gctx: &GlobalContext,
39 encoded_registry_name: InternedString,
40 pkg: PackageId,
41 checksum: &str,
42 registry_config: RegistryConfig,
43) -> CargoResult<MaybeLock> {
44 let path = cache_path.join(&pkg.tarball_name());
45 let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
46
47 if let Ok(dst) = File::open(path) {
54 let meta = dst.metadata()?;
55 if meta.len() > 0 {
56 gctx.deferred_global_last_use()?.mark_registry_crate_used(
57 global_cache_tracker::RegistryCrate {
58 encoded_registry_name,
59 crate_filename: pkg.tarball_name().into(),
60 size: meta.len(),
61 },
62 );
63 return Ok(MaybeLock::Ready(dst));
64 }
65 }
66
67 let mut url = registry_config.dl;
68 if !url.contains(CRATE_TEMPLATE)
69 && !url.contains(VERSION_TEMPLATE)
70 && !url.contains(PREFIX_TEMPLATE)
71 && !url.contains(LOWER_PREFIX_TEMPLATE)
72 && !url.contains(CHECKSUM_TEMPLATE)
73 {
74 write!(
76 url,
77 "/{}/{}/download",
78 pkg.name(),
79 pkg.version().to_string()
80 )
81 .unwrap();
82 } else {
83 let prefix = make_dep_path(&pkg.name(), true);
84 url = url
85 .replace(CRATE_TEMPLATE, &*pkg.name())
86 .replace(VERSION_TEMPLATE, &pkg.version().to_string())
87 .replace(PREFIX_TEMPLATE, &prefix)
88 .replace(LOWER_PREFIX_TEMPLATE, &prefix.to_lowercase())
89 .replace(CHECKSUM_TEMPLATE, checksum);
90 }
91
92 let authorization = if registry_config.auth_required {
93 Some(auth::auth_token(
94 gctx,
95 &pkg.source_id(),
96 None,
97 Operation::Read,
98 vec![],
99 true,
100 )?)
101 } else {
102 None
103 };
104
105 Ok(MaybeLock::Download {
106 url,
107 descriptor: pkg.to_string(),
108 authorization: authorization,
109 })
110}
111
112pub(super) fn finish_download(
117 cache_path: &Filesystem,
118 gctx: &GlobalContext,
119 encoded_registry_name: InternedString,
120 pkg: PackageId,
121 checksum: &str,
122 data: &[u8],
123) -> CargoResult<File> {
124 let actual = Sha256::new().update(data).finish_hex();
126 if actual != checksum {
127 anyhow::bail!("failed to verify the checksum of `{}`", pkg)
128 }
129 gctx.deferred_global_last_use()?.mark_registry_crate_used(
130 global_cache_tracker::RegistryCrate {
131 encoded_registry_name,
132 crate_filename: pkg.tarball_name().into(),
133 size: data.len() as u64,
134 },
135 );
136
137 cache_path.create_dir()?;
138 let path = cache_path.join(&pkg.tarball_name());
139 let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
140 let mut dst = OpenOptions::new()
141 .create(true)
142 .read(true)
143 .write(true)
144 .open(&path)
145 .with_context(|| format!("failed to open `{}`", path.display()))?;
146 let meta = dst.metadata()?;
147 if meta.len() > 0 {
148 return Ok(dst);
149 }
150
151 dst.write_all(data)?;
152 dst.seek(SeekFrom::Start(0))?;
153 Ok(dst)
154}
155
156pub(super) fn is_crate_downloaded(
161 cache_path: &Filesystem,
162 gctx: &GlobalContext,
163 pkg: PackageId,
164) -> bool {
165 let path = cache_path.join(pkg.tarball_name());
166 let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
167 if let Ok(meta) = fs::metadata(path) {
168 return meta.len() > 0;
169 }
170 false
171}