Skip to main content

fuchsia_fs/
lib.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! fuchsia.IO UTIL-ity library
6
7use flex_fuchsia_io as fio;
8
9pub mod directory;
10pub mod file;
11pub mod node;
12
13// Types/constants re-exported from fidl_fuchsia_io for convenience.
14// TODO(https://324111518): Remove the re-export of OpenFlags.
15pub use fio::{Flags, OpenFlags, PERM_EXECUTABLE, PERM_READABLE, PERM_WRITABLE};
16
17/// canonicalize_path will remove a leading `/` if it exists, since it's always unnecessary and in
18/// some cases disallowed (https://fxbug.dev/42103076).
19pub fn canonicalize_path(path: &str) -> &str {
20    if path == "/" {
21        return ".";
22    }
23    if path.starts_with('/') {
24        return &path[1..];
25    }
26    path
27}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32    use fuchsia_async as fasync;
33    use std::fs;
34    use std::path::Path;
35    use tempfile::TempDir;
36    use vfs::file::vmo::read_only;
37    use vfs::pseudo_directory;
38    use vfs::remote::remote_dir;
39    use zx_status;
40
41    #[fasync::run_singlethreaded(test)]
42    async fn open_and_read_file_test() {
43        let tempdir = TempDir::new().expect("failed to create tmp dir");
44        let data = "abc".repeat(10000);
45        fs::write(tempdir.path().join("myfile"), &data).expect("failed writing file");
46
47        let dir = crate::directory::open_in_namespace(
48            tempdir.path().to_str().unwrap(),
49            fio::PERM_READABLE,
50        )
51        .expect("could not open tmp dir");
52        let file = directory::open_file_async(&dir, "myfile", fio::PERM_READABLE)
53            .expect("could not open file");
54        let contents = file::read_to_string(&file).await.expect("could not read file");
55        assert_eq!(&contents, &data, "File contents did not match");
56    }
57
58    #[fasync::run_singlethreaded(test)]
59    async fn open_and_write_file_test() {
60        // Create temp dir for test.
61        let tempdir = TempDir::new().expect("failed to create tmp dir");
62        let dir = crate::directory::open_in_namespace(
63            tempdir.path().to_str().unwrap(),
64            fio::PERM_READABLE | fio::PERM_WRITABLE,
65        )
66        .expect("could not open tmp dir");
67
68        // Write contents.
69        let file_name = Path::new("myfile");
70        let data = "abc".repeat(10000);
71        let file = directory::open_file_async(
72            &dir,
73            file_name.to_str().unwrap(),
74            fio::Flags::FLAG_MAYBE_CREATE | fio::PERM_WRITABLE,
75        )
76        .expect("could not open file");
77        file::write(&file, &data).await.expect("could not write file");
78
79        // Verify contents.
80        let contents = std::fs::read_to_string(tempdir.path().join(file_name)).unwrap();
81        assert_eq!(&contents, &data, "File contents did not match");
82    }
83
84    #[test]
85    fn test_canonicalize_path() {
86        assert_eq!(canonicalize_path("/"), ".");
87        assert_eq!(canonicalize_path("/foo"), "foo");
88        assert_eq!(canonicalize_path("/foo/bar/"), "foo/bar/");
89
90        assert_eq!(canonicalize_path("."), ".");
91        assert_eq!(canonicalize_path("./"), "./");
92        assert_eq!(canonicalize_path("foo/bar/"), "foo/bar/");
93    }
94
95    #[fasync::run_singlethreaded(test)]
96    async fn flags_test() {
97        let tempdir = TempDir::new().expect("failed to create tmp dir");
98        std::fs::write(tempdir.path().join("read_write"), "rw/read_write")
99            .expect("failed to write file");
100        let dir = crate::directory::open_in_namespace(
101            tempdir.path().to_str().unwrap(),
102            fio::PERM_READABLE | fio::PERM_WRITABLE,
103        )
104        .expect("could not open tmp dir");
105        let example_dir = pseudo_directory! {
106            "ro" => pseudo_directory! {
107                "read_only" => read_only("ro/read_only"),
108            },
109            "rw" => remote_dir(dir)
110        };
111        let example_dir_proxy = vfs::directory::serve(
112            example_dir,
113            vfs::execution_scope::ExecutionScope::new(),
114            fio::PERM_READABLE | fio::PERM_WRITABLE,
115        );
116
117        for (file_name, flags, should_succeed) in vec![
118            ("ro/read_only", fio::PERM_READABLE, true),
119            ("ro/read_only", fio::PERM_READABLE | fio::PERM_WRITABLE, false),
120            ("ro/read_only", fio::PERM_WRITABLE, false),
121            ("rw/read_write", fio::PERM_READABLE, true),
122            ("rw/read_write", fio::PERM_READABLE | fio::PERM_WRITABLE, true),
123            ("rw/read_write", fio::PERM_WRITABLE, true),
124        ] {
125            let file_proxy =
126                directory::open_file_async(&example_dir_proxy, file_name, flags).unwrap();
127            match (should_succeed, file_proxy.query().await) {
128                (true, Ok(_)) => (),
129                (false, Err(_)) => continue,
130                (true, Err(e)) => {
131                    panic!("failed to open when expected success, couldn't describe: {:?}", e)
132                }
133                (false, Ok(d)) => {
134                    panic!("successfully opened when expected failure, could describe: {:?}", d)
135                }
136            }
137            if flags.intersects(fio::Flags::PERM_READ_BYTES) {
138                assert_eq!(
139                    file_name,
140                    file::read_to_string(&file_proxy).await.expect("failed to read file")
141                );
142            }
143            if flags.intersects(fio::Flags::PERM_WRITE_BYTES) {
144                let _: u64 = file_proxy
145                    .write(b"write_only")
146                    .await
147                    .expect("write failed")
148                    .map_err(zx_status::Status::from_raw)
149                    .expect("write error");
150            }
151            assert_eq!(file_proxy.close().await.unwrap(), Ok(()));
152        }
153    }
154}