### Install and Run NFSv3 Server CLI Source: https://context7.com/vaiz/nfs3/llms.txt Installs the `cargo-nfs3-server` command-line tool and demonstrates how to start an NFSv3 server serving a local directory, in read-only mode, using an in-memory filesystem, or with custom logging. It also includes examples for mounting the server on Linux, macOS, and Windows. ```bash # Install the tool cargo install cargo-nfs3-server # Serve a local directory (read-write) cargo-nfs3-server --path ./shared --bind-ip 0.0.0.0 --bind-port 11111 # Serve a directory in read-only mode cargo-nfs3-server --path ./documents --bind-ip 0.0.0.0 --bind-port 11111 --readonly # Use an in-memory filesystem cargo-nfs3-server --memfs --bind-port 11111 # With logging configuration cargo-nfs3-server --path ./data --log-level debug --log-file /var/log/nfs3.log # Mount the server (Linux) mkdir /mnt/nfs sudo mount.nfs -o user,noacl,nolock,vers=3,tcp,wsize=1048576,rsize=131072,port=11111,mountport=11111 localhost:/ /mnt/nfs # Mount on macOS mkdir ~/nfs_mount mount_nfs -o nolocks,vers=3,tcp,rsize=131072,port=11111,mountport=11111 localhost:/ ~/nfs_mount # Mount on Windows (Pro edition) mount.exe -o anon,nolock,mtype=soft,fileaccess=6,casesensitive \\127.0.0.1\ X: ``` -------------------------------- ### NFSv3 Server CLI Tool Usage Source: https://context7.com/vaiz/nfs3/llms.txt Instructions and examples for installing and using the `cargo-nfs3-server` command-line tool to deploy an NFSv3 server. ```APIDOC ## NFSv3 Server CLI Tool Usage This section details how to install and utilize the `cargo-nfs3-server` command-line tool for deploying an NFSv3 server. ### Installation ```bash cargo install cargo-nfs3-server ``` ### Server Deployment Examples **Serve a local directory (read-write):** ```bash cargo-nfs3-server --path ./shared --bind-ip 0.0.0.0 --bind-port 11111 ``` **Serve a directory in read-only mode:** ```bash cargo-nfs3-server --path ./documents --bind-ip 0.0.0.0 --bind-port 11111 --readonly ``` **Use an in-memory filesystem:** ```bash cargo-nfs3-server --memfs --bind-port 11111 ``` **With logging configuration:** ```bash cargo-nfs3-server --path ./data --log-level debug --log-file /var/log/nfs3.log ``` ### Mounting the Server **Mount on Linux:** ```bash mkdir /mnt/nfs sudo mount.nfs -o user,noacl,nolock,vers=3,tcp,wsize=1048576,rsize=131072,port=11111,mountport=11111 localhost:/ /mnt/nfs ``` **Mount on macOS:** ```bash mkdir ~/nfs_mount mount_nfs -o nolocks,vers=3,tcp,rsize=131072,port=11111,mountport=11111 localhost:/ ~/nfs_mount ``` **Mount on Windows (Pro edition):** ```bash mount.exe -o anon,nolock,mtype=soft,fileaccess=6,casesensitive \\127.0.0.1\\ X: ``` ``` -------------------------------- ### Run cargo-nfs3-server with specified path, IP, and port Source: https://github.com/vaiz/nfs3/blob/main/crates/cargo_nfs3_server/README.md Starts the NFSv3 server, serving files from the specified directory on the given IP address and port. This is a basic usage example. ```bash cargo-nfs3-server --path ./shared --bind-ip 0.0.0.0 --bind-port 11111 ``` -------------------------------- ### Run MemFs Example (Rust) Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_server/README.md Command to run the in-memory filesystem (MemFs) example for the NFSv3 server. It uses Cargo to build and execute the example with the 'memfs' feature enabled. ```bash cargo run --example memfs --features memfs ``` -------------------------------- ### Install cargo-nfs3-server using Cargo Source: https://github.com/vaiz/nfs3/blob/main/crates/cargo_nfs3_server/README.md Installs the cargo-nfs3-server binary using the Rust package manager, Cargo. Ensure you have Rust and Cargo installed before running this command. ```bash cargo install cargo-nfs3-server ``` -------------------------------- ### Implement NFSv3 Server with In-Memory Filesystem in Rust Source: https://context7.com/vaiz/nfs3/llms.txt This Rust code demonstrates how to create a custom NFSv3 server using an in-memory filesystem. It leverages the `nfs3-server` crate and Tokio for asynchronous operations. The example initializes a `MemFs` with predefined files and directories, then starts a TCP listener to handle NFS requests. It prints instructions on how to mount the server. ```rust use nfs3_server::tcp::{NFSTcp, NFSTcpListener}; use nfs3_server::memfs::{MemFs, MemFsConfig}; #[tokio::main] async fn main() -> anyhow::Result<()> { // Configure logging tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .init(); // Create in-memory filesystem with initial content let mut config = MemFsConfig::default(); config.add_file("/readme.txt", b"Welcome to NFSv3 server!\n"); config.add_file("/data.json", b"{\"status\": \"active\"}\n"); config.add_dir("/documents"); config.add_file("/documents/file1.txt", b"First document\n"); config.add_file("/documents/file2.txt", b"Second document\n"); for i in 0..10 { config.add_file( &format!("/documents/log_{:03}.txt", i), format!("Log entry {}\n", i).as_bytes() ); } let memfs = MemFs::new(config).expect("Failed to create memfs"); // Start the server let listener = NFSTcpListener::bind("0.0.0.0:11111", memfs).await?; println!("NFSv3 server listening on 0.0.0.0:11111"); println!("Mount with: sudo mount.nfs -o nolock,vers=3,tcp,port=11111,mountport=11111 localhost:/ /mnt/nfs"); listener.handle_forever().await?; Ok(()) } ``` -------------------------------- ### Run cargo-nfs3-server with in-memory filesystem Source: https://github.com/vaiz/nfs3/blob/main/crates/cargo_nfs3_server/README.md Starts the NFSv3 server using an in-memory filesystem for temporary storage. This is useful for quick, volatile file sharing. ```bash cargo-nfs3-server --memfs --bind-ip 0.0.0.0 --bind-port 11111 ``` -------------------------------- ### Run cargo-nfs3-server with custom logging Source: https://github.com/vaiz/nfs3/blob/main/crates/cargo_nfs3_server/README.md Starts the NFSv3 server with custom logging configurations, including log level and output file. The --quiet option can disable console logging. ```bash cargo-nfs3-server --path ./shared --log-level debug --log-file server.log --quiet ``` -------------------------------- ### Use NFSv3 Client with Smol Runtime Source: https://context7.com/vaiz/nfs3/llms.txt This Rust code snippet demonstrates how to use the `nfs3-client` crate with the Smol asynchronous runtime. It establishes an NFSv3 connection, performs a null operation, checks file access permissions using the `access` method, and retrieves filesystem statistics with `fsstat`. The example utilizes `SmolConnector` for the Smol runtime and `Nfs3ConnectionBuilder` to configure and establish the connection. It also includes error handling for NFS operations. ```rust use nfs3_client::smol::SmolConnector; use nfs3_client::Nfs3ConnectionBuilder; use nfs3_client::nfs3_types::nfs3; fn main() -> Result<(), Box> { smol::block_on(async { let mut connection = Nfs3ConnectionBuilder::new(SmolConnector, "127.0.0.1", "/") .mount() .await?; let root = connection.root_nfs_fh3(); // Perform null operation (heartbeat) connection.null().await?; // Check file access permissions let access = connection .access(&nfs3::ACCESS3args { object: root.clone(), access: nfs3::ACCESS3_READ | nfs3::ACCESS3_LOOKUP | nfs3::ACCESS3_EXECUTE, }) .await?; match access { nfs3::ACCESS3res::Ok(ok) => { println!("Access rights: {}", ok.access); } nfs3::ACCESS3res::Err((err, _)) => { eprintln!("Access check failed: {:?}", err); } } // Get filesystem statistics let fsstat = connection .fsstat(&nfs3::FSSTAT3args { fsroot: root.clone(), }) .await?; match fsstat { nfs3::FSSTAT3res::Ok(ok) => { println!("Total bytes: {}", ok.tbytes); println!("Free bytes: {}", ok.fbytes); println!("Available bytes: {}", ok.abytes); } nfs3::FSSTAT3res::Err((err, _)) => { eprintln!("Fsstat failed: {:?}", err); } } connection.unmount().await?; Ok(()) }) } ``` -------------------------------- ### NFSv3 Client with Tokio Runtime Source: https://context7.com/vaiz/nfs3/llms.txt Demonstrates how to use the `nfs3_client` with the Tokio runtime to connect to an NFSv3 server and perform operations like getting filesystem information and listing directory contents. ```APIDOC ## Connecting to NFSv3 Server with Tokio Runtime This section illustrates how to establish a connection to an NFSv3 server and perform basic operations using the `nfs3_client` library with the Tokio asynchronous runtime. ### Usage Example ```rust use nfs3_client::tokio::TokioConnector; use nfs3_client::Nfs3ConnectionBuilder; use nfs3_client::nfs3_types::nfs3; use nfs3_client::nfs3_types::rpc::{auth_unix, opaque_auth}; use nfs3_client::nfs3_types::xdr_codec::Opaque; #[tokio::main] async fn main() -> Result<(), Box> { // Configure authentication (optional, defaults to anonymous) let auth_unix = auth_unix { stamp: 0xaaaaaaaa, machinename: Opaque::borrowed(b"client-machine"), uid: 0xfffffffe, gid: 0xfffffffe, gids: vec![], }; let credential = opaque_auth::auth_unix(&auth_unix); // Connect and mount let mut connection = Nfs3ConnectionBuilder::new(TokioConnector, "127.0.0.1", "/") .portmapper_port(111) .credential(credential) .mount() .await?; let root = connection.root_nfs_fh3(); // Get filesystem info let fsinfo = connection .fsinfo(&nfs3::FSINFO3args { fsroot: root.clone(), }) .await?; match fsinfo { nfs3::FSINFO3res::Ok(ok) => { println!("Max file size: {}", ok.maxfilesize); println!("Read size: {}", ok.rtmax); } nfs3::FSINFO3res::Err((err, _)) => { eprintln!("Error: {:?}", err); } } // List directory contents let readdir = connection .readdir(&nfs3::READDIR3args { dir: root, cookie: 0, cookieverf: nfs3::cookieverf3::default(), count: 128 * 1024 * 1024, }) .await?; match readdir { nfs3::READDIR3res::Ok(ok) => { for entry in ok.reply.entries.0 { println!("{}", String::from_utf8_lossy(entry.name.0.as_ref())); } } nfs3::READDIR3res::Err((err, _)) => { eprintln!("Error: {:?}", err); } } connection.unmount().await?; Ok(()) } ``` ### Description This example demonstrates connecting to an NFSv3 server using the `nfs3_client` with the Tokio runtime. It includes steps for configuring optional authentication, establishing a connection, mounting the root directory, retrieving filesystem information (like max file size and read size), and listing the contents of the root directory. Finally, it unmounts the connection. ### Method N/A (This is a client-side code example, not a direct API endpoint call). ### Endpoint N/A ### Parameters N/A ### Request Example N/A ### Response N/A (This is a client-side code example, output is printed to the console.) ``` -------------------------------- ### Run cargo-nfs3-server in read-only mode Source: https://github.com/vaiz/nfs3/blob/main/crates/cargo_nfs3_server/README.md Starts the NFSv3 server serving files from a specified directory in read-only mode. This enhances data safety by preventing modifications. ```bash cargo-nfs3-server --path ./shared --bind-ip 0.0.0.0 --bind-port 11111 --readonly ``` -------------------------------- ### Rust NFSv3 Read-Only Filesystem Implementation Source: https://context7.com/vaiz/nfs3/llms.txt This Rust code implements a custom read-only NFSv3 filesystem. It defines a `SimpleReadOnlyFS` struct and implements the `NfsReadFileSystem` trait to handle NFS requests. The `main` function sets up a simple file structure and starts an NFS TCP listener. ```rust use std::collections::HashMap; use nfs3_server::tcp::NFSTcpListener; use nfs3_server::vfs::{ NfsReadFileSystem, FileHandleU64, ReadDirPlusIterator, DirEntryPlus, NextResult }; use nfs3_server::nfs3_types::nfs3::{ filename3, fattr3, nfspath3, nfsstat3, ftype3, fileid3, cookie3 }; struct SimpleReadOnlyFS { files: HashMap, } struct FileEntry { id: u64, parent_id: u64, name: String, content: Vec, is_dir: bool, } impl NfsReadFileSystem for SimpleReadOnlyFS { type Handle = FileHandleU64; fn root_dir(&self) -> Self::Handle { FileHandleU64::new(1) } async fn lookup( &self, dirid: &Self::Handle, filename: &filename3<'_>, ) -> Result { let dir_id = dirid.as_u64(); let name = String::from_utf8_lossy(filename.as_ref()); for entry in self.files.values() { if entry.parent_id == dir_id && entry.name == name { return Ok(FileHandleU64::new(entry.id)); } } Err(nfsstat3::NFS3ERR_NOENT) } async fn getattr(&self, id: &Self::Handle) -> Result { let entry = self.files.get(&id.as_u64()) .ok_or(nfsstat3::NFS3ERR_NOENT)?; Ok(fattr3 { type_: if entry.is_dir { ftype3::NF3DIR } else { ftype3::NF3REG }, mode: if entry.is_dir { 0o755 } else { 0o644 }, nlink: 1, uid: 1000, gid: 1000, size: entry.content.len() as u64, used: entry.content.len() as u64, rdev: Default::default(), fsid: 1, fileid: entry.id, atime: Default::default(), mtime: Default::default(), ctime: Default::default(), }) } async fn read( &self, id: &Self::Handle, offset: u64, count: u32, ) -> Result<(Vec, bool), nfsstat3> { let entry = self.files.get(&id.as_u64()) .ok_or(nfsstat3::NFS3ERR_NOENT)?; let start = offset.min(entry.content.len() as u64) as usize; let end = (offset + count as u64).min(entry.content.len() as u64) as usize; let data = entry.content[start..end].to_vec(); let eof = end >= entry.content.len(); Ok((data, eof)) } async fn readdirplus( &self, dirid: &Self::Handle, start_after: cookie3, ) -> Result, nfsstat3> { let dir_id = dirid.as_u64(); let mut entries: Vec<_> = self.files.values() .filter(|e| e.parent_id == dir_id && e.id > start_after) .collect(); entries.sort_by_key(|e| e.id); Ok(SimpleIterator { entries: entries.into_iter().map(|e| e.id).collect(), index: 0, fs: self }) } async fn readlink(&self, _id: &Self::Handle) -> Result, nfsstat3> { Err(nfsstat3::NFS3ERR_NOTSUPP) } } struct SimpleIterator<'a> { entries: Vec, index: usize, fs: &'a SimpleReadOnlyFS, } impl ReadDirPlusIterator for SimpleIterator<'_> { async fn next(&mut self) -> NextResult> { if self.index >= self.entries.len() { return NextResult::Eof; } let id = self.entries[self.index]; self.index += 1; let entry = self.fs.files.get(&id).unwrap(); let attr = self.fs.getattr(&FileHandleU64::new(id)).await.ok(); NextResult::Ok(DirEntryPlus { fileid: id, name: filename3::from(entry.name.as_bytes().to_vec()), cookie: id, name_attributes: attr, name_handle: Some(FileHandleU64::new(id)), }) } } #[tokio::main] async fn main() -> anyhow::Result<()> { let mut files = HashMap::new(); files.insert(1, FileEntry { id: 1, parent_id: 0, name: "/".into(), content: vec![], is_dir: true }); files.insert(2, FileEntry { id: 2, parent_id: 1, name: "hello.txt".into(), content: b"Hello World!".to_vec(), is_dir: false }); let fs = SimpleReadOnlyFS { files }; let listener = NFSTcpListener::bind("0.0.0.0:11111", fs).await?; listener.handle_forever().await?; Ok(()) } ``` -------------------------------- ### Connect and Read Directory with Smol Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_client/README.md Shows how to connect to an NFSv3 server using the Smol runtime, execute a readdir operation, and unmount. Requires the 'smol' feature to be enabled. ```rust use nfs3_client::smol::SmolConnector; use nfs3_client::Nfs3ConnectionBuilder; use nfs3_client::nfs3_types::nfs3; fn main() -> Result<(), Box> { smol::block_on(async { let mut connection = Nfs3ConnectionBuilder::new(SmolConnector, "127.0.0.1", "/") .mount() .await?; let root = connection.root_nfs_fh3(); println!("Calling readdir"); let readdir = connection .readdir(&nfs3::READDIR3args { dir: root.clone(), cookie: 0, cookieverf: nfs3::cookieverf3::default(), count: 128 * 1024 * 1024, }) .await?; println!("{readdir:?}"); connection.unmount().await?; Ok(()) }) } ``` -------------------------------- ### Connect and Read Directory with Tokio Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_client/README.md Demonstrates connecting to an NFSv3 server using the Tokio runtime, performing a readdir operation, and unmounting. Requires the 'tokio' feature to be enabled. ```rust use nfs3_client::tokio::TokioConnector; use nfs3_client::Nfs3ConnectionBuilder; use nfs3_types::nfs3; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), Box> { let mut connection = Nfs3ConnectionBuilder::new(TokioConnector, "127.0.0.1", "/") .mount() .await?; let root = connection.root_nfs_fh3(); println!("Calling readdir"); let readdir = connection .readdir(&nfs3::READDIR3args { dir: root, cookie: 0, cookieverf: nfs3::cookieverf3::default(), count: 128 * 1024 * 1024, }) .await?; println!("{readdir:?}"); connection.unmount().await?; Ok(()) } ``` -------------------------------- ### NFSv3 Client with Tokio Runtime Source: https://context7.com/vaiz/nfs3/llms.txt Demonstrates connecting to an NFSv3 server using the `nfs3_client` with the Tokio runtime. It shows how to configure authentication, mount the server, retrieve filesystem information, list directory contents, and unmount the connection. Requires the `nfs3_client` and `tokio` crates. ```rust use nfs3_client::tokio::TokioConnector; use nfs3_client::Nfs3ConnectionBuilder; use nfs3_client::nfs3_types::nfs3; use nfs3_client::nfs3_types::rpc::{auth_unix, opaque_auth}; use nfs3_client::nfs3_types::xdr_codec::Opaque; #[tokio::main] async fn main() -> Result<(), Box> { // Configure authentication (optional, defaults to anonymous) let auth_unix = auth_unix { stamp: 0xaaaaaaaa, machinename: Opaque::borrowed(b"client-machine"), uid: 0xfffffffe, gid: 0xfffffffe, gids: vec![], }; let credential = opaque_auth::auth_unix(&auth_unix); // Connect and mount let mut connection = Nfs3ConnectionBuilder::new(TokioConnector, "127.0.0.1", "/") .portmapper_port(111) .credential(credential) .mount() .await?; let root = connection.root_nfs_fh3(); // Get filesystem info let fsinfo = connection .fsinfo(&nfs3::FSINFO3args { fsroot: root.clone(), }) .await?; match fsinfo { nfs3::FSINFO3res::Ok(ok) => { println!("Max file size: {}", ok.maxfilesize); println!("Read size: {}", ok.rtmax); } nfs3::FSINFO3res::Err((err, _)) => { eprintln!("Error: {:?}", err); } } // List directory contents let readdir = connection .readdir(&nfs3::READDIR3args { dir: root, cookie: 0, cookieverf: nfs3::cookieverf3::default(), count: 128 * 1024 * 1024, }) .await?; match readdir { nfs3::READDIR3res::Ok(ok) => { for entry in ok.reply.entries.0 { println!("{}", String::from_utf8_lossy(entry.name.0.as_ref())); } } nfs3::READDIR3res::Err((err, _)) => { eprintln!("Error: {:?}", err); } } connection.unmount().await?; Ok(()) } ``` -------------------------------- ### NFSv3 MOUNT Protocol for Root Directory Access Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_server/README.md Explains the role of the MOUNT protocol in NFSv3, specifically how clients obtain the initial handle for a file system's root directory. This is typically done via an MNT operation on the exported path (e.g., '/'). ```pseudo-code MNT(export_path) // export_path: The path of the exported file system (e.g., '/'). // Returns: The NFS handle (nfs_fh3) for the root directory of the export. // This operation is stateless in the described implementation. ``` -------------------------------- ### Mount NFSv3 Server (Windows) Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_server/README.md Command to mount an NFSv3 server on Windows (Pro version required). It uses `mount.exe` with options tailored for Windows NFS client behavior. ```bash mount.exe -o anon,nolock,mtype=soft,fileaccess=6,casesensitive,lang=ansi,rsize=128,wsize=128,timeout=60,retry=2 \\127.0.0.1\ X: ``` -------------------------------- ### Implement Writable NFSv3 Mirror Filesystem with Tokio Source: https://context7.com/vaiz/nfs3/llms.txt This Rust code demonstrates how to implement a writable NFSv3 filesystem that mirrors a local directory. It supports both read-write and read-only modes by optionally wrapping the custom `MirrorFs` implementation in a `ReadOnlyAdapter`. The `MirrorFs` struct itself implements the `NfsFileSystem` trait for writable operations like `write`, `create`, `remove`, `rename`, `mkdir`, and `symlink`. It relies on the `nfs3-server` crate and the Tokio runtime. ```rust use nfs3_server::tcp::NFSTcpListener; use nfs3_server::vfs::{NfsFileSystem, NfsReadFileSystem}; use nfs3_server::vfs::adapters::ReadOnlyAdapter; use std::path::PathBuf; // MirrorFs implementation would go here (see examples/mirrorfs.rs for full implementation) // This example shows how to use it with read-write or read-only modes #[tokio::main] async fn main() -> anyhow::Result<()> { let args: Vec = std::env::args().collect(); let path = args.get(1).expect("Provide directory path"); let readonly = args.get(2).map_or(false, |arg| arg == "--readonly"); // Create filesystem that mirrors a local directory let mirror_fs = MirrorFs::new(PathBuf::from(path)); if readonly { // Wrap in ReadOnlyAdapter to prevent modifications let ro_fs = ReadOnlyAdapter::new(mirror_fs); let listener = NFSTcpListener::bind("0.0.0.0:11111", ro_fs).await?; println!("Read-only NFSv3 server started"); listener.handle_forever().await?; } else { // Use as read-write filesystem let listener = NFSTcpListener::bind("0.0.0.0:11111", mirror_fs).await?; println!("Read-write NFSv3 server started"); listener.handle_forever().await?; } Ok(()) } // Key NfsFileSystem trait methods for writable operations: impl NfsFileSystem for MirrorFs { async fn write(&self, id: &Self::Handle, offset: u64, data: &[u8]) -> Result { // Write data to file at offset // Update file attributes and return todo!() } async fn create(&self, dirid: &Self::Handle, filename: &filename3<'_>, setattr: sattr3) -> Result<(Self::Handle, fattr3), nfsstat3> { // Create new file in directory // Return file handle and attributes todo!() } async fn remove(&self, dirid: &Self::Handle, filename: &filename3<'_>) -> Result<(), nfsstat3> { // Remove file from directory todo!() } async fn rename( &self, from_dirid: &Self::Handle, from_filename: &filename3<'_>, to_dirid: &Self::Handle, to_filename: &filename3<'_>, ) -> Result<(), nfsstat3> { // Rename/move file between directories todo!() } async fn mkdir(&self, dirid: &Self::Handle, dirname: &filename3<'_>) -> Result<(Self::Handle, fattr3), nfsstat3> { // Create directory todo!() } async fn symlink( &self, dirid: &Self::Handle, linkname: &filename3<'_>, symlink: &nfspath3<'_>, attr: &sattr3, ) -> Result<(Self::Handle, fattr3), nfsstat3> { // Create symbolic link todo!() } } ``` -------------------------------- ### Mount NFSv3 Server (macOS) Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_server/README.md Command to mount an NFSv3 server on macOS. It uses the native `mount_nfs` command with specific options suitable for macOS. ```bash mkdir demo sudo mount_nfs -o nolocks,vers=3,tcp,rsize=131072,actimeo=120,port=11111,mountport=11111 localhost:/ demo ``` -------------------------------- ### Mount NFSv3 Server (Linux) Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_server/README.md Command to mount an NFSv3 server on Linux. It requires root privileges and specifies various mount options for the NFS client. ```bash mkdir demo sudo mount.nfs -o user,noacl,nolock,vers=3,tcp,wsize=1048576,rsize=131072,actimeo=120,port=11111,mountport=11111 localhost:/ demo ``` -------------------------------- ### NFSv3 LOOKUP Method for Directory Traversal Source: https://github.com/vaiz/nfs3/blob/main/crates/nfs3_server/README.md Demonstrates the LOOKUP operation in NFSv3, used to obtain a file handle by querying a directory's handle with a filename. This is a core mechanism for navigating the file system and acquiring handles for specific files or subdirectories. ```pseudo-code LOOKUP(directory_handle, filename) // directory_handle: The NFS handle of the parent directory. // filename: The name of the file or subdirectory within the directory. // Returns: The NFS handle (nfs_fh3) for the specified filename. // Example: LOOKUP(handle_for_dir '/', "a.txt") returns handle_for_a.txt ``` -------------------------------- ### NFSv3 File Read/Write with Rust Client Source: https://context7.com/vaiz/nfs3/llms.txt This snippet shows how to use the nfs3-client crate to connect to an NFSv3 server, lookup a file, read its content, and write new data to it. It requires a running NFSv3 server and the 'nfs3-client' and 'tokio' crates. The function takes no explicit arguments but interacts with the NFS server at '127.0.0.1:/'. It outputs file content and write status to the console. ```rust use nfs3_client::Nfs3ConnectionBuilder; use nfs3_client::tokio::TokioConnector; use nfs3_client::nfs3_types::nfs3::{self, filename3}; use nfs3_client::nfs3_types::xdr_codec::Opaque; #[tokio::main] async fn main() -> Result<(), Box> { let mut connection = Nfs3ConnectionBuilder::new(TokioConnector, "127.0.0.1", "/") .mount() .await?; let root = connection.root_nfs_fh3(); // Look up a file let lookup = connection .lookup(&nfs3::LOOKUP3args { what: nfs3::diropargs3 { dir: root.clone(), name: filename3(Opaque::borrowed(b"test.txt")), }, }) .await?; let file_handle = match lookup { nfs3::LOOKUP3res::Ok(ok) => ok.object, nfs3::LOOKUP3res::Err((err, _)) => { eprintln!("File not found: {:?}", err); return Ok(()); } }; // Read file contents let read = connection .read(&nfs3::READ3args { file: file_handle.clone(), offset: 0, count: 4096, }) .await?; match read { nfs3::READ3res::Ok(ok) => { let content = String::from_utf8_lossy(&ok.data.0); println!("File content: {}", content); println!("EOF: {}", ok.eof); } nfs3::READ3res::Err((err, _)) => { eprintln!("Read error: {:?}", err); } } // Write to file let data_to_write = b"Hello, NFSv3!"; let write = connection .write(&nfs3::WRITE3args { file: file_handle, offset: 0, count: data_to_write.len() as u32, stable: nfs3::stable_how::FILE_SYNC, data: Opaque::borrowed(data_to_write), }) .await?; match write { nfs3::WRITE3res::Ok(ok) => { println!("Wrote {} bytes", ok.count); } nfs3::WRITE3res::Err((err, _)) => { eprintln!("Write error: {:?}", err); } } connection.unmount().await?; Ok(()) } ``` -------------------------------- ### Recursively Download Folder with NFSv3 Client in Rust Source: https://context7.com/vaiz/nfs3/llms.txt This Rust code snippet demonstrates how to recursively download a remote directory structure from an NFSv3 server. It utilizes the `nfs3-client` crate and Tokio for asynchronous operations. The function iterates through directories, downloads files, and recreates the structure locally. It requires an active NFSv3 connection and a target local path. ```rust use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; use nfs3_client::Nfs3ConnectionBuilder; use nfs3_client::tokio::TokioConnector; use nfs3_client::io::{AsyncRead, AsyncWrite}; use nfs3_client::nfs3_types::nfs3::{self, Nfs3Option, filename3}; use nfs3_client::nfs3_types::xdr_codec::Opaque; #[tokio::main] async fn main() -> Result<(), Box> { let mut connection = Nfs3ConnectionBuilder::new(TokioConnector, "127.0.0.1", "/") .mount() .await?; let root = connection.root_nfs_fh3(); download_folder(&mut connection, root, "./local_copy").await?; connection.unmount().await?; Ok(()) } async fn download_folder( connection: &mut nfs3_client::Nfs3Connection, folder_fh: nfs3::nfs_fh3, local_path: &str, ) -> Result<(), Box> { fs::create_dir_all(local_path)?; let mut queue = vec![(PathBuf::from(local_path), folder_fh)]; while let Some((local_path, folder_fh)) = queue.pop() { let mut cookie = nfs3::cookie3::default(); let mut cookieverf = nfs3::cookieverf3::default(); loop { let readdirplus = connection .readdirplus(&nfs3::READDIRPLUS3args { dir: folder_fh.clone(), cookie, cookieverf, maxcount: 128 * 1024, dircount: 128 * 1024, }) .await?; // .unwrap(); // Removed unwrap to handle potential None responses gracefully // Safely handle the case where readdirplus might be None or have no entries let (entries, next_cookieverf) = match readdirplus { Some(reply) => { let entries = reply.reply.entries.into_inner(); (entries, reply.cookieverf) } None => { // If readdirplus returns None, break the inner loop. // This might indicate an issue with the server response or end of directory. break; } }; cookie = entries.last().map_or(nfs3::cookie3::default(), |e| e.cookie); cookieverf = next_cookieverf; for entry in entries { let name = String::from_utf8_lossy(&entry.name.0).into_owned(); if name == "." || name == ".." { continue; } let (fh, attrs) = if let (Nfs3Option::Some(fh), Nfs3Option::Some(attr)) = (entry.name_handle, entry.name_attributes) { (fh, attr) } else { continue; }; let local_entry_path = local_path.join(&name); if matches!(attrs.type_, nfs3::ftype3::NF3DIR) { fs::create_dir_all(&local_entry_path)?; queue.push((local_entry_path, fh)); } else { let mut file = File::create(&local_entry_path)?; let mut offset = 0; loop { let read = connection .read(&nfs3::READ3args { file: fh.clone(), offset, count: 128 * 1024, }) .await?; // .unwrap(); // Removed unwrap // Safely handle potential None responses from read let read_data = match read { Some(r) => r.data.0, None => { // If read returns None, break the inner file read loop. // This might indicate an issue or end of file. break; } }; file.write_all(&read_data)?; offset += read_data.len() as u64; if read.map_or(true, |r| r.eof) { // Check eof if read is Some, otherwise assume end break; } } } } if readdirplus.map_or(true, |r| r.reply.eof) { // Check eof if readdirplus is Some, otherwise assume end break; } } } Ok(()) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.