Skip to main content

Client

Struct Client 

Source
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

Source

pub fn connect(target: &str) -> Result<Self>

Connects to a target in host:/export form.

Source

pub fn builder( host: impl Into<String>, export: impl Into<String>, ) -> ClientBuilder

Creates a builder from host and export components.

Source

pub fn fsinfo(&self) -> Option<&FsInfo>

Returns filesystem information discovered at connect time, if available.

Examples found in repository?
examples/v3_cookbook.rs (line 30)
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}
Source

pub fn reconnect(&mut self) -> Result<()>

Reconnects using the original builder configuration.

Examples found in repository?
examples/v3_cookbook.rs (line 224)
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}
Source

pub fn fsstat(&mut self, path: &str) -> Result<FsStat>

Reads filesystem capacity information for a path.

Examples found in repository?
examples/v3_cookbook.rs (line 197)
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}
Source

pub fn pathconf(&mut self, path: &str) -> Result<PathConf>

Reads path configuration limits for a path.

Examples found in repository?
examples/v3_cookbook.rs (line 203)
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}
Source

pub fn metadata(&mut self, path: &str) -> Result<FileAttr>

Reads NFSv3 attributes for a path.

Examples found in repository?
examples/basic.rs (line 38)
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
Hide additional examples
examples/v3_cookbook.rs (line 77)
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}
Source

pub fn file_type(&mut self, path: &str) -> Result<FileType>

Returns the remote file type for a path.

Source

pub fn is_file(&mut self, path: &str) -> Result<bool>

Returns true when the path is a regular file.

Source

pub fn is_dir(&mut self, path: &str) -> Result<bool>

Returns true when the path is a directory.

Returns true when the path is a symbolic link.

Source

pub fn access(&mut self, path: &str, access: u32) -> Result<AccessResult>

Checks server-granted access bits for a path.

Examples found in repository?
examples/v3_cookbook.rs (lines 82-85)
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}
Source

pub fn lookup(&mut self, path: &str) -> Result<()>

Resolves a path and returns success if it exists.

Source

pub fn exists(&mut self, path: &str) -> Result<bool>

Returns whether a path exists.

Examples found in repository?
examples/v3_cookbook.rs (line 79)
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}
Source

pub fn read(&mut self, path: &str) -> Result<Vec<u8>>

Reads an entire file into memory.

Examples found in repository?
examples/v3_cookbook.rs (line 214)
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}
More examples
Hide additional examples
examples/basic.rs (line 32)
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}
Source

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?
examples/v3_cookbook.rs (line 98)
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}
Source

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.

Source

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?
examples/basic.rs (line 35)
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
Hide additional examples
examples/v3_cookbook.rs (line 94)
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}
Source

pub fn read_at( &mut self, path: &str, offset: u64, count: u32, ) -> Result<Vec<u8>>

Reads up to count bytes at offset.

Source

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?
examples/v3_cookbook.rs (line 88)
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}

Reads the target of a symbolic link.

Examples found in repository?
examples/v3_cookbook.rs (line 157)
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}
Source

pub fn write(&mut self, path: &str, data: &[u8]) -> Result<()>

Replaces or creates a file with data using file-sync stability.

Source

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.

Source

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.

Source

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.

Source

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?
examples/basic.rs (line 30)
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
Hide additional examples
examples/v3_cookbook.rs (line 139)
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}
Source

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.

Source

pub fn write_atomic_with_stability( &mut self, path: &str, data: &[u8], stable: StableHow, ) -> Result<()>

Atomic write with an explicit NFS write stability level.

Source

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?
examples/v3_cookbook.rs (line 76)
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}
Source

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.

Source

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.

Source

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.

Source

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?
examples/v3_cookbook.rs (lines 105-110)
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}
Source

pub fn append(&mut self, path: &str, data: &[u8]) -> Result<u64>

Appends bytes to an existing file and returns bytes written.

Source

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?
examples/v3_cookbook.rs (line 113)
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}
Source

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.

Source

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.

Source

pub fn truncate(&mut self, path: &str, size: u64) -> Result<()>

Truncates or extends a file to size bytes.

Examples found in repository?
examples/v3_cookbook.rs (line 115)
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}
Source

