//! 中间归档只检查文件属性;读取计数与异常文件覆盖不启动 Go 工具。 use super::*; use std::os::unix::fs::symlink; fn stage() -> Stage { let root = std::env::temp_dir().join(format!( "dever-go-output-{}-{}", std::process::id(), std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_nanos() )); fs::DirBuilder::new().mode(0o700).create(&root).unwrap(); Stage { root, resources: BTreeMap::new(), written: 0, started: Instant::now(), } } #[test] fn go_intermediate_output_checks_metadata_without_reading_archive() { let stage = stage(); let path = stage.root.join("package.a"); let length = 8 * 1024 * 1024; fs::File::create(&path).unwrap().set_len(length).unwrap(); let read_chars = || { fs::read_to_string("/proc/thread-self/io") .unwrap() .lines() .find_map(|line| line.strip_prefix("rchar: ")) .unwrap() .parse::() .unwrap() }; let before = read_chars(); drop(stage.output(&path).unwrap()); let consumed = read_chars() - before; eprintln!("go intermediate: fixture=sparse-zero bytes={length} rchar={consumed}"); assert!( consumed < 4096, "read {consumed} bytes for a metadata check" ); assert_eq!(fs::metadata(path).unwrap().len(), length); } #[test] fn go_output_rejects_links_empty_special_and_oversized_files() { let stage = stage(); let path = stage.root.join("output"); fs::write(&path, b"archive").unwrap(); drop(stage.output(&path).unwrap()); let link = stage.root.join("symbolic"); symlink(&path, &link).unwrap(); assert!(stage.output(&link).is_err()); fs::remove_file(link).unwrap(); let link = stage.root.join("hard"); fs::hard_link(&path, &link).unwrap(); assert!(stage.output(&path).is_err()); fs::remove_file(link).unwrap(); assert!(stage.output(&stage.root).is_err()); fs::File::create(&path).unwrap(); assert!(stage.output(&path).is_err()); fs::File::create(&path) .unwrap() .set_len(128 * 1024 * 1024 + 1) .unwrap(); assert!(stage.output(&path).is_err()); fs::remove_file(&path).unwrap(); assert!(stage.output(&path).is_err()); }