1use crate::fs::hard_link_impl;
5#[cfg(racy_asserts)]
6use crate::fs::{
7 canonicalize, hard_link_unchecked, map_result, stat_unchecked, FollowSymlinks, Metadata,
8};
9use std::path::Path;
10use std::{fs, io};
11
12#[cfg_attr(not(racy_asserts), allow(clippy::let_and_return))]
15#[inline]
16pub fn hard_link(
17 old_start: &fs::File,
18 old_path: &Path,
19 new_start: &fs::File,
20 new_path: &Path,
21) -> io::Result<()> {
22 #[cfg(racy_asserts)]
23 let (old_metadata_before, new_metadata_before) = (
24 stat_unchecked(old_start, old_path, FollowSymlinks::No),
25 stat_unchecked(new_start, new_path, FollowSymlinks::No),
26 );
27
28 let result = hard_link_impl(old_start, old_path, new_start, new_path);
30
31 #[cfg(racy_asserts)]
32 let (old_metadata_after, new_metadata_after) = (
33 stat_unchecked(old_start, old_path, FollowSymlinks::No),
34 stat_unchecked(new_start, new_path, FollowSymlinks::No),
35 );
36
37 #[cfg(racy_asserts)]
38 check_hard_link(
39 old_start,
40 old_path,
41 new_start,
42 new_path,
43 &old_metadata_before,
44 &new_metadata_before,
45 &result,
46 &old_metadata_after,
47 &new_metadata_after,
48 );
49
50 result
51}
52
53#[cfg(racy_asserts)]
54#[allow(clippy::too_many_arguments)]
55#[allow(clippy::enum_glob_use)]
56fn check_hard_link(
57 old_start: &fs::File,
58 old_path: &Path,
59 new_start: &fs::File,
60 new_path: &Path,
61 old_metadata_before: &io::Result<Metadata>,
62 new_metadata_before: &io::Result<Metadata>,
63 result: &io::Result<()>,
64 old_metadata_after: &io::Result<Metadata>,
65 new_metadata_after: &io::Result<Metadata>,
66) {
67 use io::ErrorKind::*;
68
69 match (
70 map_result(old_metadata_before),
71 map_result(new_metadata_before),
72 map_result(result),
73 map_result(old_metadata_after),
74 map_result(new_metadata_after),
75 ) {
76 (
77 Ok(old_metadata_before),
78 Err((NotFound, _)),
79 Ok(()),
80 Ok(old_metadata_after),
81 Ok(new_metadata_after),
82 ) => {
83 assert_same_file_metadata!(old_metadata_before, old_metadata_after);
84 assert_same_file_metadata!(old_metadata_before, new_metadata_after);
85 }
86
87 (_, Ok(new_metadata_before), Err((AlreadyExists, _)), _, Ok(new_metadata_after)) => {
88 assert_same_file_metadata!(&new_metadata_before, &new_metadata_after);
89 }
90
91 (_, _, Err((_kind, _message)), _, _) => match (
92 map_result(&canonicalize(old_start, old_path)),
93 map_result(&canonicalize(new_start, new_path)),
94 ) {
95 (Ok(old_canon), Ok(new_canon)) => match map_result(&hard_link_unchecked(
96 old_start, &old_canon, new_start, &new_canon,
97 )) {
98 Err((_unchecked_kind, _unchecked_message)) => {
99 }
104 _ => panic!("unsandboxed link success"),
105 },
106 (Err((_old_canon_kind, _old_canon_message)), _) => {
107 }
112 (_, Err((_new_canon_kind, _new_canon_message))) => {
113 }
118 },
119
120 other => panic!(
121 "inconsistent link checks: old_start='{:?}', old_path='{}', new_start='{:?}', \
122 new_path='{}':\n{:#?}",
123 old_start,
124 old_path.display(),
125 new_start,
126 new_path.display(),
127 other
128 ),
129 }
130}