From 8d974a6ee4a99e52ed646d809d26e5339b241f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Sun, 24 Sep 2017 00:05:43 +0200 Subject: [PATCH] Add path traversal functions. --- src/dir.rs | 55 +++++++++++++++++++++++++++++++++++++++ tests/integration-test.rs | 15 +++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/dir.rs b/src/dir.rs index a666116..4f2e58b 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -1,5 +1,7 @@ +use std::ascii::AsciiExt; use std::io::prelude::*; use std::io; +use std::io::ErrorKind; use std::str; use byteorder::{LittleEndian, ReadBytesExt}; use chrono::{DateTime, Date, TimeZone, Local}; @@ -21,6 +23,7 @@ bitflags! { } #[allow(dead_code)] +#[derive(Clone)] pub struct FatDirEntry { name: [u8; 11], attrs: FatFileAttributes, @@ -59,14 +62,29 @@ impl FatDirEntry { self.attrs } + pub fn is_dir(&self) -> bool { + self.attrs.contains(FatFileAttributes::DIRECTORY) + } + pub fn get_cluster(&self) -> u32 { ((self.first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32 } pub fn get_file(&self) -> FatFile { + if self.is_dir() { + panic!("This is a directory"); + } FatFile::new(self.get_cluster(), Some(self.size), self.state.clone()) } + pub fn get_dir(&self) -> FatDir { + if !self.is_dir() { + panic!("This is a file"); + } + let file = FatFile::new(self.get_cluster(), None, self.state.clone()); + FatDir::new(Box::new(file), self.state.clone()) + } + pub fn get_size(&self) -> u32 { self.size } @@ -134,4 +152,41 @@ impl FatDir { state: self.state.clone(), }) } + + fn split_path<'a>(path: &'a str) -> (&'a str, Option<&'a str>) { + let mut path_split = path.trim_matches('/').splitn(2, "/"); + let comp = path_split.next().unwrap(); + let rest_opt = path_split.next(); + (comp, rest_opt) + } + + fn find_entry(&mut self, name: &str) -> io::Result { + // FIXME: we should seek to beggining here + let entries: Vec = self.list()?; + for e in entries { + if e.get_name().eq_ignore_ascii_case(name) { + println!("find entry {}", name); + return Ok(e); + } + } + Err(io::Error::new(ErrorKind::NotFound, "file not found")) + } + + pub fn get_dir(&mut self, path: &str) -> io::Result { + let (name, rest_opt) = Self::split_path(path); + let e = self.find_entry(name)?; + match rest_opt { + Some(rest) => e.get_dir().get_dir(rest), + None => Ok(e.get_dir()) + } + } + + pub fn get_file(&mut self, path: &str) -> io::Result { + let (name, rest_opt) = Self::split_path(path); + let e = self.find_entry(name)?; + match rest_opt { + Some(rest) => e.get_dir().get_file(rest), + None => Ok(e.get_file()) + } + } } diff --git a/tests/integration-test.rs b/tests/integration-test.rs index fc1b4bc..0c0f5bd 100644 --- a/tests/integration-test.rs +++ b/tests/integration-test.rs @@ -34,6 +34,21 @@ fn test_img(name: &str) { assert_eq!(str::from_utf8(&buf).unwrap(), TEST_TEXT.repeat(1000)); } + { + let mut root_dir = fs.root_dir(); + let mut dir = root_dir.get_dir("very/long/path/").unwrap(); + let entries = dir.list().unwrap(); + let names = entries.iter().map(|e| e.get_name()).collect::>(); + assert_eq!(names, [".", "..", "TEST.TXT"]); + } + + { + let mut root_dir = fs.root_dir(); + let mut file = root_dir.get_file("very/long/path/test.txt").unwrap(); + let mut buf = Vec::new(); + file.read_to_end(&mut buf).unwrap(); + assert_eq!(str::from_utf8(&buf).unwrap(), TEST_TEXT); + } } #[test]