use std::io::{Read, Write};
use tracing::{debug, error};
use crate::protocol::rpc;
use crate::protocol::xdr::{self, deserialize, nfs3, Serialize};
pub async fn nfsproc3_read(
xid: u32,
input: &mut impl Read,
output: &mut impl Write,
context: &rpc::Context,
) -> Result<(), anyhow::Error> {
let args = deserialize::<nfs3::file::READ3args>(input)?;
debug!("nfsproc3_read({:?},{:?}) ", xid, args);
let id = context.vfs.fh_to_id(&args.file);
if let Err(stat) = id {
xdr::rpc::make_success_reply(xid).serialize(output)?;
stat.serialize(output)?;
nfs3::post_op_attr::None.serialize(output)?;
return Ok(());
}
let id = id.unwrap();
let max_read = context.vfs.fsinfo_rtmax().min(rpc::MAX_BLOCK_SIZE as u32);
let count = args.count.min(max_read);
let obj_attr = context.vfs.getattr(id).await.ok();
match context.vfs.check_access(id, &context.auth, nfs3::ACCESS3_READ).await {
Ok(granted) if granted & nfs3::ACCESS3_READ != 0 => {}
Ok(_) => {
xdr::rpc::make_success_reply(xid).serialize(output)?;
nfs3::nfsstat3::NFS3ERR_ACCES.serialize(output)?;
obj_attr.serialize(output)?;
return Ok(());
}
Err(stat) => {
xdr::rpc::make_success_reply(xid).serialize(output)?;
stat.serialize(output)?;
obj_attr.serialize(output)?;
return Ok(());
}
}
match context.vfs.read(id, args.offset, count).await {
Ok((bytes, eof)) => {
let res = nfs3::file::READ3resok {
file_attributes: obj_attr,
count: bytes.len() as u32,
eof,
data: bytes,
};
xdr::rpc::make_success_reply(xid).serialize(output)?;
nfs3::nfsstat3::NFS3_OK.serialize(output)?;
res.serialize(output)?;
}
Err(stat) => {
error!("nfsproc3_read error {:?} --> {:?}", xid, stat);
xdr::rpc::make_success_reply(xid).serialize(output)?;
stat.serialize(output)?;
obj_attr.serialize(output)?;
}
}
Ok(())
}