Skip to main content

ragfs_fuse/filesystem/
ops.rs

1//! `.ops/` virtual files.
2
3use fuser::{FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, ReplyWrite};
4use libc::ENOENT;
5
6use super::{RagFs, TTL, reply_file_bytes};
7use crate::inode::{
8    OPS_BATCH_INO, OPS_CREATE_INO, OPS_DELETE_INO, OPS_DIR_INO, OPS_MOVE_INO, OPS_RESULT_INO,
9    RAGFS_DIR_INO,
10};
11
12impl RagFs {
13    pub(crate) fn lookup_ops_dir(&mut self, name_str: &str, reply: ReplyEntry) {
14        match name_str {
15            ".create" => {
16                let attr = self.make_attr(OPS_CREATE_INO, FileType::RegularFile, 0);
17                reply.entry(&TTL, &attr, 0);
18            }
19            ".delete" => {
20                let attr = self.make_attr(OPS_DELETE_INO, FileType::RegularFile, 0);
21                reply.entry(&TTL, &attr, 0);
22            }
23            ".move" => {
24                let attr = self.make_attr(OPS_MOVE_INO, FileType::RegularFile, 0);
25                reply.entry(&TTL, &attr, 0);
26            }
27            ".batch" => {
28                let attr = self.make_attr(OPS_BATCH_INO, FileType::RegularFile, 0);
29                reply.entry(&TTL, &attr, 0);
30            }
31            ".result" => {
32                let content = self.runtime.block_on(self.ops_manager.get_last_result());
33                let attr =
34                    self.make_attr(OPS_RESULT_INO, FileType::RegularFile, content.len() as u64);
35                let mut cache = self.runtime.block_on(self.content_cache.write());
36                cache.insert(OPS_RESULT_INO, content);
37                reply.entry(&TTL, &attr, 0);
38            }
39            _ => reply.error(ENOENT),
40        }
41    }
42
43    pub(crate) fn getattr_ops(&mut self, ino: u64, reply: ReplyAttr) {
44        match ino {
45            OPS_DIR_INO => {
46                let attr = self.make_attr(ino, FileType::Directory, 0);
47                reply.attr(&TTL, &attr);
48            }
49            OPS_CREATE_INO | OPS_DELETE_INO | OPS_MOVE_INO | OPS_BATCH_INO => {
50                let attr = self.make_attr(ino, FileType::RegularFile, 0);
51                reply.attr(&TTL, &attr);
52            }
53            OPS_RESULT_INO => {
54                let content = self.runtime.block_on(self.ops_manager.get_last_result());
55                let size = content.len() as u64;
56                let mut cache = self.runtime.block_on(self.content_cache.write());
57                cache.insert(OPS_RESULT_INO, content);
58                let attr = self.make_attr(ino, FileType::RegularFile, size);
59                reply.attr(&TTL, &attr);
60            }
61            _ => reply.error(ENOENT),
62        }
63    }
64
65    pub(crate) fn read_ops(&mut self, ino: u64, offset: i64, size: u32, reply: ReplyData) {
66        match ino {
67            OPS_RESULT_INO => {
68                let content = self.runtime.block_on(self.ops_manager.get_last_result());
69                reply_file_bytes(reply, &content, offset, size);
70            }
71            OPS_CREATE_INO | OPS_DELETE_INO | OPS_MOVE_INO | OPS_BATCH_INO => {
72                reply.data(&[]);
73            }
74            _ => reply.error(ENOENT),
75        }
76    }
77
78    pub(crate) fn readdir_ops(&mut self, offset: i64, mut reply: ReplyDirectory) {
79        let entries = [
80            (OPS_DIR_INO, FileType::Directory, "."),
81            (RAGFS_DIR_INO, FileType::Directory, ".."),
82            (OPS_CREATE_INO, FileType::RegularFile, ".create"),
83            (OPS_DELETE_INO, FileType::RegularFile, ".delete"),
84            (OPS_MOVE_INO, FileType::RegularFile, ".move"),
85            (OPS_BATCH_INO, FileType::RegularFile, ".batch"),
86            (OPS_RESULT_INO, FileType::RegularFile, ".result"),
87        ];
88
89        for (i, (ino, kind, name)) in entries.iter().enumerate().skip(offset as usize) {
90            if reply.add(*ino, (i + 1) as i64, *kind, name) {
91                break;
92            }
93        }
94        reply.ok();
95    }
96
97    pub(crate) fn write_ops(&mut self, ino: u64, data: &[u8], reply: ReplyWrite) {
98        if ino == OPS_CREATE_INO {
99            let data_str = String::from_utf8_lossy(data).to_string();
100            let ops_manager = self.ops_manager.clone();
101            self.runtime.block_on(async move {
102                ops_manager.parse_and_create(&data_str).await;
103            });
104            reply.written(data.len() as u32);
105            return;
106        }
107        if ino == OPS_DELETE_INO {
108            let data_str = String::from_utf8_lossy(data).to_string();
109            let ops_manager = self.ops_manager.clone();
110            self.runtime.block_on(async move {
111                ops_manager.parse_and_delete(&data_str).await;
112            });
113            reply.written(data.len() as u32);
114            return;
115        }
116        if ino == OPS_MOVE_INO {
117            let data_str = String::from_utf8_lossy(data).to_string();
118            let ops_manager = self.ops_manager.clone();
119            self.runtime.block_on(async move {
120                ops_manager.parse_and_move(&data_str).await;
121            });
122            reply.written(data.len() as u32);
123            return;
124        }
125        if ino == OPS_BATCH_INO {
126            let data_str = String::from_utf8_lossy(data).to_string();
127            let ops_manager = self.ops_manager.clone();
128            self.runtime.block_on(async move {
129                ops_manager.parse_and_batch(&data_str).await;
130            });
131            reply.written(data.len() as u32);
132        }
133    }
134}