mod common;
use std::io::Cursor;
use fast_ntfs::attribute_value::NtfsAttributeValue;
use fast_ntfs::indexes::NtfsFileNameIndex;
use fast_ntfs::io::SeekFrom;
use fast_ntfs::{Ntfs, NtfsFile, NtfsReadSeek};
fn file_by_name<'n>(ntfs: &'n Ntfs, fs: &mut Cursor<Vec<u8>>, name: &str) -> NtfsFile<'n> {
let root_directory = ntfs.root_directory(fs).unwrap();
let index = root_directory.directory_index(fs).unwrap();
let mut finder = index.finder();
let entry = NtfsFileNameIndex::find(&mut finder, ntfs, fs, name)
.unwrap()
.unwrap();
entry.to_file(ntfs, fs).unwrap()
}
#[test]
fn reads_complete_non_resident_value() {
let mut fs = common::testfs1();
let ntfs = Ntfs::new(&mut fs).unwrap();
ntfs.read_upcase_table(&mut fs).unwrap();
let file = file_by_name(&ntfs, &mut fs, "1000-bytes-file");
let item = file.data(&mut fs, "").unwrap().unwrap();
let attribute = item.to_attribute().unwrap();
let mut value = attribute.value(&mut fs).unwrap();
let mut buffer = [0xcc; 1001];
assert!(!attribute.is_resident());
assert_eq!(value.read(&mut fs, &mut buffer).unwrap(), 1000);
assert_eq!(&buffer[..1000], b"12345".repeat(200));
assert_eq!(buffer[1000], 0xcc);
value.seek(&mut fs, SeekFrom::Start(1026)).unwrap();
assert!(value.data_position().value().is_none());
}
#[test]
fn reads_sparse_data_runs_as_zeroes() {
let mut fs = common::testfs1();
let ntfs = Ntfs::new(&mut fs).unwrap();
ntfs.read_upcase_table(&mut fs).unwrap();
let file = file_by_name(&ntfs, &mut fs, "sparse-file");
let item = file.data(&mut fs, "").unwrap().unwrap();
let attribute = item.to_attribute().unwrap();
let non_resident = match attribute.value(&mut fs).unwrap() {
NtfsAttributeValue::NonResident(value) => value,
_ => panic!("sparse data must be non-resident"),
};
let mut data_runs = non_resident.data_runs();
assert!(
data_runs
.next()
.unwrap()
.unwrap()
.data_position()
.value()
.is_some()
);
assert!(
data_runs
.next()
.unwrap()
.unwrap()
.data_position()
.value()
.is_none()
);
assert!(
data_runs
.next()
.unwrap()
.unwrap()
.data_position()
.value()
.is_some()
);
assert!(data_runs.next().is_none());
let mut value = attribute.value(&mut fs).unwrap();
let mut buffer = vec![0u8; 500_005];
assert_eq!(value.read(&mut fs, &mut buffer).unwrap(), buffer.len());
assert_eq!(&buffer[..5], b"12345");
assert!(buffer[5..500_000].iter().all(|byte| *byte == 0));
assert_eq!(&buffer[500_000..], b"11111");
}
#[test]
fn resident_and_non_resident_values_share_read_and_seek_semantics() {
let mut fs = common::testfs1();
let ntfs = Ntfs::new(&mut fs).unwrap();
ntfs.read_upcase_table(&mut fs).unwrap();
for (name, length) in [("file-with-12345", 5), ("1000-bytes-file", 1000)] {
let file = file_by_name(&ntfs, &mut fs, name);
let item = file.data(&mut fs, "").unwrap().unwrap();
let attribute = item.to_attribute().unwrap();
let mut value = attribute.value(&mut fs).unwrap();
assert_eq!(value.len(), length);
value.seek(&mut fs, SeekFrom::End(-5)).unwrap();
let mut tail = [0u8; 5];
value.read_exact(&mut fs, &mut tail).unwrap();
assert_eq!(&tail, b"12345");
assert_eq!(value.stream_position(), length);
value.seek(&mut fs, SeekFrom::Start(length + 1)).unwrap();
assert_eq!(value.stream_position(), length + 1);
assert_eq!(value.read(&mut fs, &mut [0u8; 1]).unwrap(), 0);
}
}