mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-13 11:04:25 +08:00
fix(msd): 区分虚拟磁盘挂载能力与文件访问状态
使用原始文件元数据挂载虚拟磁盘,允许主机使用网页文件管理不支持的文件系统。连接期间只读取元数据;初始化和删除持有外层写锁,并同步控制器缓存。 API 的 used/free 改为可空值,新增 file_access 表示 available、unsupported、blocked_while_connected 或 unknown,需要前端配套处理。补充状态序列化、元数据校验和文件系统兼容测试。
This commit is contained in:
@@ -2,7 +2,7 @@ use super::config::apply::try_apply_lock;
|
||||
use super::*;
|
||||
|
||||
use crate::msd::{
|
||||
DiskModeRequest, DownloadProgress, DriveFile, DriveInfo, DriveInitRequest,
|
||||
DiskModeRequest, DownloadProgress, DriveFile, DriveFileAccess, DriveInfo, DriveInitRequest,
|
||||
ImageDownloadRequest, ImageInfo, ImageManager, ImageMountRequest, MsdErrorCode, MsdState,
|
||||
MsdStateResponse, VentoyDrive, MIN_DRIVE_SIZE_MB,
|
||||
};
|
||||
@@ -420,16 +420,26 @@ pub async fn msd_drive_info(State(state): State<Arc<AppState>>) -> Result<Json<D
|
||||
let drive_path = config.msd.drive_path();
|
||||
let drive = VentoyDrive::new(drive_path);
|
||||
|
||||
if !drive.exists() {
|
||||
// 404: drive image file does not exist at all — truly not initialized
|
||||
return Err(MsdErrorCode::MsdDriveNotInitialized.into());
|
||||
let msd_guard = state.msd.read().await;
|
||||
let connected = match msd_guard.as_ref() {
|
||||
Some(controller) => controller.is_drive_connected().await,
|
||||
None => false,
|
||||
};
|
||||
|
||||
// Never parse the filesystem while the USB host owns it. Metadata is safe
|
||||
// to read and still lets the UI show the backing image capacity.
|
||||
let info = if connected {
|
||||
drive.raw_info(DriveFileAccess::BlockedWhileConnected)
|
||||
} else {
|
||||
drive.info().await
|
||||
}
|
||||
.map_err(|error| operation_failed("read virtual drive info", error))?;
|
||||
|
||||
if let Some(controller) = msd_guard.as_ref() {
|
||||
controller.set_drive_info(Some(info.clone())).await;
|
||||
}
|
||||
|
||||
drive
|
||||
.info()
|
||||
.await
|
||||
.map(Json)
|
||||
.map_err(|error| operation_failed("read virtual drive info", error))
|
||||
Ok(Json(info))
|
||||
}
|
||||
|
||||
/// Initialize Ventoy drive
|
||||
@@ -439,7 +449,6 @@ pub async fn msd_drive_init(
|
||||
payload: std::result::Result<Json<DriveInitRequest>, JsonRejection>,
|
||||
) -> Result<Json<DriveInfo>> {
|
||||
let req = parse_msd_json(payload)?;
|
||||
assert_drive_not_connected(&state).await?;
|
||||
let config = state.config.get();
|
||||
let msd_dir = config.msd.msd_dir_path();
|
||||
|
||||
@@ -449,6 +458,16 @@ pub async fn msd_drive_init(
|
||||
})?;
|
||||
validate_drive_init_size(req.size_mb, disk_space.available)?;
|
||||
|
||||
// Mount/unmount handlers also take this outer write lock. Holding it
|
||||
// across image creation prevents a mount from racing the destructive
|
||||
// reinitialization after the connected-state check.
|
||||
let msd_guard = state.msd.write().await;
|
||||
if let Some(controller) = msd_guard.as_ref() {
|
||||
if controller.is_drive_connected().await {
|
||||
return Err(MsdErrorCode::MsdDriveConnected.into());
|
||||
}
|
||||
}
|
||||
|
||||
let drive_path = config.msd.drive_path();
|
||||
let drive = VentoyDrive::new(drive_path);
|
||||
|
||||
@@ -456,6 +475,9 @@ pub async fn msd_drive_init(
|
||||
.init(req.size_mb)
|
||||
.await
|
||||
.map_err(|error| operation_failed("initialize virtual drive", error))?;
|
||||
if let Some(controller) = msd_guard.as_ref() {
|
||||
controller.set_drive_info(Some(info.clone())).await;
|
||||
}
|
||||
Ok(Json(info))
|
||||
}
|
||||
|
||||
@@ -471,14 +493,15 @@ pub async fn msd_drive_delete(State(state): State<Arc<AppState>>) -> Result<Json
|
||||
return Err(MsdErrorCode::MsdDriveConnected.into());
|
||||
}
|
||||
}
|
||||
drop(msd_guard);
|
||||
|
||||
// Delete the drive file
|
||||
let drive_path = config.msd.drive_path();
|
||||
if drive_path.exists() {
|
||||
std::fs::remove_file(&drive_path)
|
||||
.map_err(|error| classify_storage_error("delete virtual drive", error))?;
|
||||
}
|
||||
if let Some(controller) = msd_guard.as_ref() {
|
||||
controller.set_drive_info(None).await;
|
||||
}
|
||||
|
||||
Ok(Json(LoginResponse {
|
||||
success: true,
|
||||
|
||||
Reference in New Issue
Block a user