8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use std:: fs:: File ;
12
- use std:: io:: { self , Write , BufWriter } ;
11
+ use std:: fs:: { read_link , symlink_metadata } ;
12
+ use std:: io:: { self , empty , Write , BufWriter } ;
13
13
use std:: path:: Path ;
14
14
15
15
use flate2;
@@ -77,8 +77,7 @@ impl Tarballer {
77
77
}
78
78
for path in files {
79
79
let src = Path :: new ( & self . work_dir ) . join ( & path) ;
80
- let file = open_file ( & src) ?;
81
- builder. append_data ( & mut header ( & src, & file) ?, & path, & file)
80
+ append_path ( & mut builder, & src, & path)
82
81
. chain_err ( || format ! ( "failed to tar file '{}'" , src. display( ) ) ) ?;
83
82
}
84
83
let RayonTee ( xz, gz) = builder. into_inner ( )
@@ -95,21 +94,30 @@ impl Tarballer {
95
94
}
96
95
}
97
96
98
- fn header ( src : & Path , file : & File ) -> Result < Header > {
97
+ fn append_path < W : Write > ( builder : & mut Builder < W > , src : & Path , path : & String ) -> Result < ( ) > {
98
+ let stat = symlink_metadata ( src) ?;
99
99
let mut header = Header :: new_gnu ( ) ;
100
- header. set_metadata ( & file. metadata ( ) ?) ;
101
- if cfg ! ( windows) {
102
- // Windows doesn't really have a mode, so `tar` never marks files executable.
103
- // Use an extension whitelist to update files that usually should be so.
104
- const EXECUTABLES : [ & ' static str ; 4 ] = [ "exe" , "dll" , "py" , "sh" ] ;
105
- if let Some ( ext) = src. extension ( ) . and_then ( |s| s. to_str ( ) ) {
106
- if EXECUTABLES . contains ( & ext) {
107
- let mode = header. mode ( ) ?;
108
- header. set_mode ( mode | 0o111 ) ;
100
+ header. set_metadata ( & stat) ;
101
+ if stat. file_type ( ) . is_symlink ( ) {
102
+ let link = read_link ( src) ?;
103
+ header. set_link_name ( & link) ?;
104
+ builder. append_data ( & mut header, path, & mut empty ( ) ) ?;
105
+ } else {
106
+ if cfg ! ( windows) {
107
+ // Windows doesn't really have a mode, so `tar` never marks files executable.
108
+ // Use an extension whitelist to update files that usually should be so.
109
+ const EXECUTABLES : [ & ' static str ; 4 ] = [ "exe" , "dll" , "py" , "sh" ] ;
110
+ if let Some ( ext) = src. extension ( ) . and_then ( |s| s. to_str ( ) ) {
111
+ if EXECUTABLES . contains ( & ext) {
112
+ let mode = header. mode ( ) ?;
113
+ header. set_mode ( mode | 0o111 ) ;
114
+ }
109
115
}
110
116
}
117
+ let file = open_file ( src) ?;
118
+ builder. append_data ( & mut header, path, & file) ?;
111
119
}
112
- Ok ( header )
120
+ Ok ( ( ) )
113
121
}
114
122
115
123
/// Returns all `(directories, files)` under the source path
0 commit comments