|
5 | 5 | use byteorder::{ByteOrder, LittleEndian};
|
6 | 6 | use core::convert::TryFrom;
|
7 | 7 |
|
8 |
| -use crate::fat::{self, BlockCache, RESERVED_ENTRIES}; |
| 8 | +use crate::fat::{self, BlockCache, FatType, OnDiskDirEntry, RESERVED_ENTRIES}; |
9 | 9 |
|
10 | 10 | use crate::filesystem::{
|
11 | 11 | Attributes, ClusterId, DirEntry, DirectoryInfo, FileInfo, Mode, RawDirectory, RawFile,
|
@@ -432,8 +432,7 @@ where
|
432 | 432 | match &self.open_volumes[volume_idx].volume_type {
|
433 | 433 | VolumeType::Fat(fat) => {
|
434 | 434 | file.entry.mtime = self.time_source.get_timestamp();
|
435 |
| - let fat_type = fat.get_fat_type(); |
436 |
| - self.write_entry_to_disk(fat_type, &file.entry)?; |
| 435 | + fat.write_entry_to_disk(&self.block_device, &file.entry)?; |
437 | 436 | }
|
438 | 437 | };
|
439 | 438 |
|
@@ -518,7 +517,7 @@ where
|
518 | 517 | VolumeType::Fat(fat) => fat.write_new_directory_entry(
|
519 | 518 | &self.block_device,
|
520 | 519 | &self.time_source,
|
521 |
| - directory_info, |
| 520 | + directory_info.cluster, |
522 | 521 | sfn,
|
523 | 522 | att,
|
524 | 523 | )?,
|
@@ -789,8 +788,7 @@ where
|
789 | 788 | // If you have a length, you must have a cluster
|
790 | 789 | assert!(file_info.entry.cluster.0 != 0);
|
791 | 790 | }
|
792 |
| - let fat_type = fat.get_fat_type(); |
793 |
| - self.write_entry_to_disk(fat_type, &file_info.entry)?; |
| 791 | + fat.write_entry_to_disk(&self.block_device, &file_info.entry)?; |
794 | 792 | }
|
795 | 793 | };
|
796 | 794 | }
|
@@ -866,6 +864,146 @@ where
|
866 | 864 | Ok(self.open_files[file_idx].current_offset)
|
867 | 865 | }
|
868 | 866 |
|
| 867 | + /// Create a directory in a given directory. |
| 868 | + pub fn make_dir_in_dir<N>( |
| 869 | + &mut self, |
| 870 | + directory: RawDirectory, |
| 871 | + name: N, |
| 872 | + ) -> Result<(), Error<D::Error>> |
| 873 | + where |
| 874 | + N: ToShortFileName, |
| 875 | + { |
| 876 | + // This check is load-bearing - we do an unchecked push later. |
| 877 | + if self.open_dirs.is_full() { |
| 878 | + return Err(Error::TooManyOpenDirs); |
| 879 | + } |
| 880 | + |
| 881 | + let parent_directory_idx = self.get_dir_by_id(directory)?; |
| 882 | + let parent_directory_info = &self.open_dirs[parent_directory_idx]; |
| 883 | + let volume_id = self.open_dirs[parent_directory_idx].volume_id; |
| 884 | + let volume_idx = self.get_volume_by_id(volume_id)?; |
| 885 | + let volume_info = &self.open_volumes[volume_idx]; |
| 886 | + let sfn = name.to_short_filename().map_err(Error::FilenameError)?; |
| 887 | + |
| 888 | + debug!("Creating directory '{}'", sfn); |
| 889 | + debug!( |
| 890 | + "Parent dir is in cluster {:?}", |
| 891 | + parent_directory_info.cluster |
| 892 | + ); |
| 893 | + |
| 894 | + // Does an entry exist with this name? |
| 895 | + let maybe_dir_entry = match &volume_info.volume_type { |
| 896 | + VolumeType::Fat(fat) => { |
| 897 | + fat.find_directory_entry(&self.block_device, parent_directory_info, &sfn) |
| 898 | + } |
| 899 | + }; |
| 900 | + |
| 901 | + match maybe_dir_entry { |
| 902 | + Ok(entry) if entry.attributes.is_directory() => { |
| 903 | + return Err(Error::DirAlreadyExists); |
| 904 | + } |
| 905 | + Ok(_entry) => { |
| 906 | + return Err(Error::FileAlreadyExists); |
| 907 | + } |
| 908 | + Err(Error::FileNotFound) => { |
| 909 | + // perfect, let's make it |
| 910 | + } |
| 911 | + Err(e) => { |
| 912 | + // Some other error - tell them about it |
| 913 | + return Err(e); |
| 914 | + } |
| 915 | + }; |
| 916 | + |
| 917 | + let att = Attributes::create_from_fat(Attributes::DIRECTORY); |
| 918 | + |
| 919 | + // Need mutable access for this |
| 920 | + match &mut self.open_volumes[volume_idx].volume_type { |
| 921 | + VolumeType::Fat(fat) => { |
| 922 | + debug!("Making dir entry"); |
| 923 | + let mut new_dir_entry_in_parent = fat.write_new_directory_entry( |
| 924 | + &self.block_device, |
| 925 | + &self.time_source, |
| 926 | + parent_directory_info.cluster, |
| 927 | + sfn, |
| 928 | + att, |
| 929 | + )?; |
| 930 | + if new_dir_entry_in_parent.cluster == ClusterId::EMPTY { |
| 931 | + new_dir_entry_in_parent.cluster = |
| 932 | + fat.alloc_cluster(&self.block_device, None, false)?; |
| 933 | + // update the parent dir with the cluster of the new dir |
| 934 | + fat.write_entry_to_disk(&self.block_device, &new_dir_entry_in_parent)?; |
| 935 | + } |
| 936 | + let new_dir_start_block = fat.cluster_to_block(new_dir_entry_in_parent.cluster); |
| 937 | + debug!("Made new dir entry {:?}", new_dir_entry_in_parent); |
| 938 | + let now = self.time_source.get_timestamp(); |
| 939 | + let fat_type = fat.get_fat_type(); |
| 940 | + // A blank block |
| 941 | + let mut blocks = [Block::new()]; |
| 942 | + // make the "." entry |
| 943 | + let dot_entry_in_child = DirEntry { |
| 944 | + name: crate::ShortFileName::this_dir(), |
| 945 | + mtime: now, |
| 946 | + ctime: now, |
| 947 | + attributes: att, |
| 948 | + // point at ourselves |
| 949 | + cluster: new_dir_entry_in_parent.cluster, |
| 950 | + size: 0, |
| 951 | + entry_block: new_dir_start_block, |
| 952 | + entry_offset: 0, |
| 953 | + }; |
| 954 | + debug!("New dir has {:?}", dot_entry_in_child); |
| 955 | + let mut offset = 0; |
| 956 | + blocks[0][offset..offset + OnDiskDirEntry::LEN] |
| 957 | + .copy_from_slice(&dot_entry_in_child.serialize(fat_type)[..]); |
| 958 | + offset += OnDiskDirEntry::LEN; |
| 959 | + // make the ".." entry |
| 960 | + let dot_dot_entry_in_child = DirEntry { |
| 961 | + name: crate::ShortFileName::parent_dir(), |
| 962 | + mtime: now, |
| 963 | + ctime: now, |
| 964 | + attributes: att, |
| 965 | + // point at our parent |
| 966 | + cluster: match fat_type { |
| 967 | + FatType::Fat16 => { |
| 968 | + // On FAT16, indicate parent is root using Cluster(0) |
| 969 | + if parent_directory_info.cluster == ClusterId::ROOT_DIR { |
| 970 | + ClusterId::EMPTY |
| 971 | + } else { |
| 972 | + parent_directory_info.cluster |
| 973 | + } |
| 974 | + } |
| 975 | + FatType::Fat32 => parent_directory_info.cluster, |
| 976 | + }, |
| 977 | + size: 0, |
| 978 | + entry_block: new_dir_start_block, |
| 979 | + entry_offset: OnDiskDirEntry::LEN_U32, |
| 980 | + }; |
| 981 | + debug!("New dir has {:?}", dot_dot_entry_in_child); |
| 982 | + blocks[0][offset..offset + OnDiskDirEntry::LEN] |
| 983 | + .copy_from_slice(&dot_dot_entry_in_child.serialize(fat_type)[..]); |
| 984 | + |
| 985 | + self.block_device |
| 986 | + .write(&blocks, new_dir_start_block) |
| 987 | + .map_err(Error::DeviceError)?; |
| 988 | + |
| 989 | + // Now zero the rest of the cluster |
| 990 | + for b in blocks[0].iter_mut() { |
| 991 | + *b = 0; |
| 992 | + } |
| 993 | + for block in new_dir_start_block |
| 994 | + .range(BlockCount(u32::from(fat.blocks_per_cluster))) |
| 995 | + .skip(1) |
| 996 | + { |
| 997 | + self.block_device |
| 998 | + .write(&blocks, block) |
| 999 | + .map_err(Error::DeviceError)?; |
| 1000 | + } |
| 1001 | + } |
| 1002 | + }; |
| 1003 | + |
| 1004 | + Ok(()) |
| 1005 | + } |
| 1006 | + |
869 | 1007 | fn get_volume_by_id(&self, volume: RawVolume) -> Result<usize, Error<D::Error>> {
|
870 | 1008 | for (idx, v) in self.open_volumes.iter().enumerate() {
|
871 | 1009 | if v.volume_id == volume {
|
@@ -928,27 +1066,6 @@ where
|
928 | 1066 | let available = Block::LEN - block_offset;
|
929 | 1067 | Ok((block_idx, block_offset, available))
|
930 | 1068 | }
|
931 |
| - |
932 |
| - /// Writes a Directory Entry to the disk |
933 |
| - fn write_entry_to_disk( |
934 |
| - &self, |
935 |
| - fat_type: fat::FatType, |
936 |
| - entry: &DirEntry, |
937 |
| - ) -> Result<(), Error<D::Error>> { |
938 |
| - let mut blocks = [Block::new()]; |
939 |
| - self.block_device |
940 |
| - .read(&mut blocks, entry.entry_block, "read") |
941 |
| - .map_err(Error::DeviceError)?; |
942 |
| - let block = &mut blocks[0]; |
943 |
| - |
944 |
| - let start = usize::try_from(entry.entry_offset).map_err(|_| Error::ConversionError)?; |
945 |
| - block[start..start + 32].copy_from_slice(&entry.serialize(fat_type)[..]); |
946 |
| - |
947 |
| - self.block_device |
948 |
| - .write(&blocks, entry.entry_block) |
949 |
| - .map_err(Error::DeviceError)?; |
950 |
| - Ok(()) |
951 |
| - } |
952 | 1069 | }
|
953 | 1070 |
|
954 | 1071 | /// Transform mode variants (ReadWriteCreate_Or_Append) to simple modes ReadWriteAppend or
|
|
0 commit comments