Files
markbase/vendor/smb-server/src/error.rs
T
Warren 7eb528d35f
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled
SMB Server Phase 2: VFS backend build fix + integration test
- Add VfsFile: Send supertrait for Mutex compatibility
- Fix SmbServerCommand: struct → Subcommand enum with Start variant
- Fix tracing_subscriber::init() → try_init() to avoid panic when
  logger already initialized
- Fix CLI subcommand name: smb-server → smb-start (flatten naming)
- Add #[command(name = "smb-start")] for CLI disambiguation
- Fix unused variable warnings (smb_fs.rs, smb_server_backend.rs)
- Remove unused VfsFile imports (webdav.rs, scp_handler.rs)
- Integration test: Docker smbclient verified (list, upload, read)
2026-06-20 19:42:29 +08:00

87 lines
3.1 KiB
Rust

//! Public error type for the server, plus the NTSTATUS mapping per spec §8.
use thiserror::Error;
use crate::ntstatus;
pub type SmbResult<T> = Result<T, SmbError>;
/// Errors returned by `ShareBackend` and surfaced through the SMB protocol.
///
/// `to_nt_status` maps each variant onto a single NTSTATUS code per the spec
/// §8 table. Internal protocol-layer failures (malformed frames, signing
/// errors) never become `SmbError`; the connection loop logs them and aborts.
#[derive(Debug, Error)]
pub enum SmbError {
#[error("not found")]
NotFound,
#[error("path not found")]
PathNotFound,
#[error("access denied")]
AccessDenied,
#[error("exists")]
Exists,
#[error("not empty")]
NotEmpty,
#[error("is a directory")]
IsDirectory,
#[error("not a directory")]
NotADirectory,
#[error("name too long / invalid")]
NameInvalid,
#[error("sharing violation")]
Sharing,
#[error("not supported")]
NotSupported,
#[error("io: {0}")]
Io(#[from] std::io::Error),
}
impl SmbError {
/// Map this error onto an NTSTATUS code per the v1 spec §8 table.
pub fn to_nt_status(&self) -> u32 {
match self {
SmbError::NotFound => ntstatus::STATUS_OBJECT_NAME_NOT_FOUND,
SmbError::PathNotFound => ntstatus::STATUS_OBJECT_PATH_NOT_FOUND,
SmbError::AccessDenied => ntstatus::STATUS_ACCESS_DENIED,
SmbError::Exists => ntstatus::STATUS_OBJECT_NAME_COLLISION,
SmbError::NotEmpty => ntstatus::STATUS_DIRECTORY_NOT_EMPTY,
SmbError::IsDirectory => ntstatus::STATUS_FILE_IS_A_DIRECTORY,
SmbError::NotADirectory => ntstatus::STATUS_NOT_A_DIRECTORY,
SmbError::NameInvalid => ntstatus::STATUS_OBJECT_NAME_INVALID,
SmbError::Sharing => ntstatus::STATUS_SHARING_VIOLATION,
SmbError::NotSupported => ntstatus::STATUS_NOT_SUPPORTED,
SmbError::Io(_) => ntstatus::STATUS_UNEXPECTED_IO_ERROR,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nt_status_table_matches_spec() {
assert_eq!(SmbError::NotFound.to_nt_status(), 0xC000_000F);
assert_eq!(SmbError::PathNotFound.to_nt_status(), 0xC000_003A);
assert_eq!(SmbError::AccessDenied.to_nt_status(), 0xC000_0022);
assert_eq!(SmbError::Exists.to_nt_status(), 0xC000_0035);
assert_eq!(SmbError::NotEmpty.to_nt_status(), 0xC000_0101);
assert_eq!(SmbError::IsDirectory.to_nt_status(), 0xC000_00BA);
assert_eq!(SmbError::NotADirectory.to_nt_status(), 0xC000_0103);
assert_eq!(SmbError::NameInvalid.to_nt_status(), 0xC000_0033);
assert_eq!(SmbError::Sharing.to_nt_status(), 0xC000_0043);
assert_eq!(SmbError::NotSupported.to_nt_status(), 0xC000_00BB);
let io_err = SmbError::Io(std::io::Error::other("boom"));
assert_eq!(io_err.to_nt_status(), 0xC000_009C);
}
#[test]
fn io_err_from_blanket_works() {
let io: std::io::Error = std::io::Error::other("x");
let smb: SmbError = io.into();
assert_eq!(smb.to_nt_status(), 0xC000_009C);
}
}