Skip to content

Commit a89f513

Browse files
committed
fix(vendor): early Windows 10 versions cannot move dirs
Not sure if it is really needed, though Cargo had better follow what platform support says. > The behavior on Windows is the same on Windows 10 1607 and higher > if `FileRenameInfoEx` is supported by the filesystem; otherwise, > `from` can be anything, but `to` must *not* be a directory. https://doc.rust-lang.org/1.86.0/src/std/fs.rs.html#2430-2435
1 parent d64e8c4 commit a89f513

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

src/cargo/ops/vendor.rs

+23-9
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,19 @@ fn sync(
255255
_ => unreachable!("not registry source: {sid}"),
256256
};
257257

258-
let mut compute_file_cksums = |root| {
259-
let walkdir = WalkDir::new(root)
258+
let walkdir = |root| {
259+
WalkDir::new(root)
260260
.into_iter()
261261
// It is safe to skip errors,
262262
// since we'll hit them during copying/reading later anyway.
263263
.filter_map(|e| e.ok())
264264
// There should be no symlink in tarballs on crates.io,
265265
// but might be wrong for local registries.
266266
// Hence here be conservative and include symlinks.
267-
.filter(|e| e.file_type().is_file() || e.file_type().is_symlink());
268-
for e in walkdir {
267+
.filter(|e| e.file_type().is_file() || e.file_type().is_symlink())
268+
};
269+
let mut compute_file_cksums = |root| {
270+
for e in walkdir(root) {
269271
let path = e.path();
270272
let relative = path.strip_prefix(&dst).unwrap();
271273
let cksum = Sha256::new()
@@ -289,11 +291,24 @@ fn sync(
289291
.tempdir_in(vendor_dir)?;
290292
let unpacked_src =
291293
registry.unpack_package_in(id, staging_dir.path(), &vendor_this)?;
292-
fs::rename(&unpacked_src, &dst)?;
293-
compute_file_cksums(&dst)?;
294+
if let Err(e) = fs::rename(&unpacked_src, &dst) {
295+
// This fallback is mainly for Windows 10 versions earlier than 1607.
296+
// The destination of `fs::rename` can't be a diretory in older versions.
297+
// Can be removed once the minimal supported Windows version gets bumped.
298+
tracing::warn!("failed to `mv {unpacked_src:?} {dst:?}`: {e}");
299+
let paths: Vec<_> = walkdir(&unpacked_src).map(|e| e.into_path()).collect();
300+
cp_sources(pkg, src, &paths, &dst, &mut file_cksums, &mut tmp_buf, gctx)
301+
.with_context(|| format!("failed to copy vendored sources for {id}"))?;
302+
} else {
303+
compute_file_cksums(&dst)?;
304+
}
294305
}
295306
} else {
296-
let paths = PathSource::new(src, sid, gctx).list_files(pkg)?;
307+
let paths = PathSource::new(src, sid, gctx)
308+
.list_files(pkg)?
309+
.into_iter()
310+
.map(|p| p.into_path_buf())
311+
.collect::<Vec<_>>();
297312
cp_sources(pkg, src, &paths, &dst, &mut file_cksums, &mut tmp_buf, gctx)
298313
.with_context(|| format!("failed to copy vendored sources for {id}"))?;
299314
}
@@ -387,14 +402,13 @@ fn sync(
387402
fn cp_sources(
388403
pkg: &Package,
389404
src: &Path,
390-
paths: &[PathEntry],
405+
paths: &[PathBuf],
391406
dst: &Path,
392407
cksums: &mut BTreeMap<String, String>,
393408
tmp_buf: &mut [u8],
394409
gctx: &GlobalContext,
395410
) -> CargoResult<()> {
396411
for p in paths {
397-
let p = p.as_ref();
398412
let relative = p.strip_prefix(&src).unwrap();
399413

400414
if !vendor_this(relative) {

0 commit comments

Comments
 (0)