pub fn setattr(&mut self, path: &str, attr: &SetAttr) -> Result<()>

Applies NFSv3 attributes to a path.

Source

pub fn set_mode(&mut self, path: &str, mode: u32) -> Result<()>

Sets POSIX mode bits.

Examples found in repository?
examples/v3_cookbook.rs (line 136)
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}
Source

pub fn set_uid(&mut self, path: &str, uid: u32) -> Result<()>

Sets numeric uid.

Source

pub fn set_gid(&mut self, path: &str, gid: u32) -> Result<()>

Sets numeric gid.

Source

pub fn set_ownership(&mut self, path: &str, uid: u32, gid: u32) -> Result<()>

Sets numeric uid and gid.

Source

pub fn set_times( &mut self, path: &str, atime: Option<NfsTime>, mtime: Option<NfsTime>, ) -> Result<()>

Sets access and modification times.

Source

pub fn touch(&mut self, path: &str) -> Result<()>

Updates access and modification times to the server time.

Examples found in repository?
examples/v3_cookbook.rs (line 135)
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}
Source

pub fn write_at(&mut self, path: &str, offset: u64, data: &[u8]) -> Result<()>

Writes bytes at offset using file-sync stability.

Source

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?
examples/v3_cookbook.rs (line 114)
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}
Source

pub fn copy(&mut self, from: &str, to: &str) -> Result<u64>

Copies a file, replacing or creating the destination.

Source

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.

Source

pub fn copy_atomic(&mut self, from: &str, to: &str) -> Result<u64>

Copies through a temporary sibling and renames it into place.

Source

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?
examples/v3_cookbook.rs (line 131)
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}
Source

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?
examples/v3_cookbook.rs (line 116)
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}
Source

pub fn create(&mut self, path: &str, mode: u32) -> Result<()>

Creates a new file using guarded create semantics.

Source

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?
examples/v3_cookbook.rs (line 119)
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}
Source

pub fn create_unchecked(&mut self, path: &str, mode: u32) -> Result<()>

Creates or replaces a file using unchecked create semantics.

Source

pub fn mkdir(&mut self, path: &str, mode: u32) -> Result<()>

Creates a directory.

Source

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?
examples/v3_cookbook.rs (line 42)
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}

Creates a symbolic link at path pointing to target.

Examples found in repository?
examples/v3_cookbook.rs (line 156)
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}

Creates a hard link.

Examples found in repository?
examples/v3_cookbook.rs (line 162)
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}
Source

pub fn remove(&mut self, path: &str) -> Result<()>

Removes a non-directory entry.

Source

pub fn remove_if_exists(&mut self, path: &str) -> Result<bool>

Removes a non-directory entry if it exists.

Examples found in repository?
examples/basic.rs (line 51)
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}
Source

pub fn rmdir(&mut self, path: &str) -> Result<()>

Removes an empty directory.

Source

pub fn rmdir_if_exists(&mut self, path: &str) -> Result<bool>

Removes an empty directory if it exists.

Source

pub fn remove_all(&mut self, path: &str) -> Result<()>

Recursively removes a file tree.

The export root itself cannot be removed through this method.

Source

pub fn remove_all_if_exists(&mut self, path: &str) -> Result<bool>

Recursively removes a file tree if it exists.

Examples found in repository?
examples/v3_cookbook.rs (line 41)
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}
Source

pub fn rename(&mut self, from: &str, to: &str) -> Result<()>

Renames or moves a path.

Examples found in repository?
examples/v3_cookbook.rs (line 134)
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}
Source

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?
examples/basic.rs (line 47)
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}
Source

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?
examples/v3_cookbook.rs (line 171)
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}
Source

pub fn read_dir_page( &mut self, path: &str, cursor: Option<DirPageCursor>, ) -> Result<DirPage>

Reads one page of directory entries.

Source

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?
examples/v3_cookbook.rs (line 183)
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}
Source

pub fn unmount(self) -> Result<()>

Sends an NFSv3 unmount request for the export.

Examples found in repository?
examples/v3_cookbook.rs (line 46)
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}

Trait Implementations§

Source§

impl Debug for Client

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.