Skip to content

Commit 4be72b0

Browse files
committed
Auto merge of rust-lang#7001 - ebobrow:non-octal-file-permissions, r=Manishearth
Add non_octal_unix_permissions lint fixes rust-lang#6934 changelog: add new lint that checks for non-octal values used to set unix file permissions
2 parents 44bf60f + 7fcd155 commit 4be72b0

8 files changed

+210
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2382,6 +2382,7 @@ Released 2018-09-13
23822382
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
23832383
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
23842384
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
2385+
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
23852386
[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
23862387
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
23872388
[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
77

8-
[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
8+
[There are over 450 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
99

1010
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
1111
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.

clippy_lints/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ mod new_without_default;
297297
mod no_effect;
298298
mod non_copy_const;
299299
mod non_expressive_names;
300+
mod non_octal_unix_permissions;
300301
mod open_options;
301302
mod option_env_unwrap;
302303
mod option_if_let_else;
@@ -873,6 +874,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
873874
&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
874875
&non_expressive_names::MANY_SINGLE_CHAR_NAMES,
875876
&non_expressive_names::SIMILAR_NAMES,
877+
&non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
876878
&open_options::NONSENSICAL_OPEN_OPTIONS,
877879
&option_env_unwrap::OPTION_ENV_UNWRAP,
878880
&option_if_let_else::OPTION_IF_LET_ELSE,
@@ -1057,6 +1059,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10571059
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
10581060
store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
10591061
store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
1062+
store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
10601063

10611064
let msrv = conf.msrv.as_ref().and_then(|s| {
10621065
parse_msrv(s, None, None).or_else(|| {
@@ -1647,6 +1650,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16471650
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
16481651
LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
16491652
LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
1653+
LintId::of(&non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
16501654
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
16511655
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
16521656
LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@@ -1987,6 +1991,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
19871991
LintId::of(&misc::FLOAT_CMP),
19881992
LintId::of(&misc::MODULO_ONE),
19891993
LintId::of(&mut_key::MUTABLE_KEY_TYPE),
1994+
LintId::of(&non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
19901995
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
19911996
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
19921997
LintId::of(&ptr::MUT_FROM_REF),
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
3+
use clippy_utils::ty::match_type;
4+
use clippy_utils::{match_def_path, paths};
5+
use if_chain::if_chain;
6+
use rustc_errors::Applicability;
7+
use rustc_hir::{Expr, ExprKind};
8+
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
11+
declare_clippy_lint! {
12+
/// **What it does:** Checks for non-octal values used to set Unix file permissions.
13+
///
14+
/// **Why is this bad?** They will be converted into octal, creating potentially
15+
/// unintended file permissions.
16+
///
17+
/// **Known problems:** None.
18+
///
19+
/// **Example:**
20+
///
21+
/// ```rust,ignore
22+
/// use std::fs::OpenOptions;
23+
/// use std::os::unix::fs::OpenOptionsExt;
24+
///
25+
/// let mut options = OpenOptions::new();
26+
/// options.mode(644);
27+
/// ```
28+
/// Use instead:
29+
/// ```rust,ignore
30+
/// use std::fs::OpenOptions;
31+
/// use std::os::unix::fs::OpenOptionsExt;
32+
///
33+
/// let mut options = OpenOptions::new();
34+
/// options.mode(0o644);
35+
/// ```
36+
pub NON_OCTAL_UNIX_PERMISSIONS,
37+
correctness,
38+
"use of non-octal value to set unix file permissions, which will be translated into octal"
39+
}
40+
41+
declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
42+
43+
impl LateLintPass<'_> for NonOctalUnixPermissions {
44+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
45+
match &expr.kind {
46+
ExprKind::MethodCall(path, _, [func, param], _) => {
47+
let obj_ty = cx.typeck_results().expr_ty(&func).peel_refs();
48+
49+
if_chain! {
50+
if (path.ident.name == sym!(mode)
51+
&& (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
52+
|| match_type(cx, obj_ty, &paths::DIR_BUILDER)))
53+
|| (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
54+
if let ExprKind::Lit(_) = param.kind;
55+
56+
then {
57+
let snip = match snippet_opt(cx, param.span) {
58+
Some(s) => s,
59+
_ => return,
60+
};
61+
62+
if !snip.starts_with("0o") {
63+
show_error(cx, param);
64+
}
65+
}
66+
}
67+
},
68+
ExprKind::Call(ref func, [param]) => {
69+
if_chain! {
70+
if let ExprKind::Path(ref path) = func.kind;
71+
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
72+
if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
73+
if let ExprKind::Lit(_) = param.kind;
74+
75+
then {
76+
let snip = match snippet_opt(cx, param.span) {
77+
Some(s) => s,
78+
_ => return,
79+
};
80+
81+
if !snip.starts_with("0o") {
82+
show_error(cx, param);
83+
}
84+
}
85+
}
86+
},
87+
_ => {},
88+
};
89+
}
90+
}
91+
92+
fn show_error(cx: &LateContext<'_>, param: &Expr<'_>) {
93+
let mut applicability = Applicability::MachineApplicable;
94+
span_lint_and_sugg(
95+
cx,
96+
NON_OCTAL_UNIX_PERMISSIONS,
97+
param.span,
98+
"using a non-octal value to set unix file permissions",
99+
"consider using an octal literal instead",
100+
format!(
101+
"0o{}",
102+
snippet_with_applicability(cx, param.span, "0o..", &mut applicability,),
103+
),
104+
applicability,
105+
);
106+
}

clippy_utils/src/paths.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
2626
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
2727
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
2828
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
29+
pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"];
2930
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
3031
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
3132
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
@@ -95,6 +96,8 @@ pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWri
9596
pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
9697
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
9798
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
99+
pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
100+
pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "sys", "unix", "ext", "fs", "PermissionsExt", "from_mode"];
98101
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
99102
pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
100103
pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// ignore-windows
2+
// run-rustfix
3+
#![warn(clippy::non_octal_unix_permissions)]
4+
use std::fs::{DirBuilder, File, OpenOptions, Permissions};
5+
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
6+
7+
fn main() {
8+
let permissions = 0o760;
9+
10+
// OpenOptionsExt::mode
11+
let mut options = OpenOptions::new();
12+
options.mode(0o440);
13+
options.mode(0o400);
14+
options.mode(permissions);
15+
16+
// PermissionsExt::from_mode
17+
let _permissions = Permissions::from_mode(0o647);
18+
let _permissions = Permissions::from_mode(0o000);
19+
let _permissions = Permissions::from_mode(permissions);
20+
21+
// PermissionsExt::set_mode
22+
let f = File::create("foo.txt").unwrap();
23+
let metadata = f.metadata().unwrap();
24+
let mut permissions = metadata.permissions();
25+
26+
permissions.set_mode(0o644);
27+
permissions.set_mode(0o704);
28+
29+
// DirBuilderExt::mode
30+
let mut builder = DirBuilder::new();
31+
builder.mode(0o755);
32+
builder.mode(0o406);
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// ignore-windows
2+
// run-rustfix
3+
#![warn(clippy::non_octal_unix_permissions)]
4+
use std::fs::{DirBuilder, File, OpenOptions, Permissions};
5+
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
6+
7+
fn main() {
8+
let permissions = 0o760;
9+
10+
// OpenOptionsExt::mode
11+
let mut options = OpenOptions::new();
12+
options.mode(440);
13+
options.mode(0o400);
14+
options.mode(permissions);
15+
16+
// PermissionsExt::from_mode
17+
let _permissions = Permissions::from_mode(647);
18+
let _permissions = Permissions::from_mode(0o000);
19+
let _permissions = Permissions::from_mode(permissions);
20+
21+
// PermissionsExt::set_mode
22+
let f = File::create("foo.txt").unwrap();
23+
let metadata = f.metadata().unwrap();
24+
let mut permissions = metadata.permissions();
25+
26+
permissions.set_mode(644);
27+
permissions.set_mode(0o704);
28+
29+
// DirBuilderExt::mode
30+
let mut builder = DirBuilder::new();
31+
builder.mode(755);
32+
builder.mode(0o406);
33+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: using a non-octal value to set unix file permissions
2+
--> $DIR/non_octal_unix_permissions.rs:12:18
3+
|
4+
LL | options.mode(440);
5+
| ^^^ help: consider using an octal literal instead: `0o440`
6+
|
7+
= note: `-D clippy::non-octal-unix-permissions` implied by `-D warnings`
8+
9+
error: using a non-octal value to set unix file permissions
10+
--> $DIR/non_octal_unix_permissions.rs:17:47
11+
|
12+
LL | let _permissions = Permissions::from_mode(647);
13+
| ^^^ help: consider using an octal literal instead: `0o647`
14+
15+
error: using a non-octal value to set unix file permissions
16+
--> $DIR/non_octal_unix_permissions.rs:26:26
17+
|
18+
LL | permissions.set_mode(644);
19+
| ^^^ help: consider using an octal literal instead: `0o644`
20+
21+
error: using a non-octal value to set unix file permissions
22+
--> $DIR/non_octal_unix_permissions.rs:31:18
23+
|
24+
LL | builder.mode(755);
25+
| ^^^ help: consider using an octal literal instead: `0o755`
26+
27+
error: aborting due to 4 previous errors
28+

0 commit comments

Comments
 (0)