Skip to content

Commit d1d694b

Browse files
committed
set_file_perms: if the file is already executable, keep it executable
1 parent c26a45b commit d1d694b

File tree

5 files changed

+75
-63
lines changed

5 files changed

+75
-63
lines changed

src/rustup-dist/src/component/package.rs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,16 @@ impl Package for DirectoryPackage {
123123
// but due to rust-lang/rust#25479 they don't.
124124
#[cfg(unix)]
125125
fn set_file_perms(dest_path: &Path, src_path: &Path) -> Result<()> {
126-
use std::fs;
126+
use std::fs::{self, Metadata};
127127
use std::os::unix::fs::PermissionsExt;
128128
use walkdir::WalkDir;
129129

130+
// Compute whether this entry needs the X bit
131+
fn needs_x(meta: &Metadata) -> bool {
132+
meta.is_dir() || // Directories need it
133+
meta.permissions().mode() & 0o700 == 0o700 // If it is rwx for the user, it gets the X bit
134+
}
135+
130136
// By convention, anything in the bin/ directory of the package is a binary
131137
let is_bin = if let Some(p) = src_path.parent() {
132138
p.ends_with("bin")
@@ -141,25 +147,14 @@ fn set_file_perms(dest_path: &Path, src_path: &Path) -> Result<()> {
141147
for entry in WalkDir::new(dest_path) {
142148
let entry = try!(entry.chain_err(|| ErrorKind::ComponentDirPermissionsFailed));
143149
let meta = try!(entry.metadata().chain_err(|| ErrorKind::ComponentDirPermissionsFailed));
144-
if meta.is_dir() {
145-
let mut perm = meta.permissions();
146-
perm.set_mode(0o755);
147-
try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
148-
} else {
149-
let mut perm = meta.permissions();
150-
perm.set_mode(0o644);
151-
try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
152-
}
150+
let mut perm = meta.permissions();
151+
perm.set_mode(if needs_x(&meta) { 0o755 } else { 0o644 });
152+
try!(fs::set_permissions(entry.path(), perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
153153
}
154-
} else if is_bin {
155-
let mut perm = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed))
156-
.permissions();
157-
perm.set_mode(0o755);
158-
try!(fs::set_permissions(dest_path, perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
159154
} else {
160-
let mut perm = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed))
161-
.permissions();
162-
perm.set_mode(0o644);
155+
let meta = try!(fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
156+
let mut perm = meta.permissions();
157+
perm.set_mode(if is_bin || needs_x(&meta) { 0o755 } else { 0o644 });
163158
try!(fs::set_permissions(dest_path, perm).chain_err(|| ErrorKind::ComponentFilePermissionsFailed));
164159
}
165160

src/rustup-dist/tests/dist.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ pub fn create_mock_channel(channel: &str, date: &str,
118118
MockCommand::File("bin/rustc".to_string()),
119119
],
120120
vec![
121-
("bin/rustc".to_string(), contents.clone())
121+
("bin/rustc".to_string(), contents.clone(), false)
122122
],
123123
),
124124
]
@@ -152,7 +152,7 @@ pub fn create_mock_channel(channel: &str, date: &str,
152152
MockCommand::File("lib/libstd.rlib".to_string()),
153153
],
154154
vec![
155-
("lib/libstd.rlib".to_string(), contents.clone())
155+
("lib/libstd.rlib".to_string(), contents.clone(), false)
156156
],
157157
),
158158
]
@@ -170,7 +170,7 @@ pub fn create_mock_channel(channel: &str, date: &str,
170170
MockCommand::File("lib/i686-apple-darwin/libstd.rlib".to_string()),
171171
],
172172
vec![
173-
("lib/i686-apple-darwin/libstd.rlib".to_string(), contents.clone())
173+
("lib/i686-apple-darwin/libstd.rlib".to_string(), contents.clone(), false)
174174
],
175175
),
176176
]
@@ -188,7 +188,7 @@ pub fn create_mock_channel(channel: &str, date: &str,
188188
MockCommand::File("lib/i686-unknown-linux-gnu/libstd.rlib".to_string()),
189189
],
190190
vec![
191-
("lib/i686-unknown-linux-gnu/libstd.rlib".to_string(), contents.clone())
191+
("lib/i686-unknown-linux-gnu/libstd.rlib".to_string(), contents.clone(), false)
192192
],
193193
),
194194
]
@@ -215,7 +215,7 @@ pub fn create_mock_channel(channel: &str, date: &str,
215215
MockCommand::File("bin/bonus".to_string()),
216216
],
217217
vec![
218-
("bin/bonus".to_string(), contents.clone())
218+
("bin/bonus".to_string(), contents.clone(), false)
219219
],
220220
),
221221
]

