Viewing: error.rs

// SPDX-License-Identifier: MIT

// Copyright (c) 2025 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{LustrePath, Statfs};
use nix::errno::Errno;
use std::{ffi::FromBytesWithNulError, path::Path, result};
use thiserror::Error;

pub type Result<T> = result::Result<T, Error>;

#[derive(Error, Debug)]
pub enum Error {
    #[error("Not a Lustre filesystem {0}")]
    NotLustreFileSystem(String),

    #[error("Unable to open root: {0}: {1}")]
    LustreRootOpenError(LustrePath, std::io::Error),

    #[error("Allocation error: {0}")]
    AllocError(String),

    #[error("UTF8 Error: {0}")]
    StringConversionError(#[from] std::string::FromUtf8Error),

    #[error("UTF8 Error: {0}")]
    PathConversionError(#[from] core::str::Utf8Error),

    #[error("Invalid path: {0}")]
    UUIDParseError(#[from] FromBytesWithNulError),

    #[error(transparent)]
    Errno(Errno),

    #[error("{0}: {1}")]
    MsgErrno(String, Errno),

    #[error("parse fid error in {original} '{part}': {err}")]
    ParseFidError {
        original: String,
        part: String,
        err: std::num::ParseIntError,
    },

    #[error("invalid fid format: '{str}'")]
    InvalidFidFormat { str: String },

    #[deprecated]
    #[error(transparent)]
    Io(#[from] std::io::Error),

    #[error(transparent)]
    NulError(#[from] std::ffi::NulError),

    #[error("Would block")]
    WouldBlock,

    #[error("Lustre stats error. stat_type: {stat} index: {index} source: {source}")]
    LustreStatfs {
        stat: Statfs,
        index: u32,
        source: Errno,
    },

    #[error("Component {component_type} at index {index} is inactive")]
    ComponentInactive { component_type: Statfs, index: u32 },

    #[error(
        "Insufficient components for filesystem {filesystem}: OST count {ost_count}, total blocks {total_blocks}"
    )]
    InsufficientComponents {
        filesystem: String,
        ost_count: u32,
        total_blocks: u64,
    },

    #[error("Mount search error at index {index}: {errno}")]
    MountSearchError { index: i32, errno: Errno },

    #[error("Invalid path: {path}")]
    InvalidPath { path: Box<Path> },

    #[error("Filesystem '{filesystem}' not found in mounted Lustre filesystems")]
    FilesystemNotFound { filesystem: String },
}

impl From<Error> for std::fmt::Error {
    fn from(_err: Error) -> Self {
        std::fmt::Error
    }
}

/// Converts a negative return value from a lustre function as an `Err` variant.
/// Otherwise, returns the value as an `Ok` variant.
pub(crate) fn cvt_lz(t: libc::c_int) -> Result<i32> {
    if t < 0 {
        Err(Error::Errno(Errno::last()))
    } else {
        Ok(t)
    }
}

/// Converts a negative return value from a lustre function as an `Err` variant.
/// Otherwise, returns the value as an `Ok` variant.
/// Adds a message to the error
pub(crate) fn cvt_lz_m(t: libc::c_int, msg: String) -> Result<i32> {
    if t < 0 {
        Err(Error::MsgErrno(msg, Errno::last()))
    } else {
        Ok(t)
    }
}

/// Converts a non-zero return value from a lustre function as an `Err` variant.
pub(crate) fn cvt_nz(t: libc::c_int) -> Result<()> {
    if t != 0 {
        Err(Error::Errno(Errno::last()))
    } else {
        Ok(())
    }
}

/// Converts a non-zero return value from a lustre function as an `Err` variant.
/// Adds a message to the error
pub(crate) fn cvt_nz_m(t: libc::c_int, msg: String) -> Result<()> {
    if t != 0 {
        Err(Error::MsgErrno(msg, Errno::last()))
    } else {
        Ok(())
    }
}

pub(crate) fn cvt_rc_m(t: libc::c_int, msg: String) -> Result<()> {
    if t < 0 {
        match Errno::from_raw(-t) {
            Errno::EAGAIN => Err(Error::WouldBlock),
            _ => Err(Error::MsgErrno(msg, Errno::from_raw(-t))),
        }
    } else {
        Ok(())
    }
}

pub(crate) fn cvt_null_mut_m<T>(t: *mut T, msg: String) -> Result<*mut T> {
    if t.is_null() {
        Err(Error::MsgErrno(msg, Errno::last()))
    } else {
        Ok(t)
    }
}