Skip to main content

starnix_modules_inotify/
syscalls.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::inotify::InotifyFileObject;
6use starnix_core::task::CurrentTask;
7use starnix_core::vfs::syscalls::{LookupFlags, lookup_at};
8use starnix_core::vfs::{FdFlags, FdNumber, WdNumber};
9use starnix_sync::{Locked, Unlocked};
10use starnix_uapi::errors::Errno;
11use starnix_uapi::inotify_mask::InotifyMask;
12use starnix_uapi::user_address::UserCString;
13use starnix_uapi::{IN_CLOEXEC, IN_NONBLOCK, errno, error};
14
15pub fn sys_inotify_init1(
16    locked: &mut Locked<Unlocked>,
17    current_task: &CurrentTask,
18    flags: u32,
19) -> Result<FdNumber, Errno> {
20    if flags & !(IN_NONBLOCK | IN_CLOEXEC) != 0 {
21        return error!(EINVAL);
22    }
23    let non_blocking = flags & IN_NONBLOCK != 0;
24    let close_on_exec = flags & IN_CLOEXEC != 0;
25    let inotify_file = InotifyFileObject::new_file(locked, current_task, non_blocking);
26    let fd_flags = if close_on_exec { FdFlags::CLOEXEC } else { FdFlags::empty() };
27    current_task.add_file(locked, inotify_file, fd_flags)
28}
29
30pub fn sys_inotify_init(
31    locked: &mut Locked<Unlocked>,
32    current_task: &CurrentTask,
33) -> Result<FdNumber, Errno> {
34    sys_inotify_init1(locked, current_task, 0)
35}
36
37pub fn sys_inotify_add_watch(
38    locked: &mut Locked<Unlocked>,
39    current_task: &CurrentTask,
40    fd: FdNumber,
41    user_path: UserCString,
42    mask: u32,
43) -> Result<WdNumber, Errno> {
44    let mask = InotifyMask::from_bits(mask).ok_or_else(|| errno!(EINVAL))?;
45    if !mask.intersects(InotifyMask::ALL_EVENTS) {
46        // Mask must include at least 1 event.
47        return error!(EINVAL);
48    }
49    let file = current_task.files().get(fd)?;
50    let inotify_file = file.downcast_file::<InotifyFileObject>().ok_or_else(|| errno!(EINVAL))?;
51    let options = if mask.contains(InotifyMask::DONT_FOLLOW) {
52        LookupFlags::no_follow()
53    } else {
54        LookupFlags::default()
55    };
56    let watched_node = lookup_at(locked, current_task, FdNumber::AT_FDCWD, user_path, options)?;
57    if mask.contains(InotifyMask::ONLYDIR) && !watched_node.entry.node.is_dir() {
58        return error!(ENOTDIR);
59    }
60    inotify_file.add_watch(watched_node.entry, mask, &file)
61}
62
63pub fn sys_inotify_rm_watch(
64    _locked: &mut Locked<Unlocked>,
65    current_task: &CurrentTask,
66    fd: FdNumber,
67    watch_id: WdNumber,
68) -> Result<(), Errno> {
69    let file = current_task.files().get(fd)?;
70    let inotify_file = file.downcast_file::<InotifyFileObject>().ok_or_else(|| errno!(EINVAL))?;
71    inotify_file.remove_watch(watch_id, &file)
72}
73
74pub fn sys_arch32_inotify_init1(
75    locked: &mut Locked<Unlocked>,
76    current_task: &CurrentTask,
77    flags: u32,
78) -> Result<FdNumber, Errno> {
79    sys_inotify_init1(locked, current_task, flags)
80}
81
82pub fn sys_arch32_inotify_init(
83    locked: &mut Locked<Unlocked>,
84    current_task: &CurrentTask,
85) -> Result<FdNumber, Errno> {
86    sys_inotify_init1(locked, current_task, 0)
87}
88
89pub fn sys_arch32_inotify_add_watch(
90    locked: &mut Locked<Unlocked>,
91    current_task: &CurrentTask,
92    fd: FdNumber,
93    user_path: UserCString,
94    mask: u32,
95) -> Result<WdNumber, Errno> {
96    sys_inotify_add_watch(locked, current_task, fd, user_path, mask)
97}
98
99pub fn sys_arch32_inotify_rm_watch(
100    locked: &mut Locked<Unlocked>,
101    current_task: &CurrentTask,
102    fd: FdNumber,
103    watch_id: WdNumber,
104) -> Result<(), Errno> {
105    sys_inotify_rm_watch(locked, current_task, fd, watch_id)
106}