cargo/sources/registry/
download.rs1use crate::util::interning::InternedString;
7use anyhow::Context as _;
8use cargo_credential::Operation;
9use cargo_util::Sha256;
10use cargo_util::registry::crate_url;
11
12use crate::core::PackageId;
13use crate::core::global_cache_tracker;
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::fs::{self, File, OpenOptions};
21use std::io::SeekFrom;
22use std::io::prelude::*;
23use std::str;
24
25pub(super) fn download(
30 cache_path: &Filesystem,
31 gctx: &GlobalContext,
32 encoded_registry_name: InternedString,
33 pkg: PackageId,
34 checksum: &str,
35 registry_config: RegistryConfig,
36) -> CargoResult<MaybeLock> {
37 let path = cache_path.join(&pkg.tarball_name());
38 let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
39
40 if let Ok(dst) = File::open(path) {
47 let meta = dst.metadata()?;
48 if meta.len() > 0 {
49 gctx.deferred_global_last_use()?.mark_registry_crate_used(
50 global_cache_tracker::RegistryCrate {
51 encoded_registry_name,
52 crate_filename: pkg.tarball_name().into(),
53 size: meta.len(),
54 },
55 );
56 return Ok(MaybeLock::Ready(dst));
57 }
58 }
59
60 let url = crate_url(
61 ®istry_config.dl,
62 &*pkg.name(),
63 &pkg.version().to_string(),
64 checksum,
65 );
66
67 let authorization = if registry_config.auth_required {
68 Some(auth::auth_token(
69 gctx,
70 &pkg.source_id(),
71 None,
72 Operation::Read,
73 vec![],
74 true,
75 )?)
76 } else {
77 None
78 };
79
80 Ok(MaybeLock::Download {
81 url,
82 descriptor: pkg.to_string(),
83 authorization: authorization,
84 })
85}
86
87pub(super) fn finish_download(
92 cache_path: &Filesystem,
93 gctx: &GlobalContext,
94 encoded_registry_name: InternedString,
95 pkg: PackageId,
96 checksum: &str,
97 data: &[u8],
98) -> CargoResult<File> {
99 let actual = Sha256::new().update(data).finish_hex();
101 if actual != checksum {
102 anyhow::bail!("failed to verify the checksum of `{}`", pkg)
103 }
104 gctx.deferred_global_last_use()?.mark_registry_crate_used(
105 global_cache_tracker::RegistryCrate {
106 encoded_registry_name,
107 crate_filename: pkg.tarball_name().into(),
108 size: data.len() as u64,
109 },
110 );
111
112 cache_path.create_dir()?;
113 let path = cache_path.join(&pkg.tarball_name());
114 let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
115 let mut dst = OpenOptions::new()
116 .create(true)
117 .read(true)
118 .write(true)
119 .open(&path)
120 .with_context(|| format!("failed to open `{}`", path.display()))?;
121 let meta = dst.metadata()?;
122 if meta.len() > 0 {
123 return Ok(dst);
124 }
125
126 dst.write_all(data)?;
127 dst.seek(SeekFrom::Start(0))?;
128 Ok(dst)
129}
130
131pub(super) fn is_crate_downloaded(
136 cache_path: &Filesystem,
137 gctx: &GlobalContext,
138 pkg: PackageId,
139) -> bool {
140 let path = cache_path.join(pkg.tarball_name());
141 let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
142 if let Ok(meta) = fs::metadata(path) {
143 return meta.len() > 0;
144 }
145 false
146}