@@ -6,78 +6,28 @@ extern crate napi_derive;
66use napi:: { bindgen_prelude:: AsyncTask , Env , Error , JsNumber , Result , Task } ;
77use std:: path:: PathBuf ;
88use reflink_copy;
9- use std:: fs;
10-
11- #[ cfg( not( target_os = "windows" ) ) ]
12- extern crate xattr;
139
1410pub struct AsyncReflink {
1511 src : PathBuf ,
1612 dst : PathBuf ,
1713}
1814
19- #[ cfg( not( target_os = "windows" ) ) ]
20- fn set_destination_metadata ( src : & PathBuf , dst : & PathBuf ) -> std:: io:: Result < ( ) > {
21- let metadata_key = "user.reflink_destinations" ;
22-
23- let mut destinations = match xattr:: get ( src, metadata_key) {
24- Ok ( Some ( data) ) => String :: from_utf8_lossy ( & data) . to_string ( ) ,
25- _ => String :: from ( "" ) ,
26- } ;
27-
28- if !destinations. is_empty ( ) {
29- destinations. push_str ( "," ) ;
30- }
31- destinations. push_str ( dst. to_str ( ) . unwrap ( ) ) ;
32-
33- xattr:: set ( src, metadata_key, destinations. as_bytes ( ) )
34- }
35-
3615#[ napi]
3716impl Task for AsyncReflink {
3817 type Output = ( ) ;
3918 type JsValue = JsNumber ;
4019
4120 fn compute ( & mut self ) -> Result < Self :: Output > {
42- let mut retry_count = 0 ;
43- loop {
44- match reflink_copy:: reflink ( & self . src , & self . dst ) {
45- Ok ( _) => {
46- #[ cfg( not( target_os = "windows" ) ) ]
47- {
48- if let Err ( err) = set_destination_metadata ( & self . src , & self . dst ) {
49- return Err ( Error :: from_reason ( err. to_string ( ) ) ) ;
50- }
51- }
52-
53- // Further validation: compare the contents of both files to make sure they are identical
54- let src_contents = fs:: read ( & self . src ) . map_err ( |e| Error :: from_reason ( e. to_string ( ) ) ) ?;
55- let dst_contents = fs:: read ( & self . dst ) . map_err ( |e| Error :: from_reason ( e. to_string ( ) ) ) ?;
56-
57- if src_contents != dst_contents {
58- // Delete the destination and retry if the files are not identical
59- fs:: remove_file ( & self . dst ) . map_err ( |e| Error :: from_reason ( e. to_string ( ) ) ) ?;
60- retry_count += 1 ;
61-
62- if retry_count >= 3 { // Limit the number of retries
63- return Err ( Error :: from_reason ( format ! (
64- "Max retries reached, could not create identical reflink for '{}' -> '{}'" ,
65- self . src. display( ) ,
66- self . dst. display( )
67- ) ) ) ;
68- }
69- continue ; // Retry the operation
70- }
71-
72- return Ok ( ( ) ) ;
73- } ,
74- Err ( err) => return Err ( Error :: from_reason ( format ! (
75- "{}, reflink '{}' -> '{}'" ,
76- err. to_string( ) ,
77- self . src. display( ) ,
78- self . dst. display( )
79- ) ) ) ,
80- }
21+ match reflink_copy:: reflink ( & self . src , & self . dst ) {
22+ Ok ( _) => {
23+ Ok ( ( ) )
24+ } ,
25+ Err ( err) => return Err ( Error :: from_reason ( format ! (
26+ "{}, reflink '{}' -> '{}'" ,
27+ err. to_string( ) ,
28+ self . src. display( ) ,
29+ self . dst. display( )
30+ ) ) ) ,
8131 }
8232 }
8333
@@ -86,7 +36,6 @@ impl Task for AsyncReflink {
8636 }
8737}
8838
89-
9039// Async version
9140#[ napi( js_name = "reflinkFile" ) ]
9241pub fn reflink_task ( src : String , dst : String ) -> AsyncTask < AsyncReflink > {
@@ -98,58 +47,16 @@ pub fn reflink_task(src: String, dst: String) -> AsyncTask<AsyncReflink> {
9847// Sync version
9948#[ napi( js_name = "reflinkFileSync" ) ]
10049pub fn reflink_sync ( env : Env , src : String , dst : String ) -> Result < JsNumber > {
101- let src_path = PathBuf :: from ( src. clone ( ) ) ;
102- let dst_path = PathBuf :: from ( dst. clone ( ) ) ;
103- let mut retry_count = 0 ;
104-
105- loop {
106- // Attempt to perform reflink
107- let reflink_result = reflink_copy:: reflink ( & src_path, & dst_path) ;
108-
109- match reflink_result {
110- Ok ( _) => {
111- // Further validation: compare the contents of both files to make sure they are identical
112- let src_contents = fs:: read ( & src_path) . map_err ( |e| Error :: from_reason ( e. to_string ( ) ) ) ?;
113- let dst_contents = fs:: read ( & dst_path) . map_err ( |e| Error :: from_reason ( e. to_string ( ) ) ) ?;
114-
115- if src_contents != dst_contents {
116- if retry_count >= 3 { // Max retry count
117- return Err ( Error :: from_reason ( format ! (
118- "Max retries reached, could not create identical reflink for '{}' -> '{}'" ,
119- src_path. display( ) ,
120- dst_path. display( )
121- ) ) ) ;
122- }
123- // Remove the destination and retry
124- if let Err ( err) = fs:: remove_file ( & dst_path) {
125- return Err ( Error :: from_reason ( format ! (
126- "Failed to remove destination file '{}': {}" ,
127- dst_path. display( ) ,
128- err. to_string( )
129- ) ) ) ;
130- }
131- retry_count += 1 ;
132- continue ; // Retry the operation
133- }
134-
135- // Metadata and return handling here (existing code)
136- #[ cfg( not( target_os = "windows" ) ) ]
137- {
138- if let Err ( err) = set_destination_metadata ( & src_path, & dst_path) {
139- return Err ( Error :: from_reason ( err. to_string ( ) ) ) ;
140- }
141- }
142- return Ok ( env. create_int32 ( 0 ) ?) ;
143- } ,
144- Err ( err) => {
145- return Err ( Error :: from_reason ( format ! (
146- "{}, reflink '{}' -> '{}'" ,
147- err. to_string( ) ,
148- src_path. display( ) ,
149- dst_path. display( )
150- ) ) ) ;
151- } ,
152- }
50+ let src_path = PathBuf :: from ( src) ;
51+ let dst_path = PathBuf :: from ( dst) ;
52+ match reflink_copy:: reflink ( & src_path, & dst_path) {
53+ Ok ( _) => Ok ( env. create_int32 ( 0 ) ?) ,
54+ Err ( err) => Err ( Error :: from_reason ( format ! (
55+ "{}, reflink '{}' -> '{}'" ,
56+ err. to_string( ) ,
57+ src_path. display( ) ,
58+ dst_path. display( )
59+ ) ) ) ,
15360 }
15461}
15562
@@ -160,7 +67,7 @@ pub fn test_pyc_file() {
16067
16168 // Remove the destination file if it already exists
16269 if dst. exists ( ) {
163- fs:: remove_file ( & dst) . unwrap ( ) ;
70+ std :: fs:: remove_file ( & dst) . unwrap ( ) ;
16471 }
16572
16673 // Run the reflink operation
@@ -170,13 +77,13 @@ pub fn test_pyc_file() {
17077 println ! ( "Reflinked '{}' -> '{}'" , src. display( ) , dst. display( ) ) ;
17178
17279 // Further validation: compare the contents of both files to make sure they are identical
173- let src_contents = fs:: read ( & src) . expect ( "Failed to read source file" ) ;
174- let dst_contents = fs:: read ( & dst) . expect ( "Failed to read destination file" ) ;
80+ let src_contents = std :: fs:: read ( & src) . expect ( "Failed to read source file" ) ;
81+ let dst_contents = std :: fs:: read ( & dst) . expect ( "Failed to read destination file" ) ;
17582
17683 assert_eq ! ( src_contents, dst_contents) ;
17784
17885 // Remove the destination file
179- fs:: remove_file ( & dst) . unwrap ( ) ;
86+ std :: fs:: remove_file ( & dst) . unwrap ( ) ;
18087
18188 println ! ( "File contents match, reflink operation successful" )
18289}
0 commit comments