1use std::os::unix::prelude::PermissionsExt;
2use tracing::instrument;
3
4#[derive(Copy, Clone, Debug, Default)]
5pub struct MetadataCmpSettings {
6 pub uid: bool,
7 pub gid: bool,
8 pub mode: bool,
9 pub size: bool,
10 pub mtime: bool,
11 pub ctime: bool,
12}
13
14#[instrument]
15pub fn metadata_equal<
16 M1: crate::preserve::Metadata + std::fmt::Debug,
17 M2: crate::preserve::Metadata + std::fmt::Debug,
18>(
19 settings: &MetadataCmpSettings,
20 metadata1: &M1,
21 metadata2: &M2,
22) -> bool {
23 if settings.uid && metadata1.uid() != metadata2.uid() {
24 return false;
25 }
26 if settings.gid && metadata1.gid() != metadata2.gid() {
27 return false;
28 }
29 if settings.mode && metadata1.permissions().mode() != metadata2.permissions().mode() {
30 return false;
31 }
32 if settings.size && metadata1.size() != metadata2.size() {
33 return false;
34 }
35 if settings.mtime {
36 if metadata1.mtime() != metadata2.mtime() {
37 return false;
38 }
39 if metadata1.mtime_nsec() != 0
41 && metadata2.mtime_nsec() != 0
42 && metadata1.mtime_nsec() != metadata2.mtime_nsec()
43 {
44 return false;
45 }
46 }
47 if settings.ctime {
48 if metadata1.ctime() != 0 && metadata2.ctime() != 0 {
51 if metadata1.ctime() != metadata2.ctime() {
52 return false;
53 }
54 if metadata1.ctime_nsec() != 0
55 && metadata2.ctime_nsec() != 0
56 && metadata1.ctime_nsec() != metadata2.ctime_nsec()
57 {
58 return false;
59 }
60 }
61 }
62 true
63}
64
65#[instrument]
71pub fn dest_is_newer<
72 M1: crate::preserve::Metadata + std::fmt::Debug,
73 M2: crate::preserve::Metadata + std::fmt::Debug,
74>(
75 src: &M1,
76 dest: &M2,
77) -> bool {
78 (dest.mtime(), dest.mtime_nsec()) > (src.mtime(), src.mtime_nsec())
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 #[derive(Debug)]
85 struct FakeMeta {
86 mtime: i64,
87 mtime_nsec: i64,
88 }
89 impl crate::preserve::Metadata for FakeMeta {
90 fn uid(&self) -> u32 {
91 0
92 }
93 fn gid(&self) -> u32 {
94 0
95 }
96 fn atime(&self) -> i64 {
97 0
98 }
99 fn atime_nsec(&self) -> i64 {
100 0
101 }
102 fn mtime(&self) -> i64 {
103 self.mtime
104 }
105 fn mtime_nsec(&self) -> i64 {
106 self.mtime_nsec
107 }
108 fn permissions(&self) -> std::fs::Permissions {
109 std::os::unix::fs::PermissionsExt::from_mode(0o644)
110 }
111 }
112 #[test]
113 fn dest_newer_by_seconds() {
114 let src = FakeMeta {
115 mtime: 100,
116 mtime_nsec: 0,
117 };
118 let dest = FakeMeta {
119 mtime: 200,
120 mtime_nsec: 0,
121 };
122 assert!(dest_is_newer(&src, &dest));
123 }
124 #[test]
125 fn dest_older_by_seconds() {
126 let src = FakeMeta {
127 mtime: 200,
128 mtime_nsec: 0,
129 };
130 let dest = FakeMeta {
131 mtime: 100,
132 mtime_nsec: 0,
133 };
134 assert!(!dest_is_newer(&src, &dest));
135 }
136 #[test]
137 fn same_mtime_not_newer() {
138 let src = FakeMeta {
139 mtime: 100,
140 mtime_nsec: 500,
141 };
142 let dest = FakeMeta {
143 mtime: 100,
144 mtime_nsec: 500,
145 };
146 assert!(!dest_is_newer(&src, &dest));
147 }
148 #[test]
149 fn dest_newer_by_nsec() {
150 let src = FakeMeta {
151 mtime: 100,
152 mtime_nsec: 500,
153 };
154 let dest = FakeMeta {
155 mtime: 100,
156 mtime_nsec: 600,
157 };
158 assert!(dest_is_newer(&src, &dest));
159 }
160 #[test]
161 fn dest_older_by_nsec() {
162 let src = FakeMeta {
163 mtime: 100,
164 mtime_nsec: 600,
165 };
166 let dest = FakeMeta {
167 mtime: 100,
168 mtime_nsec: 500,
169 };
170 assert!(!dest_is_newer(&src, &dest));
171 }
172}