blob: a9490ff30332de47a6ed83cd08aedd0d5e034677 [file]
// Copyright 2026 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.
use crate::inotify::InotifyFileObject;
use starnix_core::task::CurrentTask;
use starnix_core::vfs::syscalls::{LookupFlags, lookup_at};
use starnix_core::vfs::{FdFlags, FdNumber, WdNumber};
use starnix_uapi::errors::Errno;
use starnix_uapi::inotify_mask::InotifyMask;
use starnix_uapi::user_address::UserCString;
use starnix_uapi::{IN_CLOEXEC, IN_NONBLOCK, errno, error};
pub fn sys_inotify_init1(current_task: &CurrentTask, flags: u32) -> Result<FdNumber, Errno> {
if flags & !(IN_NONBLOCK | IN_CLOEXEC) != 0 {
return error!(EINVAL);
}
let non_blocking = flags & IN_NONBLOCK != 0;
let close_on_exec = flags & IN_CLOEXEC != 0;
let inotify_file = InotifyFileObject::new_file(current_task, non_blocking);
let fd_flags = if close_on_exec { FdFlags::CLOEXEC } else { FdFlags::empty() };
current_task.add_file(inotify_file, fd_flags)
}
pub fn sys_inotify_init(current_task: &CurrentTask) -> Result<FdNumber, Errno> {
sys_inotify_init1(current_task, 0)
}
pub fn sys_inotify_add_watch(
current_task: &CurrentTask,
fd: FdNumber,
user_path: UserCString,
mask: u32,
) -> Result<WdNumber, Errno> {
let mask = InotifyMask::from_bits(mask).ok_or_else(|| errno!(EINVAL))?;
if !mask.intersects(InotifyMask::ALL_EVENTS) {
// Mask must include at least 1 event.
return error!(EINVAL);
}
let file = current_task.files().get(fd)?;
let inotify_file = file.downcast_file::<InotifyFileObject>().ok_or_else(|| errno!(EINVAL))?;
let options = if mask.contains(InotifyMask::DONT_FOLLOW) {
LookupFlags::no_follow()
} else {
LookupFlags::default()
};
let watched_node = lookup_at(current_task, FdNumber::AT_FDCWD, user_path, options)?;
if mask.contains(InotifyMask::ONLYDIR) && !watched_node.entry.node.is_dir() {
return error!(ENOTDIR);
}
inotify_file.add_watch(watched_node.entry, mask, &file)
}
pub fn sys_inotify_rm_watch(
current_task: &CurrentTask,
fd: FdNumber,
watch_id: WdNumber,
) -> Result<(), Errno> {
let file = current_task.files().get(fd)?;
let inotify_file = file.downcast_file::<InotifyFileObject>().ok_or_else(|| errno!(EINVAL))?;
inotify_file.remove_watch(watch_id, &file)
}
pub fn sys_arch32_inotify_init1(current_task: &CurrentTask, flags: u32) -> Result<FdNumber, Errno> {
sys_inotify_init1(current_task, flags)
}
pub fn sys_arch32_inotify_init(current_task: &CurrentTask) -> Result<FdNumber, Errno> {
sys_inotify_init1(current_task, 0)
}
pub fn sys_arch32_inotify_add_watch(
current_task: &CurrentTask,
fd: FdNumber,
user_path: UserCString,
mask: u32,
) -> Result<WdNumber, Errno> {
sys_inotify_add_watch(current_task, fd, user_path, mask)
}
pub fn sys_arch32_inotify_rm_watch(
current_task: &CurrentTask,
fd: FdNumber,
watch_id: WdNumber,
) -> Result<(), Errno> {
sys_inotify_rm_watch(current_task, fd, watch_id)
}