use crate::anode::AnodeReader;
use crate::cache::BlockCache;
use crate::error::{Error, Result};
use crate::io::BlockDevice;
use crate::ondisk::*;
use crate::util;
pub fn list_entries(
dir_anode: u32,
anodes: &AnodeReader,
dev: &dyn BlockDevice,
cache: &mut BlockCache,
reserved_blksize: u16,
) -> Result<Vec<DirEntry>> {
let chain = anodes.get_chain(dir_anode, dev, cache)?;
let mut entries = Vec::new();
for an in &chain {
for i in 0..an.clustersize {
let blk = an.blocknr as u64 + i as u64;
let data = cache.read_reserved(dev, blk, reserved_blksize)?;
if data.len() < DIR_BLOCK_HEADER_SIZE + 1 {
continue;
}
let id = u16::from_be_bytes(data[0..2].try_into().unwrap());
if id != DBLKID {
continue;
}
parse_dirblock_entries(data, &mut entries);
}
}
Ok(entries)
}
fn parse_dirblock_entries(data: &[u8], entries: &mut Vec<DirEntry>) {
let mut offset = DIR_BLOCK_HEADER_SIZE;
while offset < data.len() {
match DirEntry::parse(data, offset) {
Some((entry, next)) => {
entries.push(entry);
offset = next;
}
None => break,
}
}
}
pub fn lookup(
dir_anode: u32,
name: &str,
anodes: &AnodeReader,
dev: &dyn BlockDevice,
cache: &mut BlockCache,
reserved_blksize: u16,
) -> Result<DirEntry> {
let entries = list_entries(dir_anode, anodes, dev, cache, reserved_blksize)?;
entries
.into_iter()
.find(|e| util::name_eq_ci(&e.name, name))
.ok_or_else(|| Error::NotFound(name.to_string()))
}
pub fn resolve_path(
path: &str,
anodes: &AnodeReader,
dev: &dyn BlockDevice,
cache: &mut BlockCache,
reserved_blksize: u16,
) -> Result<Option<DirEntry>> {
let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
if parts.is_empty() {
return Ok(None); }
let mut dir_anode = ANODE_ROOTDIR;
for (i, part) in parts.iter().enumerate() {
let entry = lookup(dir_anode, part, anodes, dev, cache, reserved_blksize)?;
if i < parts.len() - 1 {
if !entry.is_dir() {
return Err(Error::NotADirectory);
}
dir_anode = entry.anode;
} else {
return Ok(Some(entry));
}
}
Ok(None)
}
pub fn resolve_dir_path(
path: &str,
anodes: &AnodeReader,
dev: &dyn BlockDevice,
cache: &mut BlockCache,
reserved_blksize: u16,
) -> Result<u32> {
let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
if parts.is_empty() {
return Ok(ANODE_ROOTDIR);
}
let mut dir_anode = ANODE_ROOTDIR;
for part in &parts {
let entry = lookup(dir_anode, part, anodes, dev, cache, reserved_blksize)?;
if !entry.is_dir() {
return Err(Error::NotADirectory);
}
dir_anode = entry.anode;
}
Ok(dir_anode)
}