src/rustup-dist/tests/install.rs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ fn mock_smoke_test() {
2727
vec![MockCommand::File("bin/foo".to_string()),
2828
MockCommand::File("lib/bar".to_string()),
2929
MockCommand::Dir("doc/stuff".to_string())],
30-
vec![("bin/foo".to_string(), "foo".into()),
31-
("lib/bar".to_string(), "bar".into()),
32-
("doc/stuff/doc1".to_string(), "".into()),
33-
("doc/stuff/doc2".to_string(), "".into())]),
30+
vec![("bin/foo".to_string(), "foo".into(), false),
31+
("lib/bar".to_string(), "bar".into(), false),
32+
("doc/stuff/doc1".to_string(), "".into(), false),
33+
("doc/stuff/doc2".to_string(), "".into(), false)]),
3434
("mycomponent2".to_string(),
3535
vec![MockCommand::File("bin/quux".to_string())],
36-
vec![("bin/quux".to_string(), "quux".into())]
36+
vec![("bin/quux".to_string(), "quux".into(), false)]
3737
)]
3838
};
3939

@@ -56,11 +56,11 @@ fn package_contains() {
5656
let mock = MockInstallerBuilder {
5757
components: vec![("mycomponent".to_string(),
5858
vec![MockCommand::File("bin/foo".to_string())],
59-
vec![("bin/foo".to_string(), "foo".into())],
59+
vec![("bin/foo".to_string(), "foo".into(), false)],
6060
),
6161
("mycomponent2".to_string(),
6262
vec![MockCommand::File("bin/bar".to_string())],
63-
vec![("bin/bar".to_string(), "bar".into())]
63+
vec![("bin/bar".to_string(), "bar".into(), false)]
6464
)]
6565
};
6666

@@ -78,7 +78,7 @@ fn package_bad_version() {
7878
let mock = MockInstallerBuilder {
7979
components: vec![("mycomponent".to_string(),
8080
vec![MockCommand::File("bin/foo".to_string())],
81-
vec![("bin/foo".to_string(), "foo".into())])]
81+
vec![("bin/foo".to_string(), "foo".into(), false)])]
8282
};
8383

8484
mock.build(tempdir.path());
@@ -98,10 +98,10 @@ fn basic_install() {
9898
vec![MockCommand::File("bin/foo".to_string()),
9999
MockCommand::File("lib/bar".to_string()),
100100
MockCommand::Dir("doc/stuff".to_string())],
101-
vec![("bin/foo".to_string(), "foo".into()),
102-
("lib/bar".to_string(), "bar".into()),
103-
("doc/stuff/doc1".to_string(), "".into()),
104-
("doc/stuff/doc2".to_string(), "".into())])]
101+
vec![("bin/foo".to_string(), "foo".into(), false),
102+
("lib/bar".to_string(), "bar".into(), false),
103+
("doc/stuff/doc1".to_string(), "".into(), false),
104+
("doc/stuff/doc2".to_string(), "".into(), false)])]
105105
};
106106

107107
mock.build(pkgdir.path());
@@ -136,10 +136,10 @@ fn multiple_component_install() {
136136
let mock = MockInstallerBuilder {
137137
components: vec![("mycomponent".to_string(),
138138
vec![MockCommand::File("bin/foo".to_string())],
139-
vec![("bin/foo".to_string(), "foo".into())]),
139+
vec![("bin/foo".to_string(), "foo".into(), false)]),
140140
("mycomponent2".to_string(),
141141
vec![MockCommand::File("lib/bar".to_string())],
142-
vec![("lib/bar".to_string(), "bar".into())])]
142+
vec![("lib/bar".to_string(), "bar".into(), false)])]
143143
};
144144

145145
mock.build(pkgdir.path());
@@ -176,13 +176,13 @@ fn uninstall() {
176176
vec![MockCommand::File("bin/foo".to_string()),
177177
MockCommand::File("lib/bar".to_string()),
178178
MockCommand::Dir("doc/stuff".to_string())],
179-
vec![("bin/foo".to_string(), "foo".into()),
180-
("lib/bar".to_string(), "bar".into()),
181-
("doc/stuff/doc1".to_string(), "".into()),
182-
("doc/stuff/doc2".to_string(), "".into())]),
179+
vec![("bin/foo".to_string(), "foo".into(), false),
180+
("lib/bar".to_string(), "bar".into(), false),
181+
("doc/stuff/doc1".to_string(), "".into(), false),
182+
("doc/stuff/doc2".to_string(), "".into(), false)]),
183183
("mycomponent2".to_string(),
184184
vec![MockCommand::File("lib/quux".to_string())],
185-
vec![("lib/quux".to_string(), "quux".into())])]
185+
vec![("lib/quux".to_string(), "quux".into(), false)])]
186186
};
187187

