blob: a4f38807bd9a9c1b789b187ee7e4da40e9df0054 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(https://fxbug.dev/324080864): Delete this module when we remove all deprecated functionality
// from fuchsia.io.
use assert_matches::assert_matches;
use fidl::endpoints::{DiscoverableProtocolMarker as _, ProtocolMarker, create_proxy};
use fidl_fuchsia_io as fio;
use fidl_test_placeholders::EchoMarker;
use fuchsia_async::{DurationExt as _, TimeoutExt as _};
use futures::StreamExt as _;
use io_conformance_util::test_harness::TestHarness;
use io_conformance_util::*;
const TEST_STRING: &'static str = "Hello, world!";
/// Asserts that no [`fio::NodeEvent::OnOpen_`] event is sent on an opened proxy.
async fn assert_on_open_not_received(node_proxy: &fio::NodeProxy) {
let mut events = Clone::clone(node_proxy).take_event_stream();
// Wait at most 200ms for an OnOpen event to appear.
let event = events
.next()
.on_timeout(zx::MonotonicDuration::from_millis(200).after_now(), || Option::None)
.await;
assert!(event.is_none(), "Unexpected OnOpen event received");
}
/// Helper function to open the desired node in the root folder.
/// Asserts that deprecated_open_node_status succeeds.
async fn deprecated_open_node<T: ProtocolMarker>(
dir: &fio::DirectoryProxy,
flags: fio::OpenFlags,
path: &str,
) -> T::Proxy {
deprecated_open_node_status::<T>(dir, flags, path).await.unwrap_or_else(|e| {
panic!("deprecated_open_node_status failed for {path} (flags={flags:?}): {e:?}")
})
}
/// Helper function to open the desired node in the root folder.
async fn deprecated_open_node_status<T: ProtocolMarker>(
dir: &fio::DirectoryProxy,
flags: fio::OpenFlags,
path: &str,
) -> Result<T::Proxy, zx::Status> {
let flags = flags | fio::OpenFlags::DESCRIBE;
let (node_proxy, node_server) = create_proxy::<fio::NodeMarker>();
dir.deprecated_open(flags, fio::ModeType::empty(), path, node_server)
.expect("Cannot open node");
let status = get_open_status(&node_proxy).await;
if status != zx::Status::OK { Err(status) } else { Ok(convert_node_proxy(node_proxy)) }
}
/// Helper function to open a file with the given flags. Only use this if testing something other
/// than the open call directly.
async fn deprecated_open_file_with_flags(
parent_dir: &fio::DirectoryProxy,
flags: fio::OpenFlags,
path: &str,
) -> fio::FileProxy {
deprecated_open_node::<fio::FileMarker>(
&parent_dir,
flags | fio::OpenFlags::NOT_DIRECTORY,
path,
)
.await
}
/// Helper function to open a sub-directory with the given flags. Only use this if testing
/// something other than the open call directly.
async fn deprecated_open_dir_with_flags(
parent_dir: &fio::DirectoryProxy,
flags: fio::OpenFlags,
path: &str,
) -> fio::DirectoryProxy {
deprecated_open_node::<fio::DirectoryMarker>(
&parent_dir,
flags | fio::OpenFlags::DIRECTORY,
path,
)
.await
}
#[fuchsia::test]
async fn deprecated_open_dir_without_describe_flag() {
let harness = TestHarness::new().await;
let dir = harness.get_directory(vec![], harness.dir_rights.all_flags());
for dir_flags in harness.dir_rights.combinations_deprecated() {
assert_eq!(dir_flags & fio::OpenFlags::DESCRIBE, fio::OpenFlags::empty());
let (client, server) = create_proxy::<fio::NodeMarker>();
dir.deprecated_open(
dir_flags | fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
".",
server,
)
.expect("Cannot open directory");
assert_on_open_not_received(&client).await;
}
}
#[fuchsia::test]
async fn deprecated_open_file_without_describe_flag() {
let harness = TestHarness::new().await;
for file_flags in harness.file_rights.combinations_deprecated() {
assert_eq!(file_flags & fio::OpenFlags::DESCRIBE, fio::OpenFlags::empty());
let entries = vec![file(TEST_FILE, vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let (client, server) = create_proxy::<fio::NodeMarker>();
dir.deprecated_open(
file_flags | fio::OpenFlags::NOT_DIRECTORY,
fio::ModeType::empty(),
TEST_FILE,
server,
)
.expect("Cannot open file");
assert_on_open_not_received(&client).await;
}
}
#[fuchsia::test]
async fn deprecated_open_epitaph_no_describe() {
let harness = TestHarness::new().await;
let dir = harness.get_directory(vec![], harness.dir_rights.all_flags());
let (client, server) = create_proxy::<fio::NodeMarker>();
dir.deprecated_open(
fio::OpenFlags::RIGHT_READABLE,
fio::ModeType::empty(),
"does_not_exist",
server,
)
.expect("Open should not fail!");
// Since Open1 is asynchronous, we need to invoke another method on the channel to check that
// opening failed.
let e = client
.get_attributes(Default::default())
.await
.expect_err("GetAttributes should fail on a nonexistent file.");
assert_matches!(e, fidl::Error::ClientChannelClosed { status: zx::Status::NOT_FOUND, .. });
}
/// Checks that open fails with ZX_ERR_BAD_PATH when it should.
#[fuchsia::test]
async fn deprecated_open_path() {
let harness = TestHarness::new().await;
let entries = vec![directory("dir", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
// Valid paths:
for path in [".", "/", "/dir/"] {
deprecated_open_node::<fio::NodeMarker>(&dir, fio::OpenFlags::RIGHT_READABLE, path).await;
}
// Invalid paths:
for path in [
"", "//", "///", "////", "./", "/dir//", "//dir//", "/dir//", "/dir/../", "/dir/..",
"/dir/./", "/dir/.", "/./", "./dir",
] {
assert_eq!(
deprecated_open_node_status::<fio::NodeMarker>(
&dir,
fio::OpenFlags::RIGHT_READABLE,
path
)
.await
.expect_err("open succeeded"),
zx::Status::INVALID_ARGS,
"path: {}",
path,
);
}
}
/// Check that a trailing flash with OPEN_FLAG_NOT_DIRECTORY returns ZX_ERR_INVALID_ARGS.
#[fuchsia::test]
async fn deprecated_open_trailing_slash_with_not_directory() {
let harness = TestHarness::new().await;
let dir = harness.get_directory(vec![], harness.dir_rights.all_flags());
assert_eq!(
deprecated_open_node_status::<fio::NodeMarker>(
&dir,
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::NOT_DIRECTORY,
"foo/"
)
.await
.expect_err("open succeeded"),
zx::Status::INVALID_ARGS
);
}
/// Creates a directory with all rights, and checks it can be opened for all subsets of rights.
#[fuchsia::test]
async fn deprecated_open_dir_with_sufficient_rights() {
let harness = TestHarness::new().await;
let dir = harness.get_directory(vec![], harness.dir_rights.all_flags());
for dir_flags in harness.dir_rights.combinations_deprecated() {
let (client, server) = create_proxy::<fio::NodeMarker>();
dir.deprecated_open(
dir_flags | fio::OpenFlags::DESCRIBE | fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
".",
server,
)
.expect("Cannot open directory");
assert_eq!(get_open_status(&client).await, zx::Status::OK);
}
}
/// Creates a directory with no rights, and checks opening it with any rights fails.
#[fuchsia::test]
async fn deprecated_open_dir_with_insufficient_rights() {
let harness = TestHarness::new().await;
let dir = harness.get_directory(vec![], fio::Flags::empty());
for dir_flags in harness.dir_rights.combinations_deprecated() {
if dir_flags.is_empty() {
continue;
}
let (client, server) = create_proxy::<fio::NodeMarker>();
dir.deprecated_open(
dir_flags | fio::OpenFlags::DESCRIBE | fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
".",
server,
)
.expect("Cannot open directory");
assert_eq!(get_open_status(&client).await, zx::Status::ACCESS_DENIED);
}
}
/// Opens a directory, and checks that a child directory can be opened using the same rights.
#[fuchsia::test]
async fn deprecated_open_child_dir_with_same_rights() {
let harness = TestHarness::new().await;
for dir_flags in harness.dir_rights.combinations_deprecated() {
let entries = vec![directory("child", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let parent_dir = deprecated_open_node::<fio::DirectoryMarker>(
&dir,
dir_flags | fio::OpenFlags::DIRECTORY,
".",
)
.await;
// Open child directory with same flags as parent.
let (child_dir_client, child_dir_server) = create_proxy::<fio::NodeMarker>();
parent_dir
.deprecated_open(
dir_flags | fio::OpenFlags::DESCRIBE | fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
"child",
child_dir_server,
)
.expect("Cannot open directory");
assert_eq!(get_open_status(&child_dir_client).await, zx::Status::OK);
}
}
/// Opens a directory as readable, and checks that a child directory cannot be opened as writable.
#[fuchsia::test]
async fn deprecated_open_child_dir_with_extra_rights() {
let harness = TestHarness::new().await;
let entries = vec![directory("child", vec![])];
let dir = harness.get_directory(entries, fio::PERM_READABLE);
// Open parent as readable.
let parent_dir = deprecated_open_node::<fio::DirectoryMarker>(
&dir,
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::DIRECTORY,
".",
)
.await;
// Opening child as writable should fail.
let (child_dir_client, child_dir_server) = create_proxy::<fio::NodeMarker>();
parent_dir
.deprecated_open(
fio::OpenFlags::RIGHT_WRITABLE | fio::OpenFlags::DESCRIBE | fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
"child",
child_dir_server,
)
.expect("Cannot open directory");
assert_eq!(get_open_status(&child_dir_client).await, zx::Status::ACCESS_DENIED);
}
/// Creates a child directory and opens it with OPEN_FLAG_POSIX_WRITABLE/EXECUTABLE, ensuring that
/// the requested rights are expanded to only those which the parent directory connection has.
#[fuchsia::test]
async fn deprecated_open_child_dir_with_posix_flags() {
let harness = TestHarness::new().await;
for dir_flags in harness.dir_rights.combinations_deprecated() {
let entries = vec![directory("child", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let readable = dir_flags & fio::OpenFlags::RIGHT_READABLE;
let parent_dir = deprecated_open_node::<fio::DirectoryMarker>(
&dir,
dir_flags | fio::OpenFlags::DIRECTORY,
".",
)
.await;
let (child_dir_client, child_dir_server) = create_proxy::<fio::NodeMarker>();
parent_dir
.deprecated_open(
readable
| fio::OpenFlags::POSIX_WRITABLE
| fio::OpenFlags::POSIX_EXECUTABLE
| fio::OpenFlags::DESCRIBE
| fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
"child",
child_dir_server,
)
.expect("Cannot open directory");
assert_eq!(
get_open_status(&child_dir_client).await,
zx::Status::OK,
"Failed to open directory, flags = {:?}",
dir_flags
);
// Ensure expanded rights do not exceed those of the parent directory connection.
let (status, flags) =
child_dir_client.deprecated_get_flags().await.expect("Failed to get node flags!");
assert_matches!(zx::Status::ok(status), Ok(()));
assert_eq!(flags & dir_flags, dir_flags);
}
}
/// Ensures that opening a file with more rights than the directory connection fails
/// with Status::ACCESS_DENIED.
#[fuchsia::test]
async fn deprecated_open_file_with_extra_rights() {
let harness = TestHarness::new().await;
// Combinations to test of the form (directory flags, [file flag combinations]).
// All file flags should have more rights than those of the directory flags.
let test_right_combinations = [
(fio::OpenFlags::empty(), harness.file_rights.combinations_deprecated()),
(
fio::OpenFlags::RIGHT_READABLE,
harness.file_rights.combinations_containing_deprecated(fio::Rights::WRITE_BYTES),
),
(
fio::OpenFlags::RIGHT_WRITABLE,
harness.file_rights.combinations_containing_deprecated(fio::Rights::READ_BYTES),
),
];
let entries = vec![file(TEST_FILE, vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
for (dir_flags, file_flag_combos) in test_right_combinations.iter() {
let dir_proxy = deprecated_open_node::<fio::DirectoryMarker>(
&dir,
*dir_flags | fio::OpenFlags::DIRECTORY,
".",
)
.await;
for file_flags in file_flag_combos {
if file_flags.is_empty() {
continue; // The rights in file_flags must *exceed* those in dir_flags.
}
// Ensure the combination is valid (e.g. that file_flags is requesting more rights
// than those in dir_flags).
assert!(
(*file_flags & harness.dir_rights.all_flags_deprecated())
!= (*dir_flags & harness.dir_rights.all_flags_deprecated()),
"Invalid test: file rights must exceed dir! (flags: dir = {:?}, file = {:?})",
*dir_flags,
*file_flags
);
let (client, server) = create_proxy::<fio::NodeMarker>();
dir_proxy
.deprecated_open(
*file_flags | fio::OpenFlags::DESCRIBE | fio::OpenFlags::NOT_DIRECTORY,
fio::ModeType::empty(),
TEST_FILE,
server,
)
.expect("Cannot open file");
assert_eq!(
get_open_status(&client).await,
zx::Status::ACCESS_DENIED,
"Opened a file with more rights than the directory! (flags: dir = {:?}, file = {:?})",
*dir_flags,
*file_flags
);
}
}
}
/// Opening a service node without any flags should connect the channel to the service.
#[fuchsia::test]
async fn deprecated_open_service() {
let harness = TestHarness::new().await;
if !harness.config.supports_services {
return;
}
let svc_dir = harness.open_service_directory().await;
let (echo_proxy, echo_server) = create_proxy::<EchoMarker>();
svc_dir
.deprecated_open(
fio::OpenFlags::empty(),
fio::ModeType::empty(),
EchoMarker::PROTOCOL_NAME,
echo_server.into_channel().into(),
)
.unwrap();
let echo_response = echo_proxy.echo_string(Some(TEST_STRING)).await.unwrap();
assert_eq!(echo_response.unwrap(), TEST_STRING);
}
/// Opening a service node with [`fio::OpenFlags::NODE_REFERENCE`] should open the underlying node.
#[fuchsia::test]
async fn deprecated_open_service_node_reference() {
let harness = TestHarness::new().await;
if !harness.config.supports_services {
return;
}
let svc_dir = harness.open_service_directory().await;
let (echo_proxy, echo_server) = create_proxy::<fio::NodeMarker>();
svc_dir
.deprecated_open(
fio::OpenFlags::NODE_REFERENCE,
fio::ModeType::empty(),
EchoMarker::PROTOCOL_NAME,
echo_server.into_channel().into(),
)
.unwrap();
let (_, attrs) = echo_proxy
.get_attributes(fio::NodeAttributesQuery::PROTOCOLS)
.await
.expect("transport error")
.expect("get attributes");
assert_eq!(attrs.protocols.unwrap(), fio::NodeProtocolKinds::CONNECTOR);
}
/// Creates a directory with a remote mount inside of it, and checks that the remote can be opened.
#[fuchsia::test]
async fn deprecated_open_remote_directory_test() {
let harness = TestHarness::new().await;
if !harness.config.supports_remote_dir {
return;
}
let remote_name = "remote_directory";
let remote_dir = harness.get_directory(vec![], fio::PERM_READABLE | fio::PERM_WRITABLE);
// Create a directory with the remote directory inside of it.
let entries = vec![remote_directory(remote_name, remote_dir)];
let dir = harness.get_directory(entries, fio::PERM_READABLE | fio::PERM_WRITABLE);
deprecated_open_node::<fio::DirectoryMarker>(
&dir,
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE | fio::OpenFlags::DIRECTORY,
remote_name,
)
.await;
}
/// Creates a directory with a remote mount containing a file inside of it, and checks that the
/// file can be opened through the remote.
#[fuchsia::test]
async fn deprecated_open_remote_file_test() {
let harness = TestHarness::new().await;
if !harness.config.supports_remote_dir {
return;
}
let remote_name = "remote_directory";
let remote_entries = vec![file(TEST_FILE, vec![])];
let remote_dir = harness.get_directory(remote_entries, fio::PERM_READABLE);
// Create a directory with the remote directory inside of it.
let entries = vec![remote_directory(remote_name, remote_dir)];
let dir = harness.get_directory(entries, fio::PERM_READABLE | fio::PERM_WRITABLE);
// Test opening file by opening the remote directory first and then opening the file.
let remote_dir_proxy = deprecated_open_node::<fio::DirectoryMarker>(
&dir,
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::DIRECTORY,
remote_name,
)
.await;
deprecated_open_node::<fio::NodeMarker>(
&remote_dir_proxy,
fio::OpenFlags::RIGHT_READABLE,
TEST_FILE,
)
.await;
// Test opening file directly though local directory by crossing remote automatically.
deprecated_open_node::<fio::NodeMarker>(
&dir,
fio::OpenFlags::RIGHT_READABLE,
[remote_name, "/", TEST_FILE].join("").as_str(),
)
.await;
}
/// Ensure specifying POSIX_* flags cannot cause rights escalation (https://fxbug.dev/42116881).
/// The test sets up the following hierarchy of nodes:
///
/// --------------------- RW --------------------------
/// | root_proxy | ---> | root |
/// --------------------- (a) | - /mount_point | RWX ---------------------
/// | (remote_proxy) | ---> | remote_dir |
/// -------------------------- (b) ---------------------
///
/// To validate the right escalation issue has been resolved, we call Open() on the dir_proxy
/// passing in both POSIX_* flags, which if handled correctly, should result in opening
/// remote_dir_server as RW (and NOT RWX, which can occur if both flags are passed directly to the
/// remote instead of being removed).
#[fuchsia::test]
async fn deprecated_open_remote_directory_right_escalation_test() {
let harness = TestHarness::new().await;
if !harness.config.supports_remote_dir {
return;
}
let mount_point = "mount_point";
// Use the test harness to serve a directory with RWX permissions.
let remote_proxy = harness
.get_directory(vec![], fio::PERM_READABLE | fio::PERM_WRITABLE | fio::PERM_EXECUTABLE);
// Mount the remote directory through root, and ensure that the connection only has RW
// RW permissions (which is thus a sub-set of the permissions the remote_proxy has).
let entries = vec![remote_directory(mount_point, remote_proxy)];
let root_proxy = harness.get_directory(entries, fio::PERM_READABLE | fio::PERM_WRITABLE);
// Create a new proxy/server for opening the remote node through dir_proxy.
// Here we pass the POSIX flag, which should only expand to the maximum set of
// rights available along the open chain.
let (node_proxy, node_server) = create_proxy::<fio::NodeMarker>();
root_proxy
.deprecated_open(
fio::OpenFlags::RIGHT_READABLE
| fio::OpenFlags::POSIX_WRITABLE
| fio::OpenFlags::POSIX_EXECUTABLE
| fio::OpenFlags::DIRECTORY,
fio::ModeType::empty(),
mount_point,
node_server,
)
.expect("Cannot open remote directory");
// Since the root node only has RW permissions, and even though the remote has RWX,
// we should only get RW permissions back.
let (_, node_flags) = node_proxy.deprecated_get_flags().await.unwrap();
assert_eq!(node_flags, fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE);
}
#[fuchsia::test]
async fn deprecated_set_attr_and_set_flags_on_node() {
let harness = TestHarness::new().await;
let entries = vec![file("file", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let proxy =
dir.open_node::<fio::NodeMarker>("file", fio::Flags::PROTOCOL_NODE, None).await.unwrap();
assert_eq!(
zx::Status::ok(
proxy
.deprecated_set_attr(
fio::NodeAttributeFlags::MODIFICATION_TIME,
&fio::NodeAttributes {
mode: 0,
id: 0,
content_size: 0,
storage_size: 0,
link_count: 0,
creation_time: 0,
modification_time: 1234
}
)
.await
.expect("set_attr failed")
),
Err(zx::Status::BAD_HANDLE)
);
assert_eq!(
zx::Status::ok(
proxy.deprecated_set_flags(fio::OpenFlags::APPEND).await.expect("set_flags failed")
),
Err(zx::Status::BAD_HANDLE)
);
}
#[fuchsia::test]
async fn deprecated_set_attr_file_with_sufficient_rights() {
let harness = TestHarness::new().await;
if !harness.supports_mutable_attrs() {
return;
}
for file_flags in
harness.file_rights.combinations_containing_deprecated(fio::Rights::WRITE_BYTES)
{
let entries = vec![file("file", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let file = deprecated_open_file_with_flags(&dir, file_flags, "file").await;
let (status, old_attr) = file.deprecated_get_attr().await.expect("get_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::OK);
// Set CREATION_TIME flag, but not MODIFICATION_TIME.
let status = file
.deprecated_set_attr(
fio::NodeAttributeFlags::CREATION_TIME,
&fio::NodeAttributes {
creation_time: 111,
modification_time: 222,
..EMPTY_NODE_ATTRS
},
)
.await
.expect("set_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::OK);
let (status, new_attr) = file.deprecated_get_attr().await.expect("get_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::OK);
// Check that only creation_time was updated.
let expected = fio::NodeAttributes { creation_time: 111, ..old_attr };
assert_eq!(new_attr, expected);
}
}
#[fuchsia::test]
async fn deprecated_set_attr_file_with_insufficient_rights() {
let harness = TestHarness::new().await;
if !harness.supports_mutable_attrs() {
return;
}
for file_flags in harness.file_rights.combinations_without_deprecated(fio::Rights::WRITE_BYTES)
{
let entries = vec![file("file", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let file = deprecated_open_file_with_flags(&dir, file_flags, "file").await;
let status = file
.deprecated_set_attr(
fio::NodeAttributeFlags::CREATION_TIME,
&fio::NodeAttributes {
creation_time: 111,
modification_time: 222,
..EMPTY_NODE_ATTRS
},
)
.await
.expect("set_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::BAD_HANDLE);
}
}
#[fuchsia::test]
async fn deprecated_set_attr_directory_with_sufficient_rights() {
let harness = TestHarness::new().await;
if !harness.supports_mutable_attrs() {
return;
}
for dir_flags in
harness.file_rights.combinations_containing_deprecated(fio::Rights::WRITE_BYTES)
{
let entries = vec![directory("dir", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let dir = deprecated_open_dir_with_flags(&dir, dir_flags, "dir").await;
let (status, old_attr) = dir.deprecated_get_attr().await.expect("get_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::OK);
// Set CREATION_TIME flag, but not MODIFICATION_TIME.
let status = dir
.deprecated_set_attr(
fio::NodeAttributeFlags::CREATION_TIME,
&fio::NodeAttributes {
creation_time: 111,
modification_time: 222,
..EMPTY_NODE_ATTRS
},
)
.await
.expect("set_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::OK);
let (status, new_attr) = dir.deprecated_get_attr().await.expect("get_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::OK);
// Check that only creation_time was updated.
let expected = fio::NodeAttributes { creation_time: 111, ..old_attr };
assert_eq!(new_attr, expected);
}
}
#[fuchsia::test]
async fn deprecated_set_attr_directory_with_insufficient_rights() {
let harness = TestHarness::new().await;
if !harness.supports_mutable_attrs() {
return;
}
for dir_flags in harness.file_rights.combinations_without_deprecated(fio::Rights::WRITE_BYTES) {
let entries = vec![directory("dir", vec![])];
let dir = harness.get_directory(entries, harness.dir_rights.all_flags());
let dir = deprecated_open_dir_with_flags(&dir, dir_flags, "dir").await;
let status = dir
.deprecated_set_attr(
fio::NodeAttributeFlags::CREATION_TIME,
&fio::NodeAttributes {
creation_time: 111,
modification_time: 222,
..EMPTY_NODE_ATTRS
},
)
.await
.expect("set_attr failed");
assert_eq!(zx::Status::from_raw(status), zx::Status::BAD_HANDLE);
}
}