nu_command/platform/
umask_.rs1use std::ops::Deref;
2
3use nix::libc::mode_t;
4use nu_engine::command_prelude::*;
5use nu_system::get_umask;
6
7struct Mode(umask::Mode);
16
17impl Deref for Mode {
18 type Target = umask::Mode;
19
20 fn deref(&self) -> &Self::Target {
21 &self.0
22 }
23}
24
25impl From<Mode> for mode_t {
26 #[allow(clippy::unnecessary_cast)]
27 fn from(mode: Mode) -> Self {
28 u32::from(mode.0) as mode_t
30 }
31}
32
33impl From<mode_t> for Mode {
34 #[allow(clippy::unnecessary_cast)]
35 fn from(value: mode_t) -> Self {
36 Self((value as u32).into())
38 }
39}
40
41#[derive(Clone)]
42pub struct UMask;
43
44impl Command for UMask {
45 fn name(&self) -> &str {
46 "umask"
47 }
48
49 fn description(&self) -> &str {
50 "Get or set default file creation permissions."
51 }
52
53 fn extra_description(&self) -> &str {
54 "When setting a new mask, the previous mask will be returned."
55 }
56
57 fn search_terms(&self) -> Vec<&str> {
58 vec!["permissions", "create", "file", "directory", "folder"]
59 }
60
61 fn signature(&self) -> Signature {
62 Signature::build("umask")
63 .input_output_types(vec![(Type::Nothing, Type::String)])
64 .optional(
65 "permissions",
66 SyntaxShape::String,
67 "The permissions to set on created files.",
68 )
69 .category(Category::Platform)
70 }
71
72 fn run(
73 &self,
74 engine_state: &EngineState,
75 stack: &mut Stack,
76 call: &Call,
77 _input: PipelineData,
78 ) -> Result<PipelineData, ShellError> {
79 let maybe_perms_val = call.opt::<Spanned<String>>(engine_state, stack, 0)?;
80
81 let prev_mask_bits = if let Some(perms_val) = maybe_perms_val {
82 let perms = Mode(
83 perms_val
84 .item
85 .parse()
86 .map_err(|err| ShellError::IncorrectValue {
87 msg: format!("Invalid mode: {0}.", err),
88 val_span: perms_val.span,
89 call_span: call.head,
90 })?,
91 );
92
93 let mask_bits = 0o777 ^ mode_t::from(perms);
96
97 let mask =
98 nix::sys::stat::Mode::from_bits(mask_bits).ok_or(ShellError::IncorrectValue {
99 msg: "Invalid mask; unrecognized permission bits.".into(),
102 val_span: perms_val.span,
103 call_span: call.head,
104 })?;
105
106 nix::sys::stat::umask(mask).bits()
107 } else {
108 get_umask() as mode_t
109 };
110
111 let prev_perms = Mode::from(0o777 ^ prev_mask_bits);
114
115 Ok(Value::string(prev_perms.to_string(), call.head).into_pipeline_data())
116 }
117
118 fn examples(&self) -> Vec<Example<'_>> {
119 vec![
120 Example {
121 description: "Print current default file creation permissions.",
122 example: "umask",
123 result: None,
124 },
125 Example {
126 description: "Make new files read-only to group and inaccessible to others.",
127 example: "umask rwxr-x---",
128 result: None,
129 },
130 ]
131 }
132}