blob: 48084aa23dd82ff4d004591819fafd411e7ee26d [file] [log] [blame]
Victor Hsiehf393a722021-12-08 13:04:27 -08001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use log::error;
18use nix::sys::stat::{mode_t, Mode, SFlag};
19use std::io;
20
21use super::VirtFdService;
22
23/// Default/assumed mode of files not created by authfs.
24///
25/// For files that are given to authfs as FDs (i.e. not created through authfs), their mode is
26/// unknown (or untrusted) until it is ever set. The default mode is just to make it
27/// readable/writable to VFS. When the mode is set, the value on fd_server is supposed to become
28/// consistent.
29const DEFAULT_FILE_MODE: Mode =
30 Mode::from_bits_truncate(Mode::S_IRUSR.bits() | Mode::S_IWUSR.bits());
31
32/// Default/assumed mode of directories not created by authfs.
33///
34/// See above.
35const DEFAULT_DIR_MODE: Mode = Mode::S_IRWXU;
36
37/// `Attr` maintains the local truth for attributes (e.g. mode and type) while allowing setting the
38/// remote attribute for the file description.
39pub struct Attr {
40 service: VirtFdService,
41 mode: Mode,
42 remote_fd: i32,
43 is_dir: bool,
44}
45
46impl Attr {
47 pub fn new_file(service: VirtFdService, remote_fd: i32) -> Attr {
48 Attr { service, mode: DEFAULT_FILE_MODE, remote_fd, is_dir: false }
49 }
50
51 pub fn new_dir(service: VirtFdService, remote_fd: i32) -> Attr {
52 Attr { service, mode: DEFAULT_DIR_MODE, remote_fd, is_dir: true }
53 }
54
55 pub fn new_file_with_mode(service: VirtFdService, remote_fd: i32, mode: mode_t) -> Attr {
56 Attr { service, mode: Mode::from_bits_truncate(mode), remote_fd, is_dir: false }
57 }
58
59 pub fn new_dir_with_mode(service: VirtFdService, remote_fd: i32, mode: mode_t) -> Attr {
60 Attr { service, mode: Mode::from_bits_truncate(mode), remote_fd, is_dir: true }
61 }
62
63 pub fn mode(&self) -> u32 {
64 self.mode.bits()
65 }
66
67 /// Sets the file mode.
68 ///
69 /// In addition to the actual file mode, `encoded_mode` also contains information of the file
70 /// type.
71 pub fn set_mode(&mut self, encoded_mode: u32) -> io::Result<()> {
72 let new_sflag = SFlag::from_bits_truncate(encoded_mode);
73 let new_mode = Mode::from_bits_truncate(encoded_mode);
74
75 let type_flag = if self.is_dir { SFlag::S_IFDIR } else { SFlag::S_IFREG };
76 if !type_flag.contains(new_sflag) {
77 return Err(io::Error::from_raw_os_error(libc::EINVAL));
78 }
79
80 // Request for update only if changing.
81 if new_mode != self.mode {
82 self.service.chmod(self.remote_fd, new_mode.bits() as i32).map_err(|e| {
83 error!(
84 "Failed to chmod (fd: {}, mode: {:o}) on fd_server: {:?}",
85 self.remote_fd, new_mode, e
86 );
87 io::Error::from_raw_os_error(libc::EIO)
88 })?;
89 self.mode = new_mode;
90 }
91 Ok(())
92 }
93}