vfsi_core/error.rs
1//! Structured errors for the low-level NFSv4.1 client.
2
3use std::fmt;
4
5/// NFS4 status used for transport-level failures (there is no NFS status).
6pub const STATUS_TRANSPORT: u32 = u32::MAX;
7
8/// An error from the low-level client: either an NFS4ERR_* status reported by
9/// the server for a compound operation, or a transport/RPC-level failure.
10///
11/// Callers can inspect [`status`](RpcError::status) directly instead of
12/// parsing error strings.
13///
14/// `op_index` is the index of the failing operation in the caller's request
15/// slice: the batched compound helpers (`readv`, `writev`, `getattr_many`,
16/// ...) translate compound positions to caller-relative indices before
17/// returning. For single-operation helpers it is the position within the
18/// compound (typically 2: `SEQUENCE`, `PUTFH`, op). Transport failures always
19/// report `op_index == 0`.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct RpcError {
22 /// Index of the failing operation within the compound.
23 pub op_index: usize,
24 /// The failing op's NFS4ERR_* status, or [`STATUS_TRANSPORT`].
25 pub status: u32,
26 /// Human-readable context.
27 pub message: String,
28}
29
30impl RpcError {
31 /// An NFS status from a specific compound operation.
32 pub fn op(op_index: usize, status: u32) -> RpcError {
33 RpcError {
34 op_index,
35 status,
36 message: String::new(),
37 }
38 }
39
40 /// A transport / RPC-level failure (no NFS status available).
41 pub fn transport(message: impl Into<String>) -> RpcError {
42 RpcError {
43 op_index: 0,
44 status: STATUS_TRANSPORT,
45 message: message.into(),
46 }
47 }
48
49 /// Whether this is a transport failure rather than an NFS status.
50 pub fn is_transport(&self) -> bool {
51 self.status == STATUS_TRANSPORT
52 }
53
54 /// Re-attribute this error to a different operation index (used by the
55 /// batched helpers to translate compound positions to caller indices).
56 pub fn with_op_index(self, index: usize) -> RpcError {
57 RpcError {
58 op_index: index,
59 ..self
60 }
61 }
62}
63
64impl fmt::Display for RpcError {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 if self.is_transport() {
67 write!(f, "transport error: {}", self.message)
68 } else {
69 write!(f, "op {} failed: status {}", self.op_index, self.status)
70 }
71 }
72}
73
74impl std::error::Error for RpcError {}
75
76/// Convenience alias used throughout the low-level client.
77pub type RpcResult<T> = Result<T, RpcError>;