188188
mock.build(pkgdir.path());
@@ -234,7 +234,7 @@ fn component_bad_version() {
234234
let mock = MockInstallerBuilder {
235235
components: vec![("mycomponent".to_string(),
236236
vec![MockCommand::File("bin/foo".to_string())],
237-
vec![("bin/foo".to_string(), "foo".into())])]
237+
vec![("bin/foo".to_string(), "foo".into(), false)])]
238238
};
239239

240240
mock.build(pkgdir.path());
@@ -276,11 +276,14 @@ fn unix_permissions() {
276276
components: vec![("mycomponent".to_string(),
277277
vec![MockCommand::File("bin/foo".to_string()),
278278
MockCommand::File("lib/bar".to_string()),
279+
MockCommand::File("lib/foobar".to_string()),
279280
MockCommand::Dir("doc/stuff".to_string())],
280-
vec![("bin/foo".to_string(), "foo".into()),
281-
("lib/bar".to_string(), "bar".into()),
282-
("doc/stuff/doc1".to_string(), "".into()),
283-
("doc/stuff/morestuff/doc2".to_string(), "".into())])]
281+
vec![("bin/foo".to_string(), "foo".into(), false),
282+
("lib/bar".to_string(), "bar".into(), false),
283+
("lib/foobar".to_string(), "foobar".into(), true),
284+
("doc/stuff/doc1".to_string(), "".into(), false),
285+
("doc/stuff/morestuff/doc2".to_string(), "".into(), false),
286+
("doc/stuff/morestuff/tool".to_string(), "".into(), true)])]
284287
};
285288

286289
mock.build(pkgdir.path());
@@ -304,6 +307,8 @@ fn unix_permissions() {
304307
assert_eq!(m, 0o755);
305308
let m = fs::metadata(instdir.path().join("lib/bar")).unwrap().permissions().mode();
306309
assert_eq!(m, 0o644);
310+
let m = fs::metadata(instdir.path().join("lib/foobar")).unwrap().permissions().mode();
311+
assert_eq!(m, 0o755);
307312
let m = fs::metadata(instdir.path().join("doc/stuff/")).unwrap().permissions().mode();
308313
assert_eq!(m, 0o755);
309314
let m = fs::metadata(instdir.path().join("doc/stuff/doc1")).unwrap().permissions().mode();
@@ -312,6 +317,8 @@ fn unix_permissions() {
312317
assert_eq!(m, 0o755);
313318
let m = fs::metadata(instdir.path().join("doc/stuff/morestuff/doc2")).unwrap().permissions().mode();
314319
assert_eq!(m, 0o644);
320+
let m = fs::metadata(instdir.path().join("doc/stuff/morestuff/tool")).unwrap().permissions().mode();
321+
assert_eq!(m, 0o755);
315322
}
316323

317324
// Installing to a prefix that doesn't exist creates it automatically
@@ -322,7 +329,7 @@ fn install_to_prefix_that_does_not_exist() {
322329
let mock = MockInstallerBuilder {
323330
components: vec![("mycomponent".to_string(),
324331
vec![MockCommand::File("bin/foo".to_string())],
325-
vec![("bin/foo".to_string(), "foo".into())])]
332+
vec![("bin/foo".to_string(), "foo".into(), false)])]
326333
};
327334

328335
mock.build(pkgdir.path());

src/rustup-mock/src/clitools.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ fn build_mock_std_installer(trip: &str) -> MockInstallerBuilder {
513513
components: vec![
514514
(format!("rust-std-{}", trip.clone()),
515515
vec![MockCommand::File(format!("lib/rustlib/{}/libstd.rlib", trip))],
516-
vec![(format!("lib/rustlib/{}/libstd.rlib", trip), "".into())])
516+
vec![(format!("lib/rustlib/{}/libstd.rlib", trip), "".into(), false)])
517517
]
518518
}
519519
}
@@ -524,8 +524,8 @@ fn build_mock_cross_std_installer(target: &str, date: &str) -> MockInstallerBuil
524524
(format!("rust-std-{}", target.clone()),
525525
vec![MockCommand::File(format!("lib/rustlib/{}/lib/libstd.rlib", target)),
526526
MockCommand::File(format!("lib/rustlib/{}/lib/{}", target, date))],
527-
vec![(format!("lib/rustlib/{}/lib/libstd.rlib", target), "".into()),
528-
(format!("lib/rustlib/{}/lib/{}", target, date), "".into())])
527+
vec![(format!("lib/rustlib/{}/lib/libstd.rlib", target), "".into(), false),
528+
(format!("lib/rustlib/{}/lib/{}", target, date), "".into(), false)])
529529
]
530530
}
531531
}
@@ -546,7 +546,7 @@ fn build_mock_rustc_installer(target: &str, version: &str, version_hash_: &str)
546546
components: vec![
547547
("rustc".to_string(),
548548
vec![MockCommand::File(rustc.clone())],
549-
vec![(rustc, mock_bin("rustc", version, &version_hash))])
549+
vec![(rustc, mock_bin("rustc", version, &version_hash), false)])
550550
]
551551
}
552552
}
@@ -557,7 +557,7 @@ fn build_mock_cargo_installer(version: &str, version_hash: &str) -> MockInstalle
557557
components: vec![
558558
("cargo".to_string(),
559559
vec![MockCommand::File(cargo.clone())],
560-
vec![(cargo, mock_bin("cargo", version, version_hash))])
560+
vec![(cargo, mock_bin("cargo", version, version_hash), false)])
561561
]
562562
}
563563
}
@@ -568,7 +568,7 @@ fn build_mock_rls_installer(version: &str, version_hash: &str) -> MockInstallerB
568568
components: vec![
569569
("rls".to_string(),
570570
vec![MockCommand::File(cargo.clone())],
571-
vec![(cargo, mock_bin("rls", version, version_hash))])
571+
vec![(cargo, mock_bin("rls", version, version_hash), false)])
572572
]
573573
}
574574
}
@@ -578,7 +578,7 @@ fn build_mock_rust_doc_installer() -> MockInstallerBuilder {
578578
components: vec![
579579
("rust-docs".to_string(),
580580
vec![MockCommand::File("share/doc/rust/html/index.html".to_string())],
581-
vec![("share/doc/rust/html/index.html".to_string(), "".into())])
581+
vec![("share/doc/rust/html/index.html".to_string(), "".into(), false)])
582582
]
583583
}
584584
}
@@ -588,7 +588,7 @@ fn build_mock_rust_analysis_installer(trip: &str) -> MockInstallerBuilder {
588588
components: vec![
589589
(format!("rust-analysis-{}", trip),
590590
vec![MockCommand::File(format!("lib/rustlib/{}/analysis/libfoo.json", trip))],
591-
vec![(format!("lib/rustlib/{}/analysis/libfoo.json", trip), "".into())])
591+
vec![(format!("lib/rustlib/{}/analysis/libfoo.json", trip), "".into(), false)])
592592
]
593593
}
594594
}
@@ -598,7 +598,7 @@ fn build_mock_rust_src_installer() -> MockInstallerBuilder {
598598
components: vec![
599599
("rust-src".to_string(),
600600
vec![MockCommand::File("lib/rustlib/src/rust-src/foo.rs".to_string())],
601-
vec![("lib/rustlib/src/rust-src/foo.rs".to_string(), "".into())])
601+
vec![("lib/rustlib/src/rust-src/foo.rs".to_string(), "".into(), false)])
602602
]
603603
}
604604
}

src/rustup-mock/src/lib.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ pub struct MockInstallerBuilder {
3333
}
3434

3535
// A component name, the installation commands for installing files
36-
// (either "file:" or "dir:") and the file paths and contents.
37-
pub type MockComponent = (String, Vec<MockCommand>, Vec<(String, Vec<u8>)>);
36+
// (either "file:" or "dir:") and the file paths, contents and X bit.
37+
pub type MockComponent = (String, Vec<MockCommand>, Vec<(String, Vec<u8>, bool)>);
3838

3939
#[derive(Clone)]
4040
pub enum MockCommand {
@@ -67,13 +67,23 @@ impl MockInstallerBuilder {
6767
}
6868

6969
// Create the component files
70-
for &(ref f_path, ref content) in files {
71-
let dir_path = component_dir.join(f_path);
72-
let dir_path = dir_path.parent().unwrap();
70+
for &(ref f_path, ref content, executable) in files {
71+
let fname = component_dir.join(f_path);
72+
let dir_path = fname.parent().unwrap().to_owned();
7373
fs::create_dir_all(dir_path).unwrap();
74-
let ref mut f = File::create(component_dir.join(f_path)).unwrap();
74+
let ref mut f = File::create(&fname).unwrap();
7575

7676
f.write_all(&content).unwrap();
77+
drop(f);
78+
#[cfg(unix)]
79+
{
80+
use std::os::unix::fs::PermissionsExt;
81+
if executable {
82+
let mut perm = fs::metadata(&fname).unwrap().permissions();
83+
perm.set_mode(0o755);
84+
fs::set_permissions(&fname, perm).unwrap();
85+
}
86+
}
7787
}
7888
}
7989

0 commit comments

Comments
 (0)