1use crate::{ClientResult, NinePClient};
6use bytes::Bytes;
7use ninep_proto::{
8 DirEntry, DirEntryPlus, Qid, SETATTR_ATIME, SETATTR_ATIME_SET, SETATTR_GID, SETATTR_MODE,
9 SETATTR_MTIME, SETATTR_MTIME_SET, SETATTR_SIZE, SETATTR_UID, Tsetattr,
10};
11use std::collections::VecDeque;
12
13#[derive(Clone, Copy, Debug)]
15pub enum SetattrTime {
16 Now,
17 At { sec: u64, nsec: u64 },
18}
19
20pub struct SetattrBuilder {
22 ts: Tsetattr,
23}
24
25impl SetattrBuilder {
26 pub fn new(fid: u32) -> Self {
27 Self {
28 ts: Tsetattr {
29 fid,
30 valid: 0,
31 mode: 0,
32 uid: 0,
33 gid: 0,
34 size: 0,
35 atime_sec: 0,
36 atime_nsec: 0,
37 mtime_sec: 0,
38 mtime_nsec: 0,
39 },
40 }
41 }
42
43 pub fn mode(mut self, mode: Option<u32>) -> Self {
45 if let Some(mode) = mode {
46 self.ts.valid |= SETATTR_MODE;
47 self.ts.mode = mode;
48 }
49 self
50 }
51
52 pub fn uid(mut self, uid: Option<u32>) -> Self {
53 if let Some(uid) = uid {
54 self.ts.valid |= SETATTR_UID;
55 self.ts.uid = uid;
56 }
57 self
58 }
59
60 pub fn gid(mut self, gid: Option<u32>) -> Self {
61 if let Some(gid) = gid {
62 self.ts.valid |= SETATTR_GID;
63 self.ts.gid = gid;
64 }
65 self
66 }
67
68 pub fn size(mut self, size: Option<u64>) -> Self {
69 if let Some(size) = size {
70 self.ts.valid |= SETATTR_SIZE;
71 self.ts.size = size;
72 }
73 self
74 }
75
76 pub fn atime(mut self, atime: Option<SetattrTime>) -> Self {
77 match atime {
78 Some(SetattrTime::Now) => self.ts.valid |= SETATTR_ATIME,
79 Some(SetattrTime::At { sec, nsec }) => {
80 self.ts.valid |= SETATTR_ATIME | SETATTR_ATIME_SET;
81 self.ts.atime_sec = sec;
82 self.ts.atime_nsec = nsec;
83 }
84 None => {}
85 }
86 self
87 }
88
89 pub fn mtime(mut self, mtime: Option<SetattrTime>) -> Self {
90 match mtime {
91 Some(SetattrTime::Now) => self.ts.valid |= SETATTR_MTIME,
92 Some(SetattrTime::At { sec, nsec }) => {
93 self.ts.valid |= SETATTR_MTIME | SETATTR_MTIME_SET;
94 self.ts.mtime_sec = sec;
95 self.ts.mtime_nsec = nsec;
96 }
97 None => {}
98 }
99 self
100 }
101
102 pub fn build(self) -> Tsetattr {
103 self.ts
104 }
105}
106
107impl NinePClient {
108 pub async fn open_clone(
111 &self,
112 from: u32,
113 newfid: u32,
114 flags: u32,
115 fallback_flags: Option<u32>,
116 ) -> ClientResult<(Qid, u32)> {
117 let mut res = self.lopenat(from, newfid, flags).await;
118 if res.is_err()
119 && let Some(orig) = fallback_flags
120 {
121 res = self.lopenat(from, newfid, orig).await;
122 }
123 res
124 }
125
126 pub async fn open_clone_prefetch(
129 &self,
130 from: u32,
131 newfid: u32,
132 flags: u32,
133 prefetch: u32,
134 ) -> ClientResult<(Qid, u32, Option<Bytes>)> {
135 if prefetch > 0 {
136 let (qid, iounit, data, eof) = self.lopenatread(from, newfid, flags, prefetch).await?;
137 let buf = eof.then_some(data);
138 return Ok((qid, iounit, buf));
139 }
140 let (qid, iounit) = self.open_clone(from, newfid, flags, None).await?;
141 Ok((qid, iounit, None))
142 }
143}
144
145pub trait DirEntryCookie {
147 fn cookie(&self) -> u64;
148}
149
150impl DirEntryCookie for DirEntry {
151 fn cookie(&self) -> u64 {
152 self.offset
153 }
154}
155
156impl DirEntryCookie for DirEntryPlus {
157 fn cookie(&self) -> u64 {
158 self.offset
159 }
160}
161
162pub struct ReaddirState<E> {
164 pub buf: VecDeque<E>,
166 pub fetch_cookie: u64,
168 pub resume_offset: u64,
171 pub eof: bool,
173}
174
175impl<E: DirEntryCookie> ReaddirState<E> {
176 pub fn starting_at(offset: u64) -> Self {
177 Self {
178 buf: VecDeque::new(),
179 fetch_cookie: offset,
180 resume_offset: offset,
181 eof: false,
182 }
183 }
184
185 pub fn seek(&mut self, offset: u64) {
187 if offset != self.resume_offset {
188 self.buf.clear();
189 self.fetch_cookie = offset;
190 self.resume_offset = offset;
191 self.eof = false;
192 }
193 }
194
195 pub fn absorb(&mut self, entries: Vec<E>) {
197 match entries.last() {
198 Some(last) => self.fetch_cookie = last.cookie(),
199 None => self.eof = true,
200 }
201 self.buf.extend(entries);
202 }
203}