pub struct Client { /* private fields */ }Expand description
Blocking, path-oriented NFSv3 client.
Client owns one MOUNT/NFS connection pair and exposes storage-oriented
operations such as whole-file reads, offset reads, atomic writes, copy,
directory pagination, metadata updates, and recursive removal.
Methods take paths relative to the mounted export. The root of the export is
/.
Implementations§
Source§impl Client
impl Client
Sourcepub fn builder(
host: impl Into<String>,
export: impl Into<String>,
) -> ClientBuilder
pub fn builder( host: impl Into<String>, export: impl Into<String>, ) -> ClientBuilder
Creates a builder from host and export components.
Sourcepub fn fsinfo(&self) -> Option<&FsInfo>
pub fn fsinfo(&self) -> Option<&FsInfo>
Returns filesystem information discovered at connect time, if available.
Examples found in repository?
25fn main() -> nfs::Result<()> {
26 let config = Config::from_env();
27 let mut client = connect(&config.target)?;
28
29 println!("connected to NFSv3 target {}", config.target);
30 if let Some(info) = client.fsinfo() {
31 println!(
32 "server fsinfo: read_preferred={} write_preferred={} dir_preferred={}",
33 info.read_preferred, info.write_preferred, info.dir_preferred
34 );
35 }
36
37 let work_dir = remote_path(
38 &config.remote_dir,
39 &format!("nfs-rs-v3-cookbook-{}", std::process::id()),
40 );
41 client.remove_all_if_exists(&work_dir)?;
42 client.create_dir_all(&work_dir, 0o755)?;
43
44 let flow_result = run_filesystem_flow(&mut client, &work_dir);
45 let cleanup_result = client.remove_all_if_exists(&work_dir);
46 let unmount_result = client.unmount();
47 finish(flow_result, cleanup_result, unmount_result)
48}Sourcepub fn fsstat(&mut self, path: &str) -> Result<FsStat>
pub fn fsstat(&mut self, path: &str) -> Result<FsStat>
Reads filesystem capacity information for a path.
Examples found in repository?
196fn demonstrate_filesystem_queries(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
197 let fsstat = client.fsstat(work_dir)?;
198 println!(
199 "fsstat: total={} free={} available={}",
200 fsstat.total_bytes, fsstat.free_bytes, fsstat.available_bytes
201 );
202
203 let pathconf = client.pathconf(work_dir)?;
204 println!(
205 "pathconf: name_max={} link_max={} case_preserving={}",
206 pathconf.name_max, pathconf.link_max, pathconf.case_preserving
207 );
208
209 Ok(())
210}Sourcepub fn pathconf(&mut self, path: &str) -> Result<PathConf>
pub fn pathconf(&mut self, path: &str) -> Result<PathConf>
Reads path configuration limits for a path.
Examples found in repository?
196fn demonstrate_filesystem_queries(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
197 let fsstat = client.fsstat(work_dir)?;
198 println!(
199 "fsstat: total={} free={} available={}",
200 fsstat.total_bytes, fsstat.free_bytes, fsstat.available_bytes
201 );
202
203 let pathconf = client.pathconf(work_dir)?;
204 println!(
205 "pathconf: name_max={} link_max={} case_preserving={}",
206 pathconf.name_max, pathconf.link_max, pathconf.case_preserving
207 );
208
209 Ok(())
210}Sourcepub fn metadata(&mut self, path: &str) -> Result<FileAttr>
pub fn metadata(&mut self, path: &str) -> Result<FileAttr>
Reads NFSv3 attributes for a path.
Examples found in repository?
11fn main() -> nfs::Result<()> {
12 // Usage:
13 // cargo run --example basic -- 127.0.0.1:/export /writable-dir
14 //
15 // The first argument is an NFSv3 target in `host:/export` form.
16 // The second argument is a writable directory inside that export.
17 let mut args = std::env::args().skip(1);
18 let target = args
19 .next()
20 .unwrap_or_else(|| "127.0.0.1:/export".to_owned());
21 let dir = args.next().unwrap_or_else(|| "/".to_owned());
22 let file = remote_path(&dir, &format!("nfs-rs-v3-{}.txt", std::process::id()));
23
24 let mut client = ClientBuilder::from_target(&target)?
25 .timeout(Some(Duration::from_secs(10)))
26 .connect()?;
27
28 println!("connected to NFSv3 target {target}");
29 println!("writing {file}");
30 client.write_atomic(&file, CONTENT)?;
31
32 let data = client.read(&file)?;
33 println!("read: {}", String::from_utf8_lossy(&data));
34
35 let range = client.read_range(&file, 0, 5)?;
36 println!("first 5 bytes: {:?}", String::from_utf8_lossy(&range));
37
38 let metadata = client.metadata(&file)?;
39 println!(
40 "metadata: type={:?} size={} mode={:o}",
41 metadata.file_type,
42 metadata.size,
43 metadata.mode & 0o777
44 );
45
46 println!("first entries in {dir}:");
47 for entry in client.read_dir(&dir)?.into_iter().take(8) {
48 println!(" {}", entry.name);
49 }
50
51 client.remove_if_exists(&file)?;
52 println!("removed {file}");
53 Ok(())
54}More examples
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn file_type(&mut self, path: &str) -> Result<FileType>
pub fn file_type(&mut self, path: &str) -> Result<FileType>
Returns the remote file type for a path.
Sourcepub fn is_file(&mut self, path: &str) -> Result<bool>
pub fn is_file(&mut self, path: &str) -> Result<bool>
Returns true when the path is a regular file.
Sourcepub fn is_dir(&mut self, path: &str) -> Result<bool>
pub fn is_dir(&mut self, path: &str) -> Result<bool>
Returns true when the path is a directory.
Sourcepub fn is_symlink(&mut self, path: &str) -> Result<bool>
pub fn is_symlink(&mut self, path: &str) -> Result<bool>
Returns true when the path is a symbolic link.
Sourcepub fn access(&mut self, path: &str, access: u32) -> Result<AccessResult>
pub fn access(&mut self, path: &str, access: u32) -> Result<AccessResult>
Checks server-granted access bits for a path.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn lookup(&mut self, path: &str) -> Result<()>
pub fn lookup(&mut self, path: &str) -> Result<()>
Resolves a path and returns success if it exists.
Sourcepub fn exists(&mut self, path: &str) -> Result<bool>
pub fn exists(&mut self, path: &str) -> Result<bool>
Returns whether a path exists.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}
149
150fn demonstrate_optional_links(
151 client: &mut Client,
152 object: &str,
153 work_dir: &str,
154) -> nfs::Result<()> {
155 let symlink = remote_path(work_dir, "object.symlink");
156 if optional("symlink", client.symlink(&symlink, "object.txt")).is_some() {
157 let target = client.read_link(&symlink)?;
158 println!("symlink target: {target}");
159 }
160
161 let hard_link = remote_path(work_dir, "object.hardlink");
162 if optional("hard_link", client.hard_link(object, &hard_link)).is_some() {
163 println!("created hard link: {hard_link}");
164 }
165
166 Ok(())
167}
168
169fn demonstrate_directory_reads(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
170 println!("limited directory listing:");
171 for entry in client.read_dir_limited(work_dir, 16)? {
172 let kind = entry
173 .attributes
174 .as_ref()
175 .map(|attrs| format!("{:?}", attrs.file_type))
176 .unwrap_or_else(|| "unknown".to_owned());
177 println!(" {} fileid={} type={kind}", entry.name, entry.fileid);
178 }
179
180 println!("paged directory listing:");
181 let mut cursor: Option<DirPageCursor> = None;
182 loop {
183 let page = client.read_dir_page_limited(work_dir, cursor, 4)?;
184 for entry in &page.entries {
185 println!(" page entry: {}", entry.name);
186 }
187 if page.is_eof() {
188 break;
189 }
190 cursor = page.next_cursor;
191 }
192
193 Ok(())
194}
195
196fn demonstrate_filesystem_queries(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
197 let fsstat = client.fsstat(work_dir)?;
198 println!(
199 "fsstat: total={} free={} available={}",
200 fsstat.total_bytes, fsstat.free_bytes, fsstat.available_bytes
201 );
202
203 let pathconf = client.pathconf(work_dir)?;
204 println!(
205 "pathconf: name_max={} link_max={} case_preserving={}",
206 pathconf.name_max, pathconf.link_max, pathconf.case_preserving
207 );
208
209 Ok(())
210}
211
212fn demonstrate_error_handling(client: &mut Client, work_dir: &str) {
213 let missing = remote_path(work_dir, "does-not-exist.txt");
214 match client.read(&missing) {
215 Ok(_) => println!("unexpectedly read missing file"),
216 Err(err) if err.is_not_found() => println!("missing file classified as not found"),
217 Err(err) if err.is_retryable() => println!("retryable error: {err}"),
218 Err(err) if err.is_permission_denied() => println!("permission error: {err}"),
219 Err(err) => println!("other read error: {err}"),
220 }
221}
222
223fn demonstrate_reconnect(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
224 client.reconnect()?;
225 println!(
226 "reconnected; workspace still exists = {}",
227 client.exists(work_dir)?
228 );
229 Ok(())
230}Sourcepub fn read(&mut self, path: &str) -> Result<Vec<u8>>
pub fn read(&mut self, path: &str) -> Result<Vec<u8>>
Reads an entire file into memory.
Examples found in repository?
More examples
11fn main() -> nfs::Result<()> {
12 // Usage:
13 // cargo run --example basic -- 127.0.0.1:/export /writable-dir
14 //
15 // The first argument is an NFSv3 target in `host:/export` form.
16 // The second argument is a writable directory inside that export.
17 let mut args = std::env::args().skip(1);
18 let target = args
19 .next()
20 .unwrap_or_else(|| "127.0.0.1:/export".to_owned());
21 let dir = args.next().unwrap_or_else(|| "/".to_owned());
22 let file = remote_path(&dir, &format!("nfs-rs-v3-{}.txt", std::process::id()));
23
24 let mut client = ClientBuilder::from_target(&target)?
25 .timeout(Some(Duration::from_secs(10)))
26 .connect()?;
27
28 println!("connected to NFSv3 target {target}");
29 println!("writing {file}");
30 client.write_atomic(&file, CONTENT)?;
31
32 let data = client.read(&file)?;
33 println!("read: {}", String::from_utf8_lossy(&data));
34
35 let range = client.read_range(&file, 0, 5)?;
36 println!("first 5 bytes: {:?}", String::from_utf8_lossy(&range));
37
38 let metadata = client.metadata(&file)?;
39 println!(
40 "metadata: type={:?} size={} mode={:o}",
41 metadata.file_type,
42 metadata.size,
43 metadata.mode & 0o777
44 );
45
46 println!("first entries in {dir}:");
47 for entry in client.read_dir(&dir)?.into_iter().take(8) {
48 println!(" {}", entry.name);
49 }
50
51 client.remove_if_exists(&file)?;
52 println!("removed {file}");
53 Ok(())
54}Sourcepub fn read_to_writer<W: Write + ?Sized>(
&mut self,
path: &str,
writer: &mut W,
) -> Result<u64>
pub fn read_to_writer<W: Write + ?Sized>( &mut self, path: &str, writer: &mut W, ) -> Result<u64>
Streams an entire file into a local writer.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn read_range_to_writer<W: Write + ?Sized>(
&mut self,
path: &str,
offset: u64,
count: u64,
writer: &mut W,
) -> Result<u64>
pub fn read_range_to_writer<W: Write + ?Sized>( &mut self, path: &str, offset: u64, count: u64, writer: &mut W, ) -> Result<u64>
Streams a byte range into a local writer.
Sourcepub fn read_range(
&mut self,
path: &str,
offset: u64,
count: u64,
) -> Result<Vec<u8>>
pub fn read_range( &mut self, path: &str, offset: u64, count: u64, ) -> Result<Vec<u8>>
Reads a byte range into memory.
Examples found in repository?
11fn main() -> nfs::Result<()> {
12 // Usage:
13 // cargo run --example basic -- 127.0.0.1:/export /writable-dir
14 //
15 // The first argument is an NFSv3 target in `host:/export` form.
16 // The second argument is a writable directory inside that export.
17 let mut args = std::env::args().skip(1);
18 let target = args
19 .next()
20 .unwrap_or_else(|| "127.0.0.1:/export".to_owned());
21 let dir = args.next().unwrap_or_else(|| "/".to_owned());
22 let file = remote_path(&dir, &format!("nfs-rs-v3-{}.txt", std::process::id()));
23
24 let mut client = ClientBuilder::from_target(&target)?
25 .timeout(Some(Duration::from_secs(10)))
26 .connect()?;
27
28 println!("connected to NFSv3 target {target}");
29 println!("writing {file}");
30 client.write_atomic(&file, CONTENT)?;
31
32 let data = client.read(&file)?;
33 println!("read: {}", String::from_utf8_lossy(&data));
34
35 let range = client.read_range(&file, 0, 5)?;
36 println!("first 5 bytes: {:?}", String::from_utf8_lossy(&range));
37
38 let metadata = client.metadata(&file)?;
39 println!(
40 "metadata: type={:?} size={} mode={:o}",
41 metadata.file_type,
42 metadata.size,
43 metadata.mode & 0o777
44 );
45
46 println!("first entries in {dir}:");
47 for entry in client.read_dir(&dir)?.into_iter().take(8) {
48 println!(" {}", entry.name);
49 }
50
51 client.remove_if_exists(&file)?;
52 println!("removed {file}");
53 Ok(())
54}More examples
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn read_at(
&mut self,
path: &str,
offset: u64,
count: u32,
) -> Result<Vec<u8>>
pub fn read_at( &mut self, path: &str, offset: u64, count: u32, ) -> Result<Vec<u8>>
Reads up to count bytes at offset.
Sourcepub fn read_exact_at(
&mut self,
path: &str,
offset: u64,
count: u32,
) -> Result<Vec<u8>>
pub fn read_exact_at( &mut self, path: &str, offset: u64, count: u32, ) -> Result<Vec<u8>>
Reads exactly count bytes at offset, failing if EOF is reached first.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn read_link(&mut self, path: &str) -> Result<String>
pub fn read_link(&mut self, path: &str) -> Result<String>
Reads the target of a symbolic link.
Examples found in repository?
150fn demonstrate_optional_links(
151 client: &mut Client,
152 object: &str,
153 work_dir: &str,
154) -> nfs::Result<()> {
155 let symlink = remote_path(work_dir, "object.symlink");
156 if optional("symlink", client.symlink(&symlink, "object.txt")).is_some() {
157 let target = client.read_link(&symlink)?;
158 println!("symlink target: {target}");
159 }
160
161 let hard_link = remote_path(work_dir, "object.hardlink");
162 if optional("hard_link", client.hard_link(object, &hard_link)).is_some() {
163 println!("created hard link: {hard_link}");
164 }
165
166 Ok(())
167}Sourcepub fn write(&mut self, path: &str, data: &[u8]) -> Result<()>
pub fn write(&mut self, path: &str, data: &[u8]) -> Result<()>
Replaces or creates a file with data using file-sync stability.
Sourcepub fn write_with_stability(
&mut self,
path: &str,
data: &[u8],
stable: StableHow,
) -> Result<()>
pub fn write_with_stability( &mut self, path: &str, data: &[u8], stable: StableHow, ) -> Result<()>
Replaces or creates a file with an explicit NFS write stability level.
Sourcepub fn write_from_reader<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
) -> Result<u64>
pub fn write_from_reader<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, ) -> Result<u64>
Replaces or creates a file by streaming from a local reader.
Sourcepub fn write_from_reader_with_stability<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
stable: StableHow,
) -> Result<u64>
pub fn write_from_reader_with_stability<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, stable: StableHow, ) -> Result<u64>
Replaces or creates a file from a reader with an explicit write stability level.
Sourcepub fn write_atomic(&mut self, path: &str, data: &[u8]) -> Result<()>
pub fn write_atomic(&mut self, path: &str, data: &[u8]) -> Result<()>
Writes a file through a temporary sibling and renames it into place.
Examples found in repository?
11fn main() -> nfs::Result<()> {
12 // Usage:
13 // cargo run --example basic -- 127.0.0.1:/export /writable-dir
14 //
15 // The first argument is an NFSv3 target in `host:/export` form.
16 // The second argument is a writable directory inside that export.
17 let mut args = std::env::args().skip(1);
18 let target = args
19 .next()
20 .unwrap_or_else(|| "127.0.0.1:/export".to_owned());
21 let dir = args.next().unwrap_or_else(|| "/".to_owned());
22 let file = remote_path(&dir, &format!("nfs-rs-v3-{}.txt", std::process::id()));
23
24 let mut client = ClientBuilder::from_target(&target)?
25 .timeout(Some(Duration::from_secs(10)))
26 .connect()?;
27
28 println!("connected to NFSv3 target {target}");
29 println!("writing {file}");
30 client.write_atomic(&file, CONTENT)?;
31
32 let data = client.read(&file)?;
33 println!("read: {}", String::from_utf8_lossy(&data));
34
35 let range = client.read_range(&file, 0, 5)?;
36 println!("first 5 bytes: {:?}", String::from_utf8_lossy(&range));
37
38 let metadata = client.metadata(&file)?;
39 println!(
40 "metadata: type={:?} size={} mode={:o}",
41 metadata.file_type,
42 metadata.size,
43 metadata.mode & 0o777
44 );
45
46 println!("first entries in {dir}:");
47 for entry in client.read_dir(&dir)?.into_iter().take(8) {
48 println!(" {}", entry.name);
49 }
50
51 client.remove_if_exists(&file)?;
52 println!("removed {file}");
53 Ok(())
54}More examples
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn write_atomic_with_mode(
&mut self,
path: &str,
data: &[u8],
mode: u32,
) -> Result<()>
pub fn write_atomic_with_mode( &mut self, path: &str, data: &[u8], mode: u32, ) -> Result<()>
Atomic write with an explicit mode for the temporary file.
Sourcepub fn write_atomic_with_stability(
&mut self,
path: &str,
data: &[u8],
stable: StableHow,
) -> Result<()>
pub fn write_atomic_with_stability( &mut self, path: &str, data: &[u8], stable: StableHow, ) -> Result<()>
Atomic write with an explicit NFS write stability level.
Sourcepub fn write_atomic_with_mode_and_stability(
&mut self,
path: &str,
data: &[u8],
mode: u32,
stable: StableHow,
) -> Result<()>
pub fn write_atomic_with_mode_and_stability( &mut self, path: &str, data: &[u8], mode: u32, stable: StableHow, ) -> Result<()>
Atomic write with explicit mode and write stability.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn write_atomic_from_reader<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
) -> Result<u64>
pub fn write_atomic_from_reader<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, ) -> Result<u64>
Atomic write by streaming from a local reader.
Sourcepub fn write_atomic_from_reader_with_mode<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
mode: u32,
) -> Result<u64>
pub fn write_atomic_from_reader_with_mode<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, mode: u32, ) -> Result<u64>
Atomic reader-based write with an explicit mode for the temporary file.
Sourcepub fn write_atomic_from_reader_with_stability<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
stable: StableHow,
) -> Result<u64>
pub fn write_atomic_from_reader_with_stability<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, stable: StableHow, ) -> Result<u64>
Atomic reader-based write with an explicit NFS write stability level.
Sourcepub fn write_atomic_from_reader_with_mode_and_stability<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
mode: u32,
stable: StableHow,
) -> Result<u64>
pub fn write_atomic_from_reader_with_mode_and_stability<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, mode: u32, stable: StableHow, ) -> Result<u64>
Atomic reader-based write with explicit mode and write stability.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn append(&mut self, path: &str, data: &[u8]) -> Result<u64>
pub fn append(&mut self, path: &str, data: &[u8]) -> Result<u64>
Appends bytes to an existing file and returns bytes written.
Sourcepub fn append_with_stability(
&mut self,
path: &str,
data: &[u8],
stable: StableHow,
) -> Result<u64>
pub fn append_with_stability( &mut self, path: &str, data: &[u8], stable: StableHow, ) -> Result<u64>
Appends bytes with an explicit NFS write stability level.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn append_from_reader<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
) -> Result<u64>
pub fn append_from_reader<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, ) -> Result<u64>
Appends bytes from a local reader and returns bytes written.
Sourcepub fn append_from_reader_with_stability<R: Read + ?Sized>(
&mut self,
path: &str,
reader: &mut R,
stable: StableHow,
) -> Result<u64>
pub fn append_from_reader_with_stability<R: Read + ?Sized>( &mut self, path: &str, reader: &mut R, stable: StableHow, ) -> Result<u64>
Appends from a reader with an explicit NFS write stability level.
Sourcepub fn truncate(&mut self, path: &str, size: u64) -> Result<()>
pub fn truncate(&mut self, path: &str, size: u64) -> Result<()>
Truncates or extends a file to size bytes.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn setattr(&mut self, path: &str, attr: &SetAttr) -> Result<()>
pub fn setattr(&mut self, path: &str, attr: &SetAttr) -> Result<()>
Applies NFSv3 attributes to a path.
Sourcepub fn set_mode(&mut self, path: &str, mode: u32) -> Result<()>
pub fn set_mode(&mut self, path: &str, mode: u32) -> Result<()>
Sets POSIX mode bits.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn set_ownership(&mut self, path: &str, uid: u32, gid: u32) -> Result<()>
pub fn set_ownership(&mut self, path: &str, uid: u32, gid: u32) -> Result<()>
Sets numeric uid and gid.
Sourcepub fn set_times(
&mut self,
path: &str,
atime: Option<NfsTime>,
mtime: Option<NfsTime>,
) -> Result<()>
pub fn set_times( &mut self, path: &str, atime: Option<NfsTime>, mtime: Option<NfsTime>, ) -> Result<()>
Sets access and modification times.
Sourcepub fn touch(&mut self, path: &str) -> Result<()>
pub fn touch(&mut self, path: &str) -> Result<()>
Updates access and modification times to the server time.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn write_at(&mut self, path: &str, offset: u64, data: &[u8]) -> Result<()>
pub fn write_at(&mut self, path: &str, offset: u64, data: &[u8]) -> Result<()>
Writes bytes at offset using file-sync stability.
Sourcepub fn write_at_with_stability(
&mut self,
path: &str,
offset: u64,
data: &[u8],
stable: StableHow,
) -> Result<()>
pub fn write_at_with_stability( &mut self, path: &str, offset: u64, data: &[u8], stable: StableHow, ) -> Result<()>
Writes bytes at offset with an explicit NFS write stability level.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn copy(&mut self, from: &str, to: &str) -> Result<u64>
pub fn copy(&mut self, from: &str, to: &str) -> Result<u64>
Copies a file, replacing or creating the destination.
Sourcepub fn copy_with_stability(
&mut self,
from: &str,
to: &str,
stable: StableHow,
) -> Result<u64>
pub fn copy_with_stability( &mut self, from: &str, to: &str, stable: StableHow, ) -> Result<u64>
Copies a file with an explicit NFS write stability level.
Sourcepub fn copy_atomic(&mut self, from: &str, to: &str) -> Result<u64>
pub fn copy_atomic(&mut self, from: &str, to: &str) -> Result<u64>
Copies through a temporary sibling and renames it into place.
Sourcepub fn copy_atomic_with_stability(
&mut self,
from: &str,
to: &str,
stable: StableHow,
) -> Result<u64>
pub fn copy_atomic_with_stability( &mut self, from: &str, to: &str, stable: StableHow, ) -> Result<u64>
Atomic copy with an explicit NFS write stability level.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn commit(
&mut self,
path: &str,
offset: u64,
count: u32,
) -> Result<CommitResult>
pub fn commit( &mut self, path: &str, offset: u64, count: u32, ) -> Result<CommitResult>
Commits previously unstable writes for a byte range.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn create(&mut self, path: &str, mode: u32) -> Result<()>
pub fn create(&mut self, path: &str, mode: u32) -> Result<()>
Creates a new file using guarded create semantics.
Sourcepub fn create_new(&mut self, path: &str, mode: u32) -> Result<()>
pub fn create_new(&mut self, path: &str, mode: u32) -> Result<()>
Creates a new file and fails if it already exists.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn create_unchecked(&mut self, path: &str, mode: u32) -> Result<()>
pub fn create_unchecked(&mut self, path: &str, mode: u32) -> Result<()>
Creates or replaces a file using unchecked create semantics.
Sourcepub fn create_dir_all(&mut self, path: &str, mode: u32) -> Result<()>
pub fn create_dir_all(&mut self, path: &str, mode: u32) -> Result<()>
Creates a directory and missing parents, like mkdir -p.
Examples found in repository?
25fn main() -> nfs::Result<()> {
26 let config = Config::from_env();
27 let mut client = connect(&config.target)?;
28
29 println!("connected to NFSv3 target {}", config.target);
30 if let Some(info) = client.fsinfo() {
31 println!(
32 "server fsinfo: read_preferred={} write_preferred={} dir_preferred={}",
33 info.read_preferred, info.write_preferred, info.dir_preferred
34 );
35 }
36
37 let work_dir = remote_path(
38 &config.remote_dir,
39 &format!("nfs-rs-v3-cookbook-{}", std::process::id()),
40 );
41 client.remove_all_if_exists(&work_dir)?;
42 client.create_dir_all(&work_dir, 0o755)?;
43
44 let flow_result = run_filesystem_flow(&mut client, &work_dir);
45 let cleanup_result = client.remove_all_if_exists(&work_dir);
46 let unmount_result = client.unmount();
47 finish(flow_result, cleanup_result, unmount_result)
48}
49
50fn connect(target: &str) -> nfs::Result<Client> {
51 ClientBuilder::from_target(target)?
52 .auth_sys(AuthSys::current())
53 .timeout(Some(Duration::from_secs(10)))
54 .io_size(128 * 1024)
55 .dir_size(64 * 1024)
56 .max_dir_entries(4096)
57 .retry_policy(RetryPolicy::new(
58 4,
59 Duration::from_millis(50),
60 Duration::from_secs(2),
61 ))
62 .connect()
63}
64
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn symlink(&mut self, path: &str, target: &str) -> Result<()>
pub fn symlink(&mut self, path: &str, target: &str) -> Result<()>
Creates a symbolic link at path pointing to target.
Examples found in repository?
150fn demonstrate_optional_links(
151 client: &mut Client,
152 object: &str,
153 work_dir: &str,
154) -> nfs::Result<()> {
155 let symlink = remote_path(work_dir, "object.symlink");
156 if optional("symlink", client.symlink(&symlink, "object.txt")).is_some() {
157 let target = client.read_link(&symlink)?;
158 println!("symlink target: {target}");
159 }
160
161 let hard_link = remote_path(work_dir, "object.hardlink");
162 if optional("hard_link", client.hard_link(object, &hard_link)).is_some() {
163 println!("created hard link: {hard_link}");
164 }
165
166 Ok(())
167}Sourcepub fn hard_link(&mut self, existing: &str, link: &str) -> Result<()>
pub fn hard_link(&mut self, existing: &str, link: &str) -> Result<()>
Creates a hard link.
Examples found in repository?
150fn demonstrate_optional_links(
151 client: &mut Client,
152 object: &str,
153 work_dir: &str,
154) -> nfs::Result<()> {
155 let symlink = remote_path(work_dir, "object.symlink");
156 if optional("symlink", client.symlink(&symlink, "object.txt")).is_some() {
157 let target = client.read_link(&symlink)?;
158 println!("symlink target: {target}");
159 }
160
161 let hard_link = remote_path(work_dir, "object.hardlink");
162 if optional("hard_link", client.hard_link(object, &hard_link)).is_some() {
163 println!("created hard link: {hard_link}");
164 }
165
166 Ok(())
167}Sourcepub fn remove_if_exists(&mut self, path: &str) -> Result<bool>
pub fn remove_if_exists(&mut self, path: &str) -> Result<bool>
Removes a non-directory entry if it exists.
Examples found in repository?
11fn main() -> nfs::Result<()> {
12 // Usage:
13 // cargo run --example basic -- 127.0.0.1:/export /writable-dir
14 //
15 // The first argument is an NFSv3 target in `host:/export` form.
16 // The second argument is a writable directory inside that export.
17 let mut args = std::env::args().skip(1);
18 let target = args
19 .next()
20 .unwrap_or_else(|| "127.0.0.1:/export".to_owned());
21 let dir = args.next().unwrap_or_else(|| "/".to_owned());
22 let file = remote_path(&dir, &format!("nfs-rs-v3-{}.txt", std::process::id()));
23
24 let mut client = ClientBuilder::from_target(&target)?
25 .timeout(Some(Duration::from_secs(10)))
26 .connect()?;
27
28 println!("connected to NFSv3 target {target}");
29 println!("writing {file}");
30 client.write_atomic(&file, CONTENT)?;
31
32 let data = client.read(&file)?;
33 println!("read: {}", String::from_utf8_lossy(&data));
34
35 let range = client.read_range(&file, 0, 5)?;
36 println!("first 5 bytes: {:?}", String::from_utf8_lossy(&range));
37
38 let metadata = client.metadata(&file)?;
39 println!(
40 "metadata: type={:?} size={} mode={:o}",
41 metadata.file_type,
42 metadata.size,
43 metadata.mode & 0o777
44 );
45
46 println!("first entries in {dir}:");
47 for entry in client.read_dir(&dir)?.into_iter().take(8) {
48 println!(" {}", entry.name);
49 }
50
51 client.remove_if_exists(&file)?;
52 println!("removed {file}");
53 Ok(())
54}Sourcepub fn rmdir_if_exists(&mut self, path: &str) -> Result<bool>
pub fn rmdir_if_exists(&mut self, path: &str) -> Result<bool>
Removes an empty directory if it exists.
Sourcepub fn remove_all(&mut self, path: &str) -> Result<()>
pub fn remove_all(&mut self, path: &str) -> Result<()>
Recursively removes a file tree.
The export root itself cannot be removed through this method.
Sourcepub fn remove_all_if_exists(&mut self, path: &str) -> Result<bool>
pub fn remove_all_if_exists(&mut self, path: &str) -> Result<bool>
Recursively removes a file tree if it exists.
Examples found in repository?
25fn main() -> nfs::Result<()> {
26 let config = Config::from_env();
27 let mut client = connect(&config.target)?;
28
29 println!("connected to NFSv3 target {}", config.target);
30 if let Some(info) = client.fsinfo() {
31 println!(
32 "server fsinfo: read_preferred={} write_preferred={} dir_preferred={}",
33 info.read_preferred, info.write_preferred, info.dir_preferred
34 );
35 }
36
37 let work_dir = remote_path(
38 &config.remote_dir,
39 &format!("nfs-rs-v3-cookbook-{}", std::process::id()),
40 );
41 client.remove_all_if_exists(&work_dir)?;
42 client.create_dir_all(&work_dir, 0o755)?;
43
44 let flow_result = run_filesystem_flow(&mut client, &work_dir);
45 let cleanup_result = client.remove_all_if_exists(&work_dir);
46 let unmount_result = client.unmount();
47 finish(flow_result, cleanup_result, unmount_result)
48}Sourcepub fn rename(&mut self, from: &str, to: &str) -> Result<()>
pub fn rename(&mut self, from: &str, to: &str) -> Result<()>
Renames or moves a path.
Examples found in repository?
65fn run_filesystem_flow(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
66 let object = remote_path(work_dir, "object.txt");
67 let streamed = remote_path(work_dir, "streamed.txt");
68 let created = remote_path(work_dir, "created.txt");
69 let copied = remote_path(work_dir, "copied.txt");
70 let renamed = remote_path(work_dir, "renamed.txt");
71 let nested_dir = remote_path(work_dir, "nested/a/b");
72 let nested_file = remote_path(&nested_dir, "payload.bin");
73
74 println!("workspace: {work_dir}");
75
76 client.write_atomic_with_mode_and_stability(&object, OBJECT, 0o640, StableHow::FileSync)?;
77 print_v3_metadata("object after atomic write", &client.metadata(&object)?);
78
79 let exists = client.exists(&object)?;
80 println!("exists({object}) = {exists}");
81
82 let access = client.access(
83 &object,
84 ACCESS3_READ | ACCESS3_LOOKUP | ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE,
85 )?;
86 println!("access mask granted by server: 0x{:x}", access.access);
87
88 let first_five = client.read_exact_at(&object, 0, 5)?;
89 println!(
90 "first five bytes: {:?}",
91 String::from_utf8_lossy(&first_five)
92 );
93
94 let middle = client.read_range(&object, 7, 14)?;
95 println!("range read: {:?}", String::from_utf8_lossy(&middle));
96
97 let mut downloaded = Vec::new();
98 let downloaded_len = client.read_to_writer(&object, &mut downloaded)?;
99 println!(
100 "streamed object into local Vec: {downloaded_len} bytes, {}",
101 String::from_utf8_lossy(&downloaded)
102 );
103
104 let mut upload = Cursor::new(STREAMED);
105 let uploaded_len = client.write_atomic_from_reader_with_mode_and_stability(
106 &streamed,
107 &mut upload,
108 0o644,
109 StableHow::FileSync,
110 )?;
111 println!("streamed upload wrote {uploaded_len} bytes");
112
113 client.append_with_stability(&streamed, b"appended\n", StableHow::FileSync)?;
114 client.write_at_with_stability(&streamed, 0, b"STREAMED", StableHow::FileSync)?;
115 client.truncate(&streamed, 24)?;
116 let commit = client.commit(&streamed, 0, 0)?;
117 println!("commit verifier: {:02x?}", commit.verifier);
118
119 client.create_new(&created, 0o600)?;
120 client.write_at_with_stability(
121 &created,
122 0,
123 b"created with create_new\n",
124 StableHow::FileSync,
125 )?;
126 let _ = optional(
127 "create_new existing file",
128 client.create_new(&created, 0o600),
129 );
130
131 let copied_len = client.copy_atomic_with_stability(&streamed, &copied, StableHow::FileSync)?;
132 println!("copied {copied_len} bytes from {streamed} to {copied}");
133
134 client.rename(&copied, &renamed)?;
135 let _ = optional("touch", client.touch(&renamed));
136 let _ = optional("set_mode", client.set_mode(&renamed, 0o644));
137
138 client.create_dir_all(&nested_dir, 0o755)?;
139 client.write_atomic(&nested_file, b"nested file\n")?;
140
141 demonstrate_optional_links(client, &object, work_dir)?;
142 demonstrate_directory_reads(client, work_dir)?;
143 demonstrate_filesystem_queries(client, work_dir)?;
144 demonstrate_error_handling(client, work_dir);
145 demonstrate_reconnect(client, work_dir)?;
146
147 Ok(())
148}Sourcepub fn read_dir(&mut self, path: &str) -> Result<Vec<DirEntry>>
pub fn read_dir(&mut self, path: &str) -> Result<Vec<DirEntry>>
Reads all entries in a directory, subject to the client’s entry limit.
Examples found in repository?
11fn main() -> nfs::Result<()> {
12 // Usage:
13 // cargo run --example basic -- 127.0.0.1:/export /writable-dir
14 //
15 // The first argument is an NFSv3 target in `host:/export` form.
16 // The second argument is a writable directory inside that export.
17 let mut args = std::env::args().skip(1);
18 let target = args
19 .next()
20 .unwrap_or_else(|| "127.0.0.1:/export".to_owned());
21 let dir = args.next().unwrap_or_else(|| "/".to_owned());
22 let file = remote_path(&dir, &format!("nfs-rs-v3-{}.txt", std::process::id()));
23
24 let mut client = ClientBuilder::from_target(&target)?
25 .timeout(Some(Duration::from_secs(10)))
26 .connect()?;
27
28 println!("connected to NFSv3 target {target}");
29 println!("writing {file}");
30 client.write_atomic(&file, CONTENT)?;
31
32 let data = client.read(&file)?;
33 println!("read: {}", String::from_utf8_lossy(&data));
34
35 let range = client.read_range(&file, 0, 5)?;
36 println!("first 5 bytes: {:?}", String::from_utf8_lossy(&range));
37
38 let metadata = client.metadata(&file)?;
39 println!(
40 "metadata: type={:?} size={} mode={:o}",
41 metadata.file_type,
42 metadata.size,
43 metadata.mode & 0o777
44 );
45
46 println!("first entries in {dir}:");
47 for entry in client.read_dir(&dir)?.into_iter().take(8) {
48 println!(" {}", entry.name);
49 }
50
51 client.remove_if_exists(&file)?;
52 println!("removed {file}");
53 Ok(())
54}Sourcepub fn read_dir_limited(
&mut self,
path: &str,
max_entries: usize,
) -> Result<Vec<DirEntry>>
pub fn read_dir_limited( &mut self, path: &str, max_entries: usize, ) -> Result<Vec<DirEntry>>
Reads all entries in a directory with a per-call entry limit.
Examples found in repository?
169fn demonstrate_directory_reads(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
170 println!("limited directory listing:");
171 for entry in client.read_dir_limited(work_dir, 16)? {
172 let kind = entry
173 .attributes
174 .as_ref()
175 .map(|attrs| format!("{:?}", attrs.file_type))
176 .unwrap_or_else(|| "unknown".to_owned());
177 println!(" {} fileid={} type={kind}", entry.name, entry.fileid);
178 }
179
180 println!("paged directory listing:");
181 let mut cursor: Option<DirPageCursor> = None;
182 loop {
183 let page = client.read_dir_page_limited(work_dir, cursor, 4)?;
184 for entry in &page.entries {
185 println!(" page entry: {}", entry.name);
186 }
187 if page.is_eof() {
188 break;
189 }
190 cursor = page.next_cursor;
191 }
192
193 Ok(())
194}Sourcepub fn read_dir_page(
&mut self,
path: &str,
cursor: Option<DirPageCursor>,
) -> Result<DirPage>
pub fn read_dir_page( &mut self, path: &str, cursor: Option<DirPageCursor>, ) -> Result<DirPage>
Reads one page of directory entries.
Sourcepub fn read_dir_page_limited(
&mut self,
path: &str,
cursor: Option<DirPageCursor>,
max_entries: usize,
) -> Result<DirPage>
pub fn read_dir_page_limited( &mut self, path: &str, cursor: Option<DirPageCursor>, max_entries: usize, ) -> Result<DirPage>
Reads one page of directory entries with a per-page entry limit.
Examples found in repository?
169fn demonstrate_directory_reads(client: &mut Client, work_dir: &str) -> nfs::Result<()> {
170 println!("limited directory listing:");
171 for entry in client.read_dir_limited(work_dir, 16)? {
172 let kind = entry
173 .attributes
174 .as_ref()
175 .map(|attrs| format!("{:?}", attrs.file_type))
176 .unwrap_or_else(|| "unknown".to_owned());
177 println!(" {} fileid={} type={kind}", entry.name, entry.fileid);
178 }
179
180 println!("paged directory listing:");
181 let mut cursor: Option<DirPageCursor> = None;
182 loop {
183 let page = client.read_dir_page_limited(work_dir, cursor, 4)?;
184 for entry in &page.entries {
185 println!(" page entry: {}", entry.name);
186 }
187 if page.is_eof() {
188 break;
189 }
190 cursor = page.next_cursor;
191 }
192
193 Ok(())
194}Sourcepub fn unmount(self) -> Result<()>
pub fn unmount(self) -> Result<()>
Sends an NFSv3 unmount request for the export.
Examples found in repository?
25fn main() -> nfs::Result<()> {
26 let config = Config::from_env();
27 let mut client = connect(&config.target)?;
28
29 println!("connected to NFSv3 target {}", config.target);
30 if let Some(info) = client.fsinfo() {
31 println!(
32 "server fsinfo: read_preferred={} write_preferred={} dir_preferred={}",
33 info.read_preferred, info.write_preferred, info.dir_preferred
34 );
35 }
36
37 let work_dir = remote_path(
38 &config.remote_dir,
39 &format!("nfs-rs-v3-cookbook-{}", std::process::id()),
40 );
41 client.remove_all_if_exists(&work_dir)?;
42 client.create_dir_all(&work_dir, 0o755)?;
43
44 let flow_result = run_filesystem_flow(&mut client, &work_dir);
45 let cleanup_result = client.remove_all_if_exists(&work_dir);
46 let unmount_result = client.unmount();
47 finish(flow_result, cleanup_result, unmount_result)
48}