use crate::err::Result;
use crate::impl_serialize_for_bitflags;
use bitflags::bitflags;
use serde::Serialize;
use std::io::{Error, ErrorKind};
#[derive(Serialize, Clone, Debug)]
pub struct VolumeInformationAttr {
pub major_version: u8,
pub minor_version: u8,
pub flags: VolumeFlags,
}
bitflags! {
#[derive(Clone, Debug, PartialEq)]
pub struct VolumeFlags: u16 {
const IS_DIRTY = 0x0001;
const RESIZE_LOG_FILE = 0x0002;
const UPGRADE_ON_MOUNT = 0x0004;
const MOUNTED_ON_NT4 = 0x0008;
const DELETE_USN_UNDERWAY = 0x0010;
const REPAIR_OBJECT_ID = 0x0020;
const CHKDSK_UNDERWAY = 0x4000;
const MODIFIED_BY_CHKDSK = 0x8000;
}
}
impl_serialize_for_bitflags! {VolumeFlags}
impl VolumeInformationAttr {
pub fn from_slice(value: &[u8]) -> Result<VolumeInformationAttr> {
let Some(&[major_version, minor_version, f0, f1]) = value.get(8..12) else {
return Err(Error::new(
ErrorKind::UnexpectedEof,
format!(
"$VOLUME_INFORMATION is {} bytes, expected at least 12",
value.len()
),
)
.into());
};
Ok(VolumeInformationAttr {
major_version,
minor_version,
flags: VolumeFlags::from_bits_retain(u16::from_le_bytes([f0, f1])),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn short_value_is_error() {
assert!(VolumeInformationAttr::from_slice(&[0; 11]).is_err());
}
#[test]
fn trailing_reserved_bytes_and_unnamed_flag_bits_are_kept() {
let value: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0x01, 0x80, 0x80, 0, 0, 0, 0];
let attribute = VolumeInformationAttr::from_slice(value).unwrap();
assert_eq!((attribute.major_version, attribute.minor_version), (3, 1));
assert_eq!(attribute.flags.bits(), 0x8080);
assert!(attribute.flags.contains(VolumeFlags::MODIFIED_BY_CHKDSK));
}
}