1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use crate::err::{self, Result};

use byteorder::{LittleEndian, ReadBytesExt};
use encoding::all::UTF_16LE;
use encoding::{DecoderTrap, Encoding};

use std::io::Read;

use chrono::{DateTime, Utc};
use serde::Serialize;

use winstructs::reference::MftReference;
use winstructs::timestamp::WinTimestamp;

#[derive(Serialize, Clone, Debug)]
pub struct FileNameAttr {
    pub parent: MftReference,
    pub created: DateTime<Utc>,
    pub modified: DateTime<Utc>,
    pub mft_modified: DateTime<Utc>,
    pub accessed: DateTime<Utc>,
    pub logical_size: u64,
    pub physical_size: u64,
    pub flags: u32,
    pub reparse_value: u32,
    pub name_length: u8,
    pub namespace: u8,
    pub name: String,
    pub fullname: Option<String>,
}

// TODO: fix docs (use correct idioms)
impl FileNameAttr {
    /// Parse a Filename attrbiute buffer.
    ///
    /// # Example
    ///
    /// Parse a raw buffer.
    ///
    /// ```
    /// use rustymft::attr_x30::FileNameAttr;
    /// # fn test_filename_attribute() {
    /// let attribute_buffer: &[u8] = &[
    /// 	0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0xD5,0x2D,0x48,0x58,0x43,0x5F,0xCE,0x01,
    /// 	0xD5,0x2D,0x48,0x58,0x43,0x5F,0xCE,0x01,0xD5,0x2D,0x48,0x58,0x43,0x5F,0xCE,0x01,
    /// 	0xD5,0x2D,0x48,0x58,0x43,0x5F,0xCE,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
    /// 	0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    /// 	0x08,0x03,0x24,0x00,0x4C,0x00,0x6F,0x00,0x67,0x00,0x46,0x00,0x69,0x00,0x6C,0x00,
    /// 	0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    /// ];
    ///
    /// let attribute = match FileNameAttr::new(attribute_buffer) {
    /// 	Ok(attribute) => attribute,
    /// 	Err(error) => panic!(error)
    /// };
    ///
    /// assert_eq!(attribute.parent.0, 1407374883553285);
    /// assert_eq!(attribute.created.0, 130146182088895957);
    /// assert_eq!(attribute.modified.0, 130146182088895957);
    /// assert_eq!(attribute.mft_modified.0, 130146182088895957);
    /// assert_eq!(attribute.accessed.0, 130146182088895957);
    /// assert_eq!(attribute.logical_size, 67108864);
    /// assert_eq!(attribute.physical_size, 67108864);
    /// assert_eq!(attribute.flags, 6);
    /// assert_eq!(attribute.reparse_value, 0);
    /// assert_eq!(attribute.name_length, 8);
    /// assert_eq!(attribute.namespace, 3);
    /// assert_eq!(attribute.name, "$LogFile");
    /// # }
    /// ```
    pub fn from_reader<R: Read>(reader: &mut R) -> Result<FileNameAttr> {
        let parent = MftReference(reader.read_u64::<LittleEndian>()?);
        let created = WinTimestamp::from_reader(reader)?.to_datetime();
        let modified = WinTimestamp::from_reader(reader)?.to_datetime();
        let mft_modified = WinTimestamp::from_reader(reader)?.to_datetime();
        let accessed = WinTimestamp::from_reader(reader)?.to_datetime();
        let logical_size = reader.read_u64::<LittleEndian>()?;
        let physical_size = reader.read_u64::<LittleEndian>()?;
        let flags = reader.read_u32::<LittleEndian>()?;
        let reparse_value = reader.read_u32::<LittleEndian>()?;
        let name_length = reader.read_u8()?;
        let namespace = reader.read_u8()?;

        let mut name_buffer = vec![0; (name_length as usize * 2) as usize];
        reader.read_exact(&mut name_buffer)?;

        let name = match UTF_16LE.decode(&name_buffer, DecoderTrap::Ignore) {
            Ok(s) => s,
            Err(_e) => return err::InvalidFilename {}.fail(),
        };

        let fullname = None;

        Ok(FileNameAttr {
            parent,
            created,
            modified,
            mft_modified,
            accessed,
            logical_size,
            physical_size,
            flags,
            reparse_value,
            name_length,
            namespace,
            name,
            fullname,
        })
    }
}