@@ -7,21 +7,14 @@ use std::path::{Path, PathBuf};
7
7
#[ cfg( not( target_os = "windows" ) ) ]
8
8
use std:: os:: unix:: io:: AsRawFd ;
9
9
10
+ use lightning:: util:: ser:: Writeable ;
11
+
10
12
#[ cfg( target_os = "windows" ) ]
11
13
use {
12
14
std:: ffi:: OsStr ,
13
15
std:: os:: windows:: ffi:: OsStrExt
14
16
} ;
15
17
16
- pub ( crate ) trait DiskWriteable {
17
- fn write_to_file ( & self , writer : & mut fs:: File ) -> Result < ( ) , std:: io:: Error > ;
18
- }
19
-
20
- pub ( crate ) fn get_full_filepath ( mut filepath : PathBuf , filename : String ) -> String {
21
- filepath. push ( filename) ;
22
- filepath. to_str ( ) . unwrap ( ) . to_string ( )
23
- }
24
-
25
18
#[ cfg( target_os = "windows" ) ]
26
19
macro_rules! call {
27
20
( $e: expr) => (
@@ -39,21 +32,25 @@ fn path_to_windows_str<T: AsRef<OsStr>>(path: T) -> Vec<winapi::shared::ntdef::W
39
32
}
40
33
41
34
#[ allow( bare_trait_objects) ]
42
- pub ( crate ) fn write_to_file < D : DiskWriteable > ( path : PathBuf , filename : String , data : & D ) -> std:: io:: Result < ( ) > {
43
- fs:: create_dir_all ( path. clone ( ) ) ?;
35
+ pub ( crate ) fn write_to_file < W : Writeable > ( filename_with_path : String , data : & W ) -> std:: io:: Result < ( ) > {
36
+ let mut tmp_filename = filename_with_path. clone ( ) ;
37
+ tmp_filename. push_str ( ".tmp" ) ;
38
+
39
+ let full_path = PathBuf :: from ( & filename_with_path) ;
40
+ let path = full_path. parent ( ) . unwrap ( ) ;
41
+ fs:: create_dir_all ( path) ?;
44
42
// Do a crazy dance with lots of fsync()s to be overly cautious here...
45
43
// We never want to end up in a state where we've lost the old data, or end up using the
46
44
// old data on power loss after we've returned.
47
45
// The way to atomically write a file on Unix platforms is:
48
46
// open(tmpname), write(tmpfile), fsync(tmpfile), close(tmpfile), rename(), fsync(dir)
49
- let filename_with_path = get_full_filepath ( path, filename) ;
50
- let tmp_filename = format ! ( "{}.tmp" , filename_with_path. clone( ) ) ;
47
+
51
48
52
49
{
53
50
// Note that going by rust-lang/rust@d602a6b, on MacOS it is only safe to use
54
51
// rust stdlib 1.36 or higher.
55
52
let mut f = fs:: File :: create ( & tmp_filename) ?;
56
- data. write_to_file ( & mut f) ?;
53
+ data. write ( & mut f) ?;
57
54
f. sync_all ( ) ?;
58
55
}
59
56
// Fsync the parent directory on Unix.
@@ -87,15 +84,17 @@ pub(crate) fn write_to_file<D: DiskWriteable>(path: PathBuf, filename: String, d
87
84
88
85
#[ cfg( test) ]
89
86
mod tests {
90
- use super :: { DiskWriteable , get_full_filepath, write_to_file} ;
87
+ use lightning:: util:: ser:: { Writer , Writeable } ;
88
+
89
+ use super :: { write_to_file} ;
91
90
use std:: fs;
92
91
use std:: io;
93
92
use std:: io:: Write ;
94
- use std:: path:: PathBuf ;
93
+ use std:: path:: { PathBuf , MAIN_SEPARATOR } ;
95
94
96
95
struct TestWriteable { }
97
- impl DiskWriteable for TestWriteable {
98
- fn write_to_file ( & self , writer : & mut fs :: File ) -> Result < ( ) , io:: Error > {
96
+ impl Writeable for TestWriteable {
97
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , std :: io:: Error > {
99
98
writer. write_all ( & [ 42 ; 1 ] )
100
99
}
101
100
}
@@ -113,7 +112,8 @@ mod tests {
113
112
let mut perms = fs:: metadata ( path. to_string ( ) ) . unwrap ( ) . permissions ( ) ;
114
113
perms. set_readonly ( true ) ;
115
114
fs:: set_permissions ( path. to_string ( ) , perms) . unwrap ( ) ;
116
- match write_to_file ( PathBuf :: from ( path. to_string ( ) ) , filename, & test_writeable) {
115
+
116
+ match write_to_file ( format ! ( "{}{}{}" , path, MAIN_SEPARATOR , filename) , & test_writeable) {
117
117
Err ( e) => assert_eq ! ( e. kind( ) , io:: ErrorKind :: PermissionDenied ) ,
118
118
_ => panic ! ( "Unexpected error message" )
119
119
}
@@ -131,10 +131,11 @@ mod tests {
131
131
fn test_rename_failure ( ) {
132
132
let test_writeable = TestWriteable { } ;
133
133
let filename = "test_rename_failure_filename" ;
134
- let path = PathBuf :: from ( "test_rename_failure_dir" ) ;
134
+ let path = "test_rename_failure_dir" ;
135
+ let full_file_path = format ! ( "{}{}{}" , path, MAIN_SEPARATOR , filename) ;
135
136
// Create the channel data file and make it a directory.
136
- fs:: create_dir_all ( get_full_filepath ( path . clone ( ) , filename . to_string ( ) ) ) . unwrap ( ) ;
137
- match write_to_file ( path . clone ( ) , filename . to_string ( ) , & test_writeable) {
137
+ fs:: create_dir_all ( full_file_path . clone ( ) ) . unwrap ( ) ;
138
+ match write_to_file ( full_file_path , & test_writeable) {
138
139
Err ( e) => assert_eq ! ( e. raw_os_error( ) , Some ( libc:: EISDIR ) ) ,
139
140
_ => panic ! ( "Unexpected Ok(())" )
140
141
}
@@ -144,16 +145,17 @@ mod tests {
144
145
#[ test]
145
146
fn test_diskwriteable_failure ( ) {
146
147
struct FailingWriteable { }
147
- impl DiskWriteable for FailingWriteable {
148
- fn write_to_file ( & self , _writer : & mut fs :: File ) -> Result < ( ) , std:: io:: Error > {
148
+ impl Writeable for FailingWriteable {
149
+ fn write < W : Writer > ( & self , _writer : & mut W ) -> Result < ( ) , std:: io:: Error > {
149
150
Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "expected failure" ) )
150
151
}
151
152
}
152
153
153
154
let filename = "test_diskwriteable_failure" ;
154
- let path = PathBuf :: from ( "test_diskwriteable_failure_dir" ) ;
155
+ let path = "test_diskwriteable_failure_dir" ;
155
156
let test_writeable = FailingWriteable { } ;
156
- match write_to_file ( path. clone ( ) , filename. to_string ( ) , & test_writeable) {
157
+ let full_path = format ! ( "{}{}{}" , path, MAIN_SEPARATOR , filename) ;
158
+ match write_to_file ( full_path. clone ( ) , & test_writeable) {
157
159
Err ( e) => {
158
160
assert_eq ! ( e. kind( ) , std:: io:: ErrorKind :: Other ) ;
159
161
assert_eq ! ( e. get_ref( ) . unwrap( ) . to_string( ) , "expected failure" ) ;
@@ -170,12 +172,11 @@ mod tests {
170
172
fn test_tmp_file_creation_failure ( ) {
171
173
let test_writeable = TestWriteable { } ;
172
174
let filename = "test_tmp_file_creation_failure_filename" . to_string ( ) ;
173
- let path = PathBuf :: from ( "test_tmp_file_creation_failure_dir" ) ;
174
-
175
- // Create the tmp file and make it a directory.
176
- let tmp_path = get_full_filepath ( path. clone ( ) , format ! ( "{}.tmp" , filename. clone( ) ) ) ;
175
+ let path = "test_tmp_file_creation_failure_dir" ;
176
+ let tmp_path = format ! ( "{}{}{}.tmp" , path, MAIN_SEPARATOR , filename. clone( ) ) ;
177
+ let full_filepath = format ! ( "{}{}{}" , path, MAIN_SEPARATOR , filename) ;
177
178
fs:: create_dir_all ( tmp_path) . unwrap ( ) ;
178
- match write_to_file ( path , filename , & test_writeable) {
179
+ match write_to_file ( full_filepath , & test_writeable) {
179
180
Err ( e) => {
180
181
#[ cfg( not( target_os = "windows" ) ) ]
181
182
assert_eq ! ( e. raw_os_error( ) , Some ( libc:: EISDIR ) ) ;
0 commit comments