Skip to main content

erofs_component/
symlink.rs

1// Copyright 2026 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
5use crate::volume::ErofsVolume;
6use erofs::SymlinkNode;
7use fidl_fuchsia_io as fio;
8use std::sync::Arc;
9use vfs::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
10use vfs::node::Node;
11use vfs::symlink::Symlink;
12
13/// An implementation of an EROFS symlink node.
14pub struct ErofsSymlink {
15    volume: Arc<ErofsVolume>,
16    node: SymlinkNode,
17    target: Vec<u8>,
18}
19
20impl ErofsSymlink {
21    pub fn new(volume: Arc<ErofsVolume>, node: SymlinkNode) -> Result<Arc<Self>, zx::Status> {
22        let target = volume.fs().read_symlink(&node).map_err(|e| e.to_status())?;
23        Ok(Arc::new(Self { volume, node, target }))
24    }
25
26    pub fn node(&self) -> &SymlinkNode {
27        &self.node
28    }
29}
30
31impl GetEntryInfo for ErofsSymlink {
32    fn entry_info(&self) -> EntryInfo {
33        EntryInfo::new(self.node.nid(), fio::DirentType::Symlink)
34    }
35}
36
37impl DirectoryEntry for ErofsSymlink {
38    fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), zx::Status> {
39        request.open_symlink(self)
40    }
41}
42
43impl Node for ErofsSymlink {
44    async fn get_attributes(
45        &self,
46        requested_attributes: fio::NodeAttributesQuery,
47    ) -> Result<fio::NodeAttributes2, zx::Status> {
48        let mtime = self.node.mtime_ns();
49        let content_size = self.target.len() as u64;
50        let selinux_context = self
51            .volume
52            .fs()
53            .get_xattr(&self.node, b"security.selinux")
54            .ok()
55            .flatten()
56            .map(fio::SelinuxContext::Data);
57        Ok(vfs::attributes!(
58            requested_attributes,
59            Mutable {
60                mode: self.node.mode() as u32,
61                uid: self.node.uid(),
62                gid: self.node.gid(),
63                creation_time: mtime,
64                modification_time: mtime,
65                access_time: mtime,
66                selinux_context: selinux_context,
67            },
68            Immutable {
69                protocols: fio::NodeProtocolKinds::SYMLINK,
70                abilities: fio::Operations::GET_ATTRIBUTES,
71                content_size: content_size,
72                storage_size: content_size,
73                id: self.node.nid(),
74                link_count: self.node.link_count() as u64,
75                change_time: mtime,
76            }
77        ))
78    }
79
80    async fn list_extended_attributes(&self) -> Result<Vec<Vec<u8>>, zx::Status> {
81        self.volume.fs().list_xattrs(&self.node).map_err(|e| e.to_status())
82    }
83
84    async fn get_extended_attribute(&self, name: Vec<u8>) -> Result<Vec<u8>, zx::Status> {
85        self.volume
86            .fs()
87            .get_xattr(&self.node, &name)
88            .map_err(|e| e.to_status())?
89            .ok_or(zx::Status::NOT_FOUND)
90    }
91}
92
93impl Symlink for ErofsSymlink {
94    async fn read_target(&self) -> Result<Vec<u8>, zx::Status> {
95        Ok(self.target.clone())
96    }
97}