@@ -6,65 +6,21 @@ use std::{ffi::OsStr, path::Path};
66use derive_setters:: Setters ;
77use ignore:: DirEntry ;
88use jiff:: Timestamp ;
9+ use log:: warn;
910use serde:: { Deserialize , Serialize } ;
1011use serde_with:: serde_as;
1112
1213use super :: { IgnoreErrorKind , IgnoreResult , OpenFile } ;
1314use crate :: backend:: {
1415 ReadSourceEntry ,
15- node:: { ExtendedAttribute , Metadata , Node , NodeType } ,
16+ node:: {
17+ ExtendedAttribute , Metadata , Node , NodeType ,
18+ modification:: { DevIdOption , TimeOption , XattrOption } ,
19+ } ,
1620} ;
1721
1822#[ cfg( not( windows) ) ]
19- use {
20- log:: warn,
21- std:: os:: unix:: fs:: { FileTypeExt , MetadataExt } ,
22- } ;
23-
24- #[ cfg_attr( feature = "clap" , derive( clap:: ValueEnum ) ) ]
25- #[ derive( Debug , Clone , Copy , Serialize , Deserialize ) ]
26- #[ serde( rename_all = "kebab-case" ) ]
27- pub enum TimeOption {
28- Yes ,
29- Mtime ,
30- No ,
31- }
32-
33- impl TimeOption {
34- fn map ( self , default : Option < Timestamp > , mtime : Option < Timestamp > ) -> Option < Timestamp > {
35- match self {
36- Self :: Yes => default,
37- Self :: Mtime => mtime,
38- Self :: No => None ,
39- }
40- }
41- }
42-
43- #[ cfg_attr( feature = "clap" , derive( clap:: ValueEnum ) ) ]
44- #[ derive( Debug , Clone , Copy , Default , Serialize , Deserialize ) ]
45- #[ serde( rename_all = "kebab-case" ) ]
46- pub enum DevIdOption {
47- Yes ,
48- #[ default]
49- Hardlink ,
50- No ,
51- }
52-
53- impl DevIdOption {
54- #[ cfg( windows) ]
55- fn map ( self , _m : & std:: fs:: Metadata ) -> u64 {
56- 0
57- }
58-
59- #[ cfg( not( windows) ) ]
60- fn map ( self , m : & std:: fs:: Metadata ) -> u64 {
61- match self {
62- Self :: Yes => m. dev ( ) ,
63- Self :: Hardlink if m. nlink ( ) > 1 && !m. is_dir ( ) => m. dev ( ) ,
64- _ => 0 ,
65- }
66- }
67- }
23+ use std:: os:: unix:: fs:: { FileTypeExt , MetadataExt } ;
6824
6925#[ cfg_attr( feature = "clap" , derive( clap:: ValueEnum ) ) ]
7026#[ derive( Debug , Clone , Copy , Default , Serialize , Deserialize ) ]
@@ -75,63 +31,6 @@ pub enum BlockdevOption {
7531 File ,
7632}
7733
78- #[ cfg_attr( feature = "clap" , derive( clap:: ValueEnum ) ) ]
79- #[ derive( Debug , Clone , Copy , Default , Serialize , Deserialize ) ]
80- #[ serde( rename_all = "kebab-case" ) ]
81- pub enum XattrOption {
82- #[ default]
83- Yes ,
84- No ,
85- }
86-
87- impl XattrOption {
88- #[ cfg( any( windows, target_os = "openbsd" ) ) ]
89- fn map ( & self , _path : & Path ) -> Vec < ExtendedAttribute > {
90- Vec :: new ( )
91- }
92-
93- /// List [`ExtendedAttribute`] for a [`Node`] located at `path`
94- ///
95- /// # Argument
96- ///
97- /// * `path` to the [`Node`] for which to list attributes
98- ///
99- /// # Errors
100- ///
101- /// * If Xattr couldn't be listed or couldn't be read
102- #[ cfg( not( any( windows, target_os = "openbsd" ) ) ) ]
103- fn map ( self , path : & Path ) -> Vec < ExtendedAttribute > {
104- let list = |path : & Path | {
105- xattr:: list ( path)
106- . map_err ( |err| IgnoreErrorKind :: ErrorXattr {
107- path : path. to_path_buf ( ) ,
108- source : err,
109- } ) ?
110- . map ( |name| {
111- Ok ( ExtendedAttribute {
112- name : name. to_string_lossy ( ) . to_string ( ) ,
113- value : xattr:: get ( path, name) . map_err ( |err| {
114- IgnoreErrorKind :: ErrorXattr {
115- path : path. to_path_buf ( ) ,
116- source : err,
117- }
118- } ) ?,
119- } )
120- } )
121- . collect :: < IgnoreResult < Vec < ExtendedAttribute > > > ( )
122- } ;
123-
124- match self {
125- Self :: Yes => list ( path)
126- . inspect_err ( |err| {
127- warn ! ( "ignoring error: {err}" ) ;
128- } )
129- . unwrap_or_default ( ) ,
130- Self :: No => Vec :: new ( ) ,
131- }
132- }
133- }
134-
13534#[ serde_as]
13635#[ cfg_attr( feature = "clap" , derive( clap:: Parser ) ) ]
13736#[ cfg_attr( feature = "merge" , derive( conflate:: Merge ) ) ]
@@ -141,7 +40,7 @@ impl XattrOption {
14140#[ non_exhaustive]
14241/// [`LocalSourceSaveOptions`] describes how entries from a local source will be saved in the repository.
14342pub struct LocalSourceSaveOptions {
144- /// Set access time [default: yes ]
43+ /// Set access time [default: mtime ]
14544 #[ cfg_attr( feature = "clap" , clap( long) ) ]
14645 #[ cfg_attr( feature = "merge" , merge( strategy = conflate:: option:: overwrite_none) ) ]
14746 pub set_atime : Option < TimeOption > ,
@@ -189,18 +88,29 @@ impl LocalSourceSaveOptions {
18988 } ) ?;
19089
19190 let mtime = m. modified ( ) . ok ( ) . and_then ( |t| Timestamp :: try_from ( t) . ok ( ) ) ;
192- let atime = m. accessed ( ) . ok ( ) . and_then ( |t| Timestamp :: try_from ( t) . ok ( ) ) ;
91+ let atime = || m. accessed ( ) . ok ( ) . and_then ( |t| Timestamp :: try_from ( t) . ok ( ) ) ;
19392 let atime = self
19493 . set_atime
19594 . unwrap_or ( TimeOption :: Mtime )
196- . map ( atime, mtime) ;
197- let ctime = Self :: default_ctime ( & m) ;
198- let ctime = self . set_ctime . unwrap_or ( TimeOption :: Yes ) . map ( ctime, mtime) ;
95+ . map_or_else ( atime, mtime) ;
96+ let ctime = || Self :: ctime ( & m) ;
97+ let ctime = self
98+ . set_ctime
99+ . unwrap_or ( TimeOption :: Yes )
100+ . map_or_else ( ctime, mtime) ;
199101
200102 let ( uid, user, gid, group) = Self :: user_group ( & m) ;
201103 let size = if m. is_dir ( ) { 0 } else { m. len ( ) } ;
202- let device_id = self . set_devid . unwrap_or_default ( ) . map ( & m) ;
203- let extended_attributes = self . set_xattrs . unwrap_or_default ( ) . map ( entry. path ( ) ) ;
104+ let device_id = self
105+ . set_devid
106+ . unwrap_or_default ( )
107+ . map_or_else ( || Self :: device_id ( & m) , Self :: hardlink ( & m) ) ;
108+ let xattr = || {
109+ Self :: xattrs ( entry. path ( ) )
110+ . inspect_err ( |err| warn ! ( "ignoring error obtaining xargs: {err}" ) )
111+ . unwrap_or_default ( )
112+ } ;
113+ let extended_attributes = self . set_xattrs . unwrap_or_default ( ) . map_or_else ( xattr) ;
204114 let ( mode, inode, links) = Self :: nix_infos ( & m) ;
205115
206116 let meta = Metadata {
@@ -251,11 +161,19 @@ impl LocalSourceSaveOptions {
251161
252162#[ cfg( not( windows) ) ]
253163impl LocalSourceSaveOptions {
254- fn default_ctime ( m : & std:: fs:: Metadata ) -> Option < Timestamp > {
164+ fn ctime ( m : & std:: fs:: Metadata ) -> Option < Timestamp > {
255165 #[ allow( clippy:: cast_possible_truncation) ]
256166 Timestamp :: new ( m. ctime ( ) , m. ctime_nsec ( ) as i32 ) . ok ( )
257167 }
258168
169+ fn device_id ( m : & std:: fs:: Metadata ) -> u64 {
170+ m. dev ( )
171+ }
172+
173+ fn hardlink ( m : & std:: fs:: Metadata ) -> bool {
174+ m. nlink ( ) > 1 && !m. is_dir ( )
175+ }
176+
259177 fn user_group (
260178 m : & std:: fs:: Metadata ,
261179 ) -> ( Option < u32 > , Option < String > , Option < u32 > , Option < String > ) {
@@ -273,6 +191,39 @@ impl LocalSourceSaveOptions {
273191 ( Some ( mode) , inode, links)
274192 }
275193
194+ /// List [`ExtendedAttribute`] for a [`Node`] located at `path`
195+ ///
196+ /// # Argument
197+ ///
198+ /// * `path` to the [`Node`] for which to list attributes
199+ ///
200+ /// # Errors
201+ ///
202+ /// * If Xattr couldn't be listed or couldn't be read
203+ #[ cfg( not( target_os = "openbsd" ) ) ]
204+ fn xattrs ( path : & Path ) -> IgnoreResult < Vec < ExtendedAttribute > > {
205+ xattr:: list ( path)
206+ . map_err ( |err| IgnoreErrorKind :: ErrorXattr {
207+ path : path. to_path_buf ( ) ,
208+ source : err,
209+ } ) ?
210+ . map ( |name| {
211+ Ok ( ExtendedAttribute {
212+ name : name. to_string_lossy ( ) . to_string ( ) ,
213+ value : xattr:: get ( path, name) . map_err ( |err| IgnoreErrorKind :: ErrorXattr {
214+ path : path. to_path_buf ( ) ,
215+ source : err,
216+ } ) ?,
217+ } )
218+ } )
219+ . collect :: < IgnoreResult < Vec < ExtendedAttribute > > > ( )
220+ }
221+
222+ #[ cfg( target_os = "openbsd" ) ]
223+ fn xattrs ( _path : & Path ) -> IgnoreResult < Vec < ExtendedAttribute > > {
224+ Ok ( Vec :: new ( ) )
225+ }
226+
276227 fn to_node_other ( self , name : & OsStr , m : & std:: fs:: Metadata , meta : Metadata ) -> Node {
277228 let filetype = m. file_type ( ) ;
278229 if filetype. is_block_device ( ) {
@@ -297,9 +248,15 @@ impl LocalSourceSaveOptions {
297248
298249#[ cfg( windows) ]
299250impl LocalSourceSaveOptions {
300- fn default_ctime ( m : & std:: fs:: Metadata ) -> Option < Timestamp > {
251+ fn ctime ( m : & std:: fs:: Metadata ) -> Option < Timestamp > {
301252 m. created ( ) . ok ( ) . and_then ( |t| Timestamp :: try_from ( t) . ok ( ) )
302253 }
254+ fn device_id ( _m : & std:: fs:: Metadata ) -> u64 {
255+ 0
256+ }
257+ fn hardlink ( m : & std:: fs:: Metadata ) -> bool {
258+ false
259+ }
303260 fn user_group (
304261 _m : & std:: fs:: Metadata ,
305262 ) -> ( Option < u32 > , Option < String > , Option < u32 > , Option < String > ) {
@@ -310,6 +267,10 @@ impl LocalSourceSaveOptions {
310267 ( None , 0 , 0 )
311268 }
312269
270+ fn xattrs ( _path : & Path ) -> IgnoreResult < Vec < ExtendedAttribute > > {
271+ Ok ( Vec :: new ( ) )
272+ }
273+
313274 fn to_node_other ( self , name : & OsStr , _m : & std:: fs:: Metadata , meta : Metadata ) -> Node {
314275 Node :: new_node ( name, NodeType :: File , meta)
315276 }
0 commit comments