Skip to content

Commit 6071df4

Browse files
authored
Merge pull request #19 from ceigel/master
Add Controller.open_dir_entry function to open a dir_entry
2 parents 88d8ce6 + ad58b60 commit 6071df4

File tree

2 files changed

+135
-81
lines changed

2 files changed

+135
-81
lines changed

src/filesystem.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ pub enum FilenameError {
142142
NameTooLong,
143143
/// Can't start a file with a period, or after 8 characters.
144144
MisplacedPeriod,
145+
/// Can't extract utf8 from file name
146+
Utf8Error,
145147
}
146148

147149
// ****************************************************************************
@@ -268,6 +270,20 @@ impl ShortFileName {
268270
const FILENAME_BASE_MAX_LEN: usize = 8;
269271
const FILENAME_MAX_LEN: usize = 11;
270272

273+
/// Get base name (name without extension) of file name
274+
pub fn base_name(&self) -> &[u8] {
275+
Self::bytes_before_space(&self.contents[..Self::FILENAME_BASE_MAX_LEN])
276+
}
277+
278+
/// Get base name (name without extension) of file name
279+
pub fn extension(&self) -> &[u8] {
280+
Self::bytes_before_space(&self.contents[Self::FILENAME_BASE_MAX_LEN..])
281+
}
282+
283+
fn bytes_before_space(bytes: &[u8]) -> &[u8] {
284+
bytes.split(|b| *b == b' ').next().unwrap_or(&bytes[0..0])
285+
}
286+
271287
/// Create a new MS-DOS 8.3 space-padded file name as stored in the directory entry.
272288
pub fn create_from_str(name: &str) -> Result<ShortFileName, FilenameError> {
273289
let mut sfn = ShortFileName {
@@ -735,6 +751,26 @@ mod test {
735751
assert_eq!(sfn, ShortFileName::create_from_str("HELLO.TXT").unwrap());
736752
}
737753

754+
#[test]
755+
fn filename_get_extension() {
756+
let mut sfn = ShortFileName::create_from_str("hello.txt").unwrap();
757+
assert_eq!(sfn.extension(), "TXT".as_bytes());
758+
sfn = ShortFileName::create_from_str("hello").unwrap();
759+
assert_eq!(sfn.extension(), "".as_bytes());
760+
sfn = ShortFileName::create_from_str("hello.a").unwrap();
761+
assert_eq!(sfn.extension(), "A".as_bytes());
762+
}
763+
764+
#[test]
765+
fn filename_get_base_name() {
766+
let mut sfn = ShortFileName::create_from_str("hello.txt").unwrap();
767+
assert_eq!(sfn.base_name(), "HELLO".as_bytes());
768+
sfn = ShortFileName::create_from_str("12345678").unwrap();
769+
assert_eq!(sfn.base_name(), "12345678".as_bytes());
770+
sfn = ShortFileName::create_from_str("1").unwrap();
771+
assert_eq!(sfn.base_name(), "1".as_bytes());
772+
}
773+
738774
#[test]
739775
fn filename_fulllength() {
740776
let sfn = ShortFileName {

src/lib.rs

Lines changed: 99 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -440,86 +440,38 @@ where
440440
}
441441
}
442442

443-
/// Open a file with the given full path. A file can only be opened once.
444-
pub fn open_file_in_dir(
443+
/// Open a file from DirEntry. This is obtained by calling iterate_dir. A file can only be opened once.
444+
pub fn open_dir_entry(
445445
&mut self,
446446
volume: &mut Volume,
447-
dir: &Directory,
448-
name: &str,
447+
dir_entry: DirEntry,
449448
mode: Mode,
450449
) -> Result<File, Error<D::Error>> {
451-
// Find a free directory entry
452-
let mut open_files_row = None;
453-
for (i, d) in self.open_files.iter().enumerate() {
454-
if d.1 == Cluster::INVALID {
455-
open_files_row = Some(i);
450+
let open_files_row = self.get_open_files_row()?;
451+
// Check it's not already open
452+
for dir_table_row in self.open_files.iter() {
453+
if *dir_table_row == (volume.idx, dir_entry.cluster) {
454+
return Err(Error::DirAlreadyOpen);
456455
}
457456
}
458-
let open_files_row = open_files_row.ok_or(Error::TooManyOpenDirs)?;
459-
let dir_entry = match &volume.volume_type {
460-
VolumeType::Fat(fat) => fat.find_directory_entry(self, dir, name),
461-
};
462-
463-
let dir_entry = match dir_entry {
464-
Ok(entry) => Some(entry),
465-
Err(_)
466-
if (mode == Mode::ReadWriteCreate)
467-
| (mode == Mode::ReadWriteCreateOrTruncate)
468-
| (mode == Mode::ReadWriteCreateOrAppend) =>
469-
{
470-
None
471-
}
472-
_ => return Err(Error::FileNotFound),
473-
};
474-
475-
if let Some(entry) = &dir_entry {
476-
// Check it's not already open
477-
for dir_table_row in self.open_files.iter() {
478-
if *dir_table_row == (volume.idx, entry.cluster) {
479-
return Err(Error::DirAlreadyOpen);
480-
}
481-
}
482-
if entry.attributes.is_directory() {
483-
return Err(Error::OpenedDirAsFile);
484-
}
485-
if entry.attributes.is_read_only() && mode != Mode::ReadOnly {
486-
return Err(Error::ReadOnly);
487-
}
488-
};
489-
490-
let mut mode = mode;
491-
if mode == Mode::ReadWriteCreateOrAppend {
492-
if dir_entry.is_some() {
493-
mode = Mode::ReadWriteAppend;
494-
} else {
495-
mode = Mode::ReadWriteCreate;
496-
}
497-
} else if mode == Mode::ReadWriteCreateOrTruncate {
498-
if dir_entry.is_some() {
499-
mode = Mode::ReadWriteTruncate;
500-
} else {
501-
mode = Mode::ReadWriteCreate;
502-
}
457+
if dir_entry.attributes.is_directory() {
458+
return Err(Error::OpenedDirAsFile);
459+
}
460+
if dir_entry.attributes.is_read_only() && mode != Mode::ReadOnly {
461+
return Err(Error::ReadOnly);
503462
}
504463

464+
let mode = solve_mode_variant(mode, true);
505465
let file = match mode {
506-
Mode::ReadOnly => {
507-
// Safe to unwrap, since we actually have an entry if we got here
508-
let dir_entry = dir_entry.unwrap();
509-
510-
File {
511-
starting_cluster: dir_entry.cluster,
512-
current_cluster: (0, dir_entry.cluster),
513-
current_offset: 0,
514-
length: dir_entry.size,
515-
mode,
516-
entry: dir_entry,
517-
}
518-
}
466+
Mode::ReadOnly => File {
467+
starting_cluster: dir_entry.cluster,
468+
current_cluster: (0, dir_entry.cluster),
469+
current_offset: 0,
470+
length: dir_entry.size,
471+
mode,
472+
entry: dir_entry,
473+
},
519474
Mode::ReadWriteAppend => {
520-
// Safe to unwrap, since we actually have an entry if we got here
521-
let dir_entry = dir_entry.unwrap();
522-
523475
let mut file = File {
524476
starting_cluster: dir_entry.cluster,
525477
current_cluster: (0, dir_entry.cluster),
@@ -533,9 +485,6 @@ where
533485
file
534486
}
535487
Mode::ReadWriteTruncate => {
536-
// Safe to unwrap, since we actually have an entry if we got here
537-
let dir_entry = dir_entry.unwrap();
538-
539488
let mut file = File {
540489
starting_cluster: dir_entry.cluster,
541490
current_cluster: (0, dir_entry.cluster),
@@ -560,6 +509,41 @@ where
560509

561510
file
562511
}
512+
_ => return Err(Error::Unsupported),
513+
};
514+
// Remember this open file
515+
self.open_files[open_files_row] = (volume.idx, file.starting_cluster);
516+
Ok(file)
517+
}
518+
519+
/// Open a file with the given full path. A file can only be opened once.
520+
pub fn open_file_in_dir(
521+
&mut self,
522+
volume: &mut Volume,
523+
dir: &Directory,
524+
name: &str,
525+
mode: Mode,
526+
) -> Result<File, Error<D::Error>> {
527+
let dir_entry = match &volume.volume_type {
528+
VolumeType::Fat(fat) => fat.find_directory_entry(self, dir, name),
529+
};
530+
531+
let open_files_row = self.get_open_files_row()?;
532+
let dir_entry = match dir_entry {
533+
Ok(entry) => Some(entry),
534+
Err(_)
535+
if (mode == Mode::ReadWriteCreate)
536+
| (mode == Mode::ReadWriteCreateOrTruncate)
537+
| (mode == Mode::ReadWriteCreateOrAppend) =>
538+
{
539+
None
540+
}
541+
_ => return Err(Error::FileNotFound),
542+
};
543+
544+
let mode = solve_mode_variant(mode, dir_entry.is_some());
545+
546+
match mode {
563547
Mode::ReadWriteCreate => {
564548
if dir_entry.is_some() {
565549
return Err(Error::FileAlreadyExists);
@@ -573,20 +557,36 @@ where
573557
}
574558
};
575559

576-
File {
560+
let file = File {
577561
starting_cluster: entry.cluster,
578562
current_cluster: (0, entry.cluster),
579563
current_offset: 0,
580564
length: entry.size,
581565
mode,
582566
entry,
583-
}
567+
};
568+
// Remember this open file
569+
self.open_files[open_files_row] = (volume.idx, file.starting_cluster);
570+
Ok(file)
584571
}
585-
_ => return Err(Error::Unsupported),
586-
};
587-
// Remember this open file
588-
self.open_files[open_files_row] = (volume.idx, file.starting_cluster);
589-
Ok(file)
572+
_ => {
573+
// Safe to unwrap, since we actually have an entry if we got here
574+
let dir_entry = dir_entry.unwrap();
575+
self.open_dir_entry(volume, dir_entry, mode)
576+
}
577+
}
578+
}
579+
580+
/// Get the next entry in open_files list
581+
fn get_open_files_row(&self) -> Result<usize, Error<D::Error>> {
582+
// Find a free directory entry
583+
let mut open_files_row = None;
584+
for (i, d) in self.open_files.iter().enumerate() {
585+
if d.1 == Cluster::INVALID {
586+
open_files_row = Some(i);
587+
}
588+
}
589+
open_files_row.ok_or(Error::TooManyOpenDirs)
590590
}
591591

592592
/// Read from an open file.
@@ -800,7 +800,25 @@ where
800800
//
801801
// ****************************************************************************
802802

803-
// None
803+
/// Transform mode variants (ReadWriteCreate_Or_Append) to simple modes ReadWriteAppend or
804+
/// ReadWriteCreate
805+
fn solve_mode_variant(mode: Mode, dir_entry_is_some: bool) -> Mode {
806+
let mut mode = mode;
807+
if mode == Mode::ReadWriteCreateOrAppend {
808+
if dir_entry_is_some {
809+
mode = Mode::ReadWriteAppend;
810+
} else {
811+
mode = Mode::ReadWriteCreate;
812+
}
813+
} else if mode == Mode::ReadWriteCreateOrTruncate {
814+
if dir_entry_is_some {
815+
mode = Mode::ReadWriteTruncate;
816+
} else {
817+
mode = Mode::ReadWriteCreate;
818+
}
819+
}
820+
mode
821+
}
804822

805823
// ****************************************************************************
806824
//

0 commit comments

Comments
 (0)