summary refs log tree commit diff
path: root/sys_util/src/file_flags.rs
blob: 7a2ad1baeb96d9fdae986634ac73499668b91820 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::os::unix::io::AsRawFd;

use libc::{fcntl, EINVAL, F_GETFL, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY};

use crate::{errno_result, Error, Result};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FileFlags {
    Read,
    Write,
    ReadWrite,
}

impl FileFlags {
    pub fn from_file(file: &dyn AsRawFd) -> Result<FileFlags> {
        // Trivially safe because fcntl with the F_GETFL command is totally safe and we check for
        // error.
        let flags = unsafe { fcntl(file.as_raw_fd(), F_GETFL) };
        if flags == -1 {
            errno_result()
        } else {
            match flags & O_ACCMODE {
                O_RDONLY => Ok(FileFlags::Read),
                O_WRONLY => Ok(FileFlags::Write),
                O_RDWR => Ok(FileFlags::ReadWrite),
                _ => Err(Error::new(EINVAL)),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{pipe, EventFd};

    #[test]
    fn pipe_pair() {
        let (read_pipe, write_pipe) = pipe(true).unwrap();
        assert_eq!(FileFlags::from_file(&read_pipe).unwrap(), FileFlags::Read);
        assert_eq!(FileFlags::from_file(&write_pipe).unwrap(), FileFlags::Write);
    }

    #[test]
    fn eventfd() {
        let evt = EventFd::new().unwrap();
        assert_eq!(FileFlags::from_file(&evt).unwrap(), FileFlags::ReadWrite);
    }
}