From 062e4847e17d85ebc09d49c1933e9b263729165d Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 17:41:56 +0100 Subject: [PATCH 01/72] add project files --- .gitignore | 5 +++++ Cargo.toml | 8 ++++++++ rustfmt.toml | 2 ++ 3 files changed, 15 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 rustfmt.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b8f070e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +/target/ +**/*.rs.bk +Cargo.lock +.*.sw? diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ded51c2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ext2" +version = "0.1.0" +authors = ["Szymon Walter "] + +[dependencies] +rlibc = "1.0" +bitflags = "1.0" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..3450fc4 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 80 +wrap_comments = true From 568ebd3207d0c4df5051413b4bdba9f55145ebff Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 17:42:59 +0100 Subject: [PATCH 02/72] add some struct definitions --- src/block_group.rs | 29 +++++++ src/inode.rs | 124 ++++++++++++++++++++++++++ src/lib.rs | 21 ++++- src/superblock.rs | 210 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 src/block_group.rs create mode 100644 src/inode.rs create mode 100644 src/superblock.rs diff --git a/src/block_group.rs b/src/block_group.rs new file mode 100644 index 0000000..739fa32 --- /dev/null +++ b/src/block_group.rs @@ -0,0 +1,29 @@ +/// The Block Group Descriptor Table contains a descriptor for each block group +/// within the file system. The number of block groups within the file system, +/// and correspondingly, the number of entries in the Block Group Descriptor +/// Table, is described above. Each descriptor contains information regarding +/// where important data structures for that group are located. +/// +/// The (`BlockGroupDescriptor`) table is located in the block immediately +/// following the Superblock. So if the block size (determined from a field in +/// the superblock) is 1024 bytes per block, the Block Group Descriptor Table +/// will begin at block 2. For any other block size, it will begin at block 1. +/// Remember that blocks are numbered starting at 0, and that block numbers +/// don't usually correspond to physical block addresses. +#[repr(C, packed)] +pub struct BlockGroupDescriptor { + /// Block address of block usage bitmap + block_usage_addr: u32, + /// Block address of inode usage bitmap + inode_usage_addr: u32, + /// Starting block address of inode table + inode_table_block: u32, + /// Number of unallocated blocks in group + free_blocks_count: u16, + /// Number of unallocated inodes in group + free_inodes_count: u16, + /// Number of directories in group + dirs_count: u16, + #[doc(hidden)] + _reserved: [u8; 14], +} diff --git a/src/inode.rs b/src/inode.rs new file mode 100644 index 0000000..072ad45 --- /dev/null +++ b/src/inode.rs @@ -0,0 +1,124 @@ +#[repr(C, packed)] +pub struct Inode { + /// Type and Permissions (see below) + type_perm: u16, + /// User ID + uid: u16, + /// Lower 32 bits of size in bytes + size_low: u32, + /// Last Access Time (in POSIX time) + atime: u32, + /// Creation Time (in POSIX time) + ctime: u32, + /// Last Modification time (in POSIX time) + mtime: u32, + /// Deletion time (in POSIX time) + dtime: u32, + /// Group ID + gid: u16, + /// Count of hard links (directory entries) to this inode. When this + /// reaches 0, the data blocks are marked as unallocated. + hard_links: u16, + /// Count of disk sectors (not Ext2 blocks) in use by this inode, not + /// counting the actual inode structure nor directory entries linking + /// to the inode. + sectors_count: u32, + /// Flags + flags: u32, + /// Operating System Specific value #1 + _os_specific_1: u32, + /// Direct block pointers + direct_pointer: [u32; 12], + /// Singly Indirect Block Pointer (Points to a block that is a list of + /// block pointers to data) + indirect_pointer: u32, + /// Doubly Indirect Block Pointer (Points to a block that is a list of + /// block pointers to Singly Indirect Blocks) + doubly_indirect: u32, + /// Triply Indirect Block Pointer (Points to a block that is a list of + /// block pointers to Doubly Indirect Blocks) + triply_indirect: u32, + /// Generation number (Primarily used for NFS) + gen_number: u32, + /// In Ext2 version 0, this field is reserved. In version >= 1, + /// Extended attribute block (File ACL). + ext_attribute_block: u32, + /// In Ext2 version 0, this field is reserved. In version >= 1, Upper + /// 32 bits of file size (if feature bit set) if it's a file, + /// Directory ACL if it's a directory + size_high: u32, + /// Block address of fragment + frag_block_addr: u32, + /// Operating System Specific Value #2 + _os_specific_2: [u8; 12], +} + +bitflags! { + pub struct TypePerm: u16 { + /// FIFO + const FIFO = 0x1000; + /// Character device + const CHAR_DEVICE = 0x2000; + /// Directory + const DIRECTORY = 0x4000; + /// Block device + const BLOCK_DEVICE = 0x6000; + /// Regular file + const FILE = 0x8000; + /// Symbolic link + const SYMLINK = 0xA000; + /// Unix socket + const SOCKET = 0xC000; + /// Other—execute permission + const O_EXEC = 0x001; + /// Other—write permission + const O_WRITE = 0x002; + /// Other—read permission + const O_READ = 0x004; + /// Group—execute permission + const G_EXEC = 0x008; + /// Group—write permission + const G_WRITE = 0x010; + /// Group—read permission + const G_READ = 0x020; + /// User—execute permission + const U_EXEC = 0x040; + /// User—write permission + const U_WRITE = 0x080; + /// User—read permission + const U_READ = 0x100; + /// Sticky Bit + const STICKY = 0x200; + /// Set group ID + const SET_GID = 0x400; + /// Set user ID + const SET_UID = 0x800; + } +} + +bitflags! { + pub struct InodeFlags: u32 { + /// Secure deletion (not used) + const SECURE_DEL = 0x00000001; + /// Keep a copy of data when deleted (not used) + const KEEP_COPY = 0x00000002; + /// File compression (not used) + const COMPRESSION = 0x00000004; + /// Synchronous updates—new data is written immediately to disk + const SYNC_UPDATE = 0x00000008; + /// Immutable file (content cannot be changed) + const IMMUTABLE = 0x00000010; + /// Append only + const APPEND_ONLY = 0x00000020; + /// File is not included in 'dump' command + const NODUMP = 0x00000040; + /// Last accessed time should not updated + const DONT_ATIME = 0x00000080; + /// Hash indexed directory + const HASH_DIR = 0x00010000; + /// AFS directory + const AFS_DIR = 0x00020000; + /// Journal file data + const JOURNAL_DATA = 0x00040000; + } +} diff --git a/src/lib.rs b/src/lib.rs index a6cc7cf..4bdee73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,23 @@ #![cfg_attr(not(test), no_std)] +#[macro_use] +extern crate bitflags; + +pub mod superblock; +pub mod block_group; +pub mod inode; + #[cfg(test)] -mod tests {} +mod tests { + use super::superblock::*; + use super::block_group::*; + use super::inode::*; + + #[test] + fn sizes() { + use std::mem::size_of; + assert_eq!(size_of::(), 1024); + assert_eq!(size_of::(), 32); + assert_eq!(size_of::(), 128); + } +} diff --git a/src/superblock.rs b/src/superblock.rs new file mode 100644 index 0000000..258e8b2 --- /dev/null +++ b/src/superblock.rs @@ -0,0 +1,210 @@ +/// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a +/// volume +pub const EXT2_MAGIC: u16 = 0xef53; + +/// Filesystem is free of errors +pub const FS_CLEAN: u16 = 1; +/// Filesystem has errors +pub const FS_ERR: u16 = 2; + +/// Ignore errors +pub const ERR_IGNORE: u16 = 1; +/// Remount as read-only on error +pub const ERR_RONLY: u16 = 2; +/// Panic on error +pub const ERR_PANIC: u16 = 3; + +/// Creator OS is Linux +pub const OS_LINUX: u32 = 0; +/// Creator OS is Hurd +pub const OS_HURD: u32 = 1; +/// Creator OS is Masix +pub const OS_MASIX: u32 = 2; +/// Creator OS is FreeBSD +pub const OS_FREEBSD: u32 = 3; +/// Creator OS is a BSD4.4-Lite derivative +pub const OS_LITE: u32 = 4; + +/// The Superblock contains all information about the layout of the file system +/// and possibly contains other important information like what optional +/// features were used to create the file system. +/// +/// The Superblock is always located at byte 1024 from the beginning of the +/// volume and is exactly 1024 bytes in length. For example, if the disk uses +/// 512 byte sectors, the Superblock will begin at LBA 2 and will occupy all of +/// sector 2 and 3. +#[repr(C, packed)] +pub struct Superblock { + // taken from https://wiki.osdev.org/Ext2 + /// Total number of inodes in file system + inodes_count: u32, + /// Total number of blocks in file system + blocks_count: u32, + /// Number of blocks reserved for superuser (see offset 80) + r_blocks_count: u32, + /// Total number of unallocated blocks + free_blocks_count: u32, + /// Total number of unallocated inodes + free_inodes_count: u32, + /// Block number of the block containing the superblock + first_data_block: u32, + /// log2 (block size) - 10. (In other words, the number to shift 1,024 + /// to the left by to obtain the block size) + log_block_size: u32, + /// log2 (fragment size) - 10. (In other words, the number to shift + /// 1,024 to the left by to obtain the fragment size) + log_frag_size: i32, + /// Number of blocks in each block group + blocks_per_group: u32, + /// Number of fragments in each block group + frags_per_group: u32, + /// Number of inodes in each block group + inodes_per_group: u32, + /// Last mount time (in POSIX time) + mtime: u32, + /// Last written time (in POSIX time) + wtime: u32, + /// Number of times the volume has been mounted since its last + /// consistency check (fsck) + mnt_count: u16, + /// Number of mounts allowed before a consistency check (fsck) must be + /// done + max_mnt_count: i16, + /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 + /// on a volume + magic: u16, + /// File system state (see `FS_CLEAN` and `FS_ERR`) + state: u16, + /// What to do when an error is detected (see `ERR_IGNORE`, `ERR_RONLY` and + /// `ERR_PANIC`) + errors: u16, + /// Minor portion of version (combine with Major portion below to + /// construct full version field) + rev_minor: u16, + /// POSIX time of last consistency check (fsck) + lastcheck: u32, + /// Interval (in POSIX time) between forced consistency checks (fsck) + checkinterval: u32, + /// Operating system ID from which the filesystem on this volume was + /// created + creator_os: u32, + /// Major portion of version (combine with Minor portion above to + /// construct full version field) + rev_major: u32, + /// User ID that can use reserved blocks + block_uid: u16, + /// Group ID that can use reserved blocks + block_gid: u16, + + /// First non-reserved inode in file system. + first_inode: u32, + /// Size of each inode structure in bytes. + inode_size: u16, + /// Block group that this superblock is part of (if backup copy) + block_group: u16, + /// Optional features present (features that are not required to read + /// or write, but usually result in a performance increase) + features_opt: FeaturesOptional, + /// Required features present (features that are required to be + /// supported to read or write) + features_req: FeaturesRequired, + /// Features that if not supported, the volume must be mounted + /// read-only) + features_ronly: FeaturesROnly, + /// File system ID (what is output by blkid) + fs_id: [u8; 16], + /// Volume name (C-style string: characters terminated by a 0 byte) + volume_name: [u8; 16], + /// Path volume was last mounted to (C-style string: characters + /// terminated by a 0 byte) + last_mnt_path: [u8; 64], + /// Compression algorithms used (see Required features above) + compression: u32, + /// Number of blocks to preallocate for files + prealloc_blocks_files: u8, + /// Number of blocks to preallocate for directories + prealloc_blocks_dirs: u8, + #[doc(hidden)] + _unused: [u8; 2], + /// Journal ID (same style as the File system ID above) + journal_id: [u8; 16], + /// Journal inode + journal_inode: u32, + /// Journal device + journal_dev: u32, + /// Head of orphan inode list + journal_orphan_head: u32, + #[doc(hidden)] + _reserved: [u8; 788], +} + +impl Superblock { + #[inline] + pub fn block_size(&self) -> usize { + 1024 << self.log_block_size + } + + #[inline] + pub fn frag_size(&self) -> usize { + 1024 << self.log_frag_size + } + + pub fn block_group_count(&self) -> Result { + let blocks_mod = self.blocks_count % self.blocks_per_group; + let inodes_mod = self.inodes_count % self.inodes_per_group; + let blocks_inc = if blocks_mod == 0 { 0 } else { 1 }; + let inodes_inc = if inodes_mod == 0 { 0 } else { 1 }; + let by_blocks = self.blocks_count / self.blocks_per_group + blocks_inc; + let by_inodes = self.inodes_count / self.inodes_per_group + inodes_inc; + if by_blocks == by_inodes { + Ok(by_blocks) + } else { + Err((by_blocks, by_inodes)) + } + } +} + +bitflags! { + /// Optional features + pub struct FeaturesOptional: u32 { + /// Preallocate some number of (contiguous?) blocks (see + /// `Superblock::prealloc_blocks_dirs`) to a directory when creating a new one + const PREALLOCATE = 0x0001; + /// AFS server inodes exist + const AFS = 0x0002; + /// File system has a journal (Ext3) + const JOURNAL = 0x0004; + /// Inodes have extended attributes + const EXTENDED_INODE = 0x0008; + /// File system can resize itself for larger partitions + const SELF_RESIZE = 0x0010; + /// Directories use hash index + const HASH_INDEX = 0x0020; + } +} + +bitflags! { + /// Required features. If these are not supported; can't mount + pub struct FeaturesRequired: u32 { + /// Compression is used + const REQ_COMPRESSION = 0x0001; + /// Directory entries contain a type field + const REQ_DIRECTORY_TYPE = 0x0002; + /// File system needs to replay its journal + const REQ_REPLAY_JOURNAL = 0x0004; + /// File system uses a journal device + const REQ_JOURNAL_DEVICE = 0x0008; + } +} + +bitflags! { + /// ROnly features. If these are not supported; remount as read-only + pub struct FeaturesROnly: u32 { + /// Sparse superblocks and group descriptor tables + const RONLY_SPARSE = 0x0001; + /// File system uses a 64-bit file size + const RONLY_FILE_SIZE_64 = 0x0002; + /// Directory contents are stored in the form of a Binary Tree + const RONLY_BTREE_DIRECTORY = 0x0004; + } +} From 41f6ea196760370d957890113096a5ceba90e3ff Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 18:11:58 +0100 Subject: [PATCH 03/72] add `error` module --- src/error.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..a7caea7 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,22 @@ +/// Wrapper around the raw `ErrorKind` +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Error { + kind: ErrorKind, +} + +impl Error { + pub fn from_kind(kind: ErrorKind) -> Error { + Error { kind } + } + + pub fn kind(&self) -> ErrorKind { + self.kind + } +} + +/// The set of all possible errors +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum ErrorKind { + BadMagic, + OutOfBounds, +} From 71a97a9e4dfb00357cc5f0fa581e0639f6bb73d5 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 18:12:10 +0100 Subject: [PATCH 04/72] add `error` module --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 4bdee73..02ab7a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; +pub mod error; pub mod superblock; pub mod block_group; pub mod inode; From b211d958079e55dedc90391162f8f0952988cf27 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 18:34:26 +0100 Subject: [PATCH 05/72] replace Error/ErroKind pair with just `enum Error` --- src/error.rs | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/error.rs b/src/error.rs index a7caea7..d6aee4f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,22 +1,7 @@ -/// Wrapper around the raw `ErrorKind` -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Error { - kind: ErrorKind, -} - -impl Error { - pub fn from_kind(kind: ErrorKind) -> Error { - Error { kind } - } - - pub fn kind(&self) -> ErrorKind { - self.kind - } -} - /// The set of all possible errors #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum ErrorKind { - BadMagic, - OutOfBounds, +pub enum Error { + BadMagic(u16), + OutOfBounds(usize), + BadBlockGroupCount(u32, u32), } From 096cc865a434a016db15d6e9fdfa717af49280cd Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 18:38:54 +0100 Subject: [PATCH 06/72] add locating `Superblock` and `[BlockGroupDescriptor]` --- src/block_group.rs | 1 + src/inode.rs | 1 + src/superblock.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/src/block_group.rs b/src/block_group.rs index 739fa32..5f0d49f 100644 --- a/src/block_group.rs +++ b/src/block_group.rs @@ -11,6 +11,7 @@ /// Remember that blocks are numbered starting at 0, and that block numbers /// don't usually correspond to physical block addresses. #[repr(C, packed)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct BlockGroupDescriptor { /// Block address of block usage bitmap block_usage_addr: u32, diff --git a/src/inode.rs b/src/inode.rs index 072ad45..c1f4792 100644 --- a/src/inode.rs +++ b/src/inode.rs @@ -1,4 +1,5 @@ #[repr(C, packed)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Inode { /// Type and Permissions (see below) type_perm: u16, diff --git a/src/superblock.rs b/src/superblock.rs index 258e8b2..6fc818a 100644 --- a/src/superblock.rs +++ b/src/superblock.rs @@ -1,3 +1,16 @@ +#[cfg(test)] +use std::mem; +#[cfg(test)] +use std::slice; + +#[cfg(not(test))] +use core::mem; +#[cfg(not(test))] +use core::slice; + +use error::Error; +use block_group::BlockGroupDescriptor; + /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a /// volume pub const EXT2_MAGIC: u16 = 0xef53; @@ -34,6 +47,7 @@ pub const OS_LITE: u32 = 4; /// 512 byte sectors, the Superblock will begin at LBA 2 and will occupy all of /// sector 2 and 3. #[repr(C, packed)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Superblock { // taken from https://wiki.osdev.org/Ext2 /// Total number of inodes in file system @@ -139,6 +153,50 @@ pub struct Superblock { } impl Superblock { + pub fn find<'a>( + haystack: &'a mut [u8], + ) -> Result<&'a mut Superblock, Error> { + let offset = 1024; + let end = offset + mem::size_of::(); + if haystack.len() < end { + return Err(Error::OutOfBounds(end)); + } + + let superblock: &mut Superblock = unsafe { + let ptr = + haystack.as_ptr().offset(offset as isize) as *mut Superblock; + ptr.as_mut().unwrap() + }; + + if superblock.magic != EXT2_MAGIC { + Err(Error::BadMagic(superblock.magic)) + } else { + Ok(superblock) + } + } + + pub fn find_block_table<'a>( + &self, + haystack: &'a mut [u8], + ) -> Result<&'a mut [BlockGroupDescriptor], Error> { + let count = self.block_group_count() + .map_err(|(a, b)| Error::BadBlockGroupCount(a, b))? + as usize; + + let offset = 2048; + let end = offset + count * mem::size_of::(); + if haystack.len() < end { + return Err(Error::OutOfBounds(end)); + } + + let ptr = unsafe { + haystack.as_ptr().offset(offset as isize) + as *mut BlockGroupDescriptor + }; + let slice = unsafe { slice::from_raw_parts_mut(ptr, count) }; + Ok(slice) + } + #[inline] pub fn block_size(&self) -> usize { 1024 << self.log_block_size From c5f0edeabc4d10ce968c96d3aa7d3d537d1e0e60 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 19:01:31 +0100 Subject: [PATCH 07/72] minor fixes --- src/block_group.rs | 1 - src/inode.rs | 1 - src/superblock.rs | 28 ++++++++++++++++++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/block_group.rs b/src/block_group.rs index 5f0d49f..739fa32 100644 --- a/src/block_group.rs +++ b/src/block_group.rs @@ -11,7 +11,6 @@ /// Remember that blocks are numbered starting at 0, and that block numbers /// don't usually correspond to physical block addresses. #[repr(C, packed)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct BlockGroupDescriptor { /// Block address of block usage bitmap block_usage_addr: u32, diff --git a/src/inode.rs b/src/inode.rs index c1f4792..072ad45 100644 --- a/src/inode.rs +++ b/src/inode.rs @@ -1,5 +1,4 @@ #[repr(C, packed)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Inode { /// Type and Permissions (see below) type_perm: u16, diff --git a/src/superblock.rs b/src/superblock.rs index 6fc818a..269b98b 100644 --- a/src/superblock.rs +++ b/src/superblock.rs @@ -47,7 +47,6 @@ pub const OS_LITE: u32 = 4; /// 512 byte sectors, the Superblock will begin at LBA 2 and will occupy all of /// sector 2 and 3. #[repr(C, packed)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Superblock { // taken from https://wiki.osdev.org/Ext2 /// Total number of inodes in file system @@ -163,8 +162,8 @@ impl Superblock { } let superblock: &mut Superblock = unsafe { - let ptr = - haystack.as_ptr().offset(offset as isize) as *mut Superblock; + let ptr = haystack.as_mut_ptr().offset(offset as isize) + as *mut Superblock; ptr.as_mut().unwrap() }; @@ -190,7 +189,7 @@ impl Superblock { } let ptr = unsafe { - haystack.as_ptr().offset(offset as isize) + haystack.as_mut_ptr().offset(offset as isize) as *mut BlockGroupDescriptor }; let slice = unsafe { slice::from_raw_parts_mut(ptr, count) }; @@ -266,3 +265,24 @@ bitflags! { const RONLY_BTREE_DIRECTORY = 0x0004; } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn find() { + let mut buffer = vec![0_u8; 4096]; + let addr = &buffer[1024] as *const _ as usize; + // magic + buffer[1024 + 56] = EXT2_MAGIC as u8; + buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; + let superblock = Superblock::find(&mut buffer); + assert!( + superblock.is_ok(), + "Err({:?})", + superblock.err().unwrap_or_else(|| unreachable!()), + ); + assert_eq!(superblock.unwrap() as *const _ as usize, addr); + } +} From e0163e2b9ebac3866655e5d19f3b862f0da3ee7c Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 19:04:57 +0100 Subject: [PATCH 08/72] add offset argument to `find_*` functions --- src/superblock.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/superblock.rs b/src/superblock.rs index 269b98b..62ca518 100644 --- a/src/superblock.rs +++ b/src/superblock.rs @@ -154,8 +154,9 @@ pub struct Superblock { impl Superblock { pub fn find<'a>( haystack: &'a mut [u8], + offset: isize, ) -> Result<&'a mut Superblock, Error> { - let offset = 1024; + let offset = (1024 + offset) as usize; let end = offset + mem::size_of::(); if haystack.len() < end { return Err(Error::OutOfBounds(end)); @@ -177,12 +178,13 @@ impl Superblock { pub fn find_block_table<'a>( &self, haystack: &'a mut [u8], + offset: isize, ) -> Result<&'a mut [BlockGroupDescriptor], Error> { let count = self.block_group_count() .map_err(|(a, b)| Error::BadBlockGroupCount(a, b))? as usize; - let offset = 2048; + let offset = (2048 + offset) as usize; let end = offset + count * mem::size_of::(); if haystack.len() < end { return Err(Error::OutOfBounds(end)); @@ -277,7 +279,7 @@ mod tests { // magic buffer[1024 + 56] = EXT2_MAGIC as u8; buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; - let superblock = Superblock::find(&mut buffer); + let superblock = Superblock::find(&mut buffer, 0); assert!( superblock.is_ok(), "Err({:?})", From a19d8b205a3bc2afc9eb09e1a1fae49866d8ffcd Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 19:06:50 +0100 Subject: [PATCH 09/72] add inode doc comment (copied from osdev) --- src/inode.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/inode.rs b/src/inode.rs index 072ad45..1ce8fc7 100644 --- a/src/inode.rs +++ b/src/inode.rs @@ -1,3 +1,10 @@ +/// An inode is a structure on the disk that represents a file, directory, +/// symbolic link, etc. Inodes do not contain the data of the file / directory / +/// etc. that they represent. Instead, they link to the blocks that actually +/// contain the data. This lets the inodes themselves have a well-defined size +/// which lets them be placed in easily indexed arrays. Each block group has an +/// array of inodes it is responsible for, and conversely every inode within a +/// file system belongs to one of such tables (and one of such block groups). #[repr(C, packed)] pub struct Inode { /// Type and Permissions (see below) From 0ffd97d29a9fb3906bdee621b357460b7a12cb25 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 19:29:49 +0100 Subject: [PATCH 10/72] move `find_descriptor_table` to `impl BlockGroupDescriptor` --- src/block_group.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++ src/superblock.rs | 28 ------------------------ 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/block_group.rs b/src/block_group.rs index 739fa32..14974e1 100644 --- a/src/block_group.rs +++ b/src/block_group.rs @@ -1,3 +1,15 @@ +#[cfg(test)] +use std::mem; +#[cfg(test)] +use std::slice; + +#[cfg(not(test))] +use core::mem; +#[cfg(not(test))] +use core::slice; + +use error::Error; + /// The Block Group Descriptor Table contains a descriptor for each block group /// within the file system. The number of block groups within the file system, /// and correspondingly, the number of entries in the Block Group Descriptor @@ -27,3 +39,44 @@ pub struct BlockGroupDescriptor { #[doc(hidden)] _reserved: [u8; 14], } + +impl BlockGroupDescriptor { + pub fn find_descriptor_table<'a>( + haystack: &'a mut [u8], + offset: isize, + count: usize, + ) -> Result<&'a mut [BlockGroupDescriptor], Error> { + let offset = (2048 + offset) as usize; + let end = offset + count * mem::size_of::(); + if haystack.len() < end { + return Err(Error::OutOfBounds(end)); + } + + let ptr = unsafe { + haystack.as_mut_ptr().offset(offset as isize) + as *mut BlockGroupDescriptor + }; + let slice = unsafe { slice::from_raw_parts_mut(ptr, count) }; + Ok(slice) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn find() { + let mut buffer = vec![0_u8; 4096]; + let addr = &buffer[2048] as *const _ as usize; + // magic + let table = + BlockGroupDescriptor::find_descriptor_table(&mut buffer, 0, 0); + assert!( + table.is_ok(), + "Err({:?})", + table.err().unwrap_or_else(|| unreachable!()), + ); + assert_eq!(table.unwrap().as_ptr() as usize, addr); + } +} diff --git a/src/superblock.rs b/src/superblock.rs index 62ca518..bb59bfd 100644 --- a/src/superblock.rs +++ b/src/superblock.rs @@ -1,15 +1,10 @@ #[cfg(test)] use std::mem; -#[cfg(test)] -use std::slice; #[cfg(not(test))] use core::mem; -#[cfg(not(test))] -use core::slice; use error::Error; -use block_group::BlockGroupDescriptor; /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a /// volume @@ -175,29 +170,6 @@ impl Superblock { } } - pub fn find_block_table<'a>( - &self, - haystack: &'a mut [u8], - offset: isize, - ) -> Result<&'a mut [BlockGroupDescriptor], Error> { - let count = self.block_group_count() - .map_err(|(a, b)| Error::BadBlockGroupCount(a, b))? - as usize; - - let offset = (2048 + offset) as usize; - let end = offset + count * mem::size_of::(); - if haystack.len() < end { - return Err(Error::OutOfBounds(end)); - } - - let ptr = unsafe { - haystack.as_mut_ptr().offset(offset as isize) - as *mut BlockGroupDescriptor - }; - let slice = unsafe { slice::from_raw_parts_mut(ptr, count) }; - Ok(slice) - } - #[inline] pub fn block_size(&self) -> usize { 1024 << self.log_block_size From 0c750fbdda7b3b5484665aefee4f0c41b32e1647 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 20:35:55 +0100 Subject: [PATCH 11/72] move raw packed struct to `sys` module --- src/lib.rs | 10 ++--- src/{ => sys}/block_group.rs | 12 +++--- src/{ => sys}/inode.rs | 42 +++++++++--------- src/sys/mod.rs | 3 ++ src/{ => sys}/superblock.rs | 82 ++++++++++++++++++------------------ 5 files changed, 75 insertions(+), 74 deletions(-) rename src/{ => sys}/block_group.rs (93%) rename src/{ => sys}/inode.rs (88%) create mode 100644 src/sys/mod.rs rename src/{ => sys}/superblock.rs (87%) diff --git a/src/lib.rs b/src/lib.rs index 02ab7a0..deaeaa1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,15 +4,13 @@ extern crate bitflags; pub mod error; -pub mod superblock; -pub mod block_group; -pub mod inode; +pub mod sys; #[cfg(test)] mod tests { - use super::superblock::*; - use super::block_group::*; - use super::inode::*; + use sys::superblock::*; + use sys::block_group::*; + use sys::inode::*; #[test] fn sizes() { diff --git a/src/block_group.rs b/src/sys/block_group.rs similarity index 93% rename from src/block_group.rs rename to src/sys/block_group.rs index 14974e1..eb277b9 100644 --- a/src/block_group.rs +++ b/src/sys/block_group.rs @@ -25,17 +25,17 @@ use error::Error; #[repr(C, packed)] pub struct BlockGroupDescriptor { /// Block address of block usage bitmap - block_usage_addr: u32, + pub block_usage_addr: u32, /// Block address of inode usage bitmap - inode_usage_addr: u32, + pub inode_usage_addr: u32, /// Starting block address of inode table - inode_table_block: u32, + pub inode_table_block: u32, /// Number of unallocated blocks in group - free_blocks_count: u16, + pub free_blocks_count: u16, /// Number of unallocated inodes in group - free_inodes_count: u16, + pub free_inodes_count: u16, /// Number of directories in group - dirs_count: u16, + pub dirs_count: u16, #[doc(hidden)] _reserved: [u8; 14], } diff --git a/src/inode.rs b/src/sys/inode.rs similarity index 88% rename from src/inode.rs rename to src/sys/inode.rs index 1ce8fc7..d5cc47c 100644 --- a/src/inode.rs +++ b/src/sys/inode.rs @@ -8,56 +8,56 @@ #[repr(C, packed)] pub struct Inode { /// Type and Permissions (see below) - type_perm: u16, + pub type_perm: u16, /// User ID - uid: u16, + pub uid: u16, /// Lower 32 bits of size in bytes - size_low: u32, + pub size_low: u32, /// Last Access Time (in POSIX time) - atime: u32, + pub atime: u32, /// Creation Time (in POSIX time) - ctime: u32, + pub ctime: u32, /// Last Modification time (in POSIX time) - mtime: u32, + pub mtime: u32, /// Deletion time (in POSIX time) - dtime: u32, + pub dtime: u32, /// Group ID - gid: u16, + pub gid: u16, /// Count of hard links (directory entries) to this inode. When this /// reaches 0, the data blocks are marked as unallocated. - hard_links: u16, + pub hard_links: u16, /// Count of disk sectors (not Ext2 blocks) in use by this inode, not /// counting the actual inode structure nor directory entries linking /// to the inode. - sectors_count: u32, + pub sectors_count: u32, /// Flags - flags: u32, + pub flags: u32, /// Operating System Specific value #1 - _os_specific_1: u32, + pub _os_specific_1: [u8; 4], /// Direct block pointers - direct_pointer: [u32; 12], + pub direct_pointer: [u32; 12], /// Singly Indirect Block Pointer (Points to a block that is a list of /// block pointers to data) - indirect_pointer: u32, + pub indirect_pointer: u32, /// Doubly Indirect Block Pointer (Points to a block that is a list of /// block pointers to Singly Indirect Blocks) - doubly_indirect: u32, + pub doubly_indirect: u32, /// Triply Indirect Block Pointer (Points to a block that is a list of /// block pointers to Doubly Indirect Blocks) - triply_indirect: u32, + pub triply_indirect: u32, /// Generation number (Primarily used for NFS) - gen_number: u32, + pub gen_number: u32, /// In Ext2 version 0, this field is reserved. In version >= 1, /// Extended attribute block (File ACL). - ext_attribute_block: u32, + pub ext_attribute_block: u32, /// In Ext2 version 0, this field is reserved. In version >= 1, Upper /// 32 bits of file size (if feature bit set) if it's a file, /// Directory ACL if it's a directory - size_high: u32, + pub size_high: u32, /// Block address of fragment - frag_block_addr: u32, + pub frag_block_addr: u32, /// Operating System Specific Value #2 - _os_specific_2: [u8; 12], + pub _os_specific_2: [u8; 12], } bitflags! { diff --git a/src/sys/mod.rs b/src/sys/mod.rs new file mode 100644 index 0000000..91552bd --- /dev/null +++ b/src/sys/mod.rs @@ -0,0 +1,3 @@ +pub mod superblock; +pub mod block_group; +pub mod inode; diff --git a/src/superblock.rs b/src/sys/superblock.rs similarity index 87% rename from src/superblock.rs rename to src/sys/superblock.rs index bb59bfd..93748a4 100644 --- a/src/superblock.rs +++ b/src/sys/superblock.rs @@ -45,103 +45,103 @@ pub const OS_LITE: u32 = 4; pub struct Superblock { // taken from https://wiki.osdev.org/Ext2 /// Total number of inodes in file system - inodes_count: u32, + pub inodes_count: u32, /// Total number of blocks in file system - blocks_count: u32, + pub blocks_count: u32, /// Number of blocks reserved for superuser (see offset 80) - r_blocks_count: u32, + pub r_blocks_count: u32, /// Total number of unallocated blocks - free_blocks_count: u32, + pub free_blocks_count: u32, /// Total number of unallocated inodes - free_inodes_count: u32, + pub free_inodes_count: u32, /// Block number of the block containing the superblock - first_data_block: u32, + pub first_data_block: u32, /// log2 (block size) - 10. (In other words, the number to shift 1,024 /// to the left by to obtain the block size) - log_block_size: u32, + pub log_block_size: u32, /// log2 (fragment size) - 10. (In other words, the number to shift /// 1,024 to the left by to obtain the fragment size) - log_frag_size: i32, + pub log_frag_size: i32, /// Number of blocks in each block group - blocks_per_group: u32, + pub blocks_per_group: u32, /// Number of fragments in each block group - frags_per_group: u32, + pub frags_per_group: u32, /// Number of inodes in each block group - inodes_per_group: u32, + pub inodes_per_group: u32, /// Last mount time (in POSIX time) - mtime: u32, + pub mtime: u32, /// Last written time (in POSIX time) - wtime: u32, + pub wtime: u32, /// Number of times the volume has been mounted since its last /// consistency check (fsck) - mnt_count: u16, + pub mnt_count: u16, /// Number of mounts allowed before a consistency check (fsck) must be /// done - max_mnt_count: i16, + pub max_mnt_count: i16, /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 /// on a volume - magic: u16, + pub magic: u16, /// File system state (see `FS_CLEAN` and `FS_ERR`) - state: u16, + pub state: u16, /// What to do when an error is detected (see `ERR_IGNORE`, `ERR_RONLY` and /// `ERR_PANIC`) - errors: u16, + pub errors: u16, /// Minor portion of version (combine with Major portion below to /// construct full version field) - rev_minor: u16, + pub rev_minor: u16, /// POSIX time of last consistency check (fsck) - lastcheck: u32, + pub lastcheck: u32, /// Interval (in POSIX time) between forced consistency checks (fsck) - checkinterval: u32, + pub checkinterval: u32, /// Operating system ID from which the filesystem on this volume was /// created - creator_os: u32, + pub creator_os: u32, /// Major portion of version (combine with Minor portion above to /// construct full version field) - rev_major: u32, + pub rev_major: u32, /// User ID that can use reserved blocks - block_uid: u16, + pub block_uid: u16, /// Group ID that can use reserved blocks - block_gid: u16, + pub block_gid: u16, /// First non-reserved inode in file system. - first_inode: u32, + pub first_inode: u32, /// Size of each inode structure in bytes. - inode_size: u16, + pub inode_size: u16, /// Block group that this superblock is part of (if backup copy) - block_group: u16, + pub block_group: u16, /// Optional features present (features that are not required to read /// or write, but usually result in a performance increase) - features_opt: FeaturesOptional, + pub features_opt: FeaturesOptional, /// Required features present (features that are required to be /// supported to read or write) - features_req: FeaturesRequired, + pub features_req: FeaturesRequired, /// Features that if not supported, the volume must be mounted /// read-only) - features_ronly: FeaturesROnly, + pub features_ronly: FeaturesROnly, /// File system ID (what is output by blkid) - fs_id: [u8; 16], + pub fs_id: [u8; 16], /// Volume name (C-style string: characters terminated by a 0 byte) - volume_name: [u8; 16], + pub volume_name: [u8; 16], /// Path volume was last mounted to (C-style string: characters /// terminated by a 0 byte) - last_mnt_path: [u8; 64], + pub last_mnt_path: [u8; 64], /// Compression algorithms used (see Required features above) - compression: u32, + pub compression: u32, /// Number of blocks to preallocate for files - prealloc_blocks_files: u8, + pub prealloc_blocks_files: u8, /// Number of blocks to preallocate for directories - prealloc_blocks_dirs: u8, + pub prealloc_blocks_dirs: u8, #[doc(hidden)] _unused: [u8; 2], /// Journal ID (same style as the File system ID above) - journal_id: [u8; 16], + pub journal_id: [u8; 16], /// Journal inode - journal_inode: u32, + pub journal_inode: u32, /// Journal device - journal_dev: u32, + pub journal_dev: u32, /// Head of orphan inode list - journal_orphan_head: u32, + pub journal_orphan_head: u32, #[doc(hidden)] _reserved: [u8; 788], } From a9d5677c579959ce20d7e0224eeba25026d04fa6 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Sun, 18 Mar 2018 20:38:48 +0100 Subject: [PATCH 12/72] make `find*` functions unsafe --- src/sys/block_group.rs | 2 +- src/sys/superblock.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index eb277b9..14bff9b 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -41,7 +41,7 @@ pub struct BlockGroupDescriptor { } impl BlockGroupDescriptor { - pub fn find_descriptor_table<'a>( + pub unsafe fn find_descriptor_table<'a>( haystack: &'a mut [u8], offset: isize, count: usize, diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 93748a4..1a26b9b 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -147,7 +147,7 @@ pub struct Superblock { } impl Superblock { - pub fn find<'a>( + pub unsafe fn find<'a>( haystack: &'a mut [u8], offset: isize, ) -> Result<&'a mut Superblock, Error> { From 43e400ef0861171515a36717469fbdc76b17b428 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 00:01:21 +0100 Subject: [PATCH 13/72] fix again --- src/sys/block_group.rs | 20 ++++++-------------- src/sys/superblock.rs | 8 ++------ 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 14bff9b..70c6ab2 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -1,11 +1,4 @@ -#[cfg(test)] -use std::mem; -#[cfg(test)] -use std::slice; - -#[cfg(not(test))] use core::mem; -#[cfg(not(test))] use core::slice; use error::Error; @@ -52,11 +45,9 @@ impl BlockGroupDescriptor { return Err(Error::OutOfBounds(end)); } - let ptr = unsafe { - haystack.as_mut_ptr().offset(offset as isize) - as *mut BlockGroupDescriptor - }; - let slice = unsafe { slice::from_raw_parts_mut(ptr, count) }; + let ptr = haystack.as_mut_ptr().offset(offset as isize) + as *mut BlockGroupDescriptor; + let slice = slice::from_raw_parts_mut(ptr, count); Ok(slice) } } @@ -70,8 +61,9 @@ mod tests { let mut buffer = vec![0_u8; 4096]; let addr = &buffer[2048] as *const _ as usize; // magic - let table = - BlockGroupDescriptor::find_descriptor_table(&mut buffer, 0, 0); + let table = unsafe { + BlockGroupDescriptor::find_descriptor_table(&mut buffer, 0, 0) + }; assert!( table.is_ok(), "Err({:?})", diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 1a26b9b..e89a66c 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -1,7 +1,3 @@ -#[cfg(test)] -use std::mem; - -#[cfg(not(test))] use core::mem; use error::Error; @@ -157,7 +153,7 @@ impl Superblock { return Err(Error::OutOfBounds(end)); } - let superblock: &mut Superblock = unsafe { + let superblock: &mut Superblock = { let ptr = haystack.as_mut_ptr().offset(offset as isize) as *mut Superblock; ptr.as_mut().unwrap() @@ -251,7 +247,7 @@ mod tests { // magic buffer[1024 + 56] = EXT2_MAGIC as u8; buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; - let superblock = Superblock::find(&mut buffer, 0); + let superblock = unsafe { Superblock::find(&mut buffer, 0) }; assert!( superblock.is_ok(), "Err({:?})", From e91533440ed954891d2d7f99f04c19f8a6dec994 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 00:02:31 +0100 Subject: [PATCH 14/72] add smart, delayed update `Buffer` --- src/buffer/length.rs | 93 +++++++++++++++ src/buffer/mod.rs | 264 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 8 ++ 3 files changed, 365 insertions(+) create mode 100644 src/buffer/length.rs create mode 100644 src/buffer/mod.rs diff --git a/src/buffer/length.rs b/src/buffer/length.rs new file mode 100644 index 0000000..e198377 --- /dev/null +++ b/src/buffer/length.rs @@ -0,0 +1,93 @@ +use core::fmt::{self, Debug, Display}; +use core::cmp::Ordering; + +#[derive(Clone, Copy, Debug, Hash)] +pub enum Length { + Unbounded, + Bounded(usize), +} + +impl Length { + pub fn try_len(&self) -> Option { + match *self { + Length::Unbounded => None, + Length::Bounded(n) => Some(n), + } + } + + pub unsafe fn len(&self) -> usize { + match *self { + Length::Unbounded => { + panic!("attempt to convert `Length::Unbounded` to `usize`") + } + Length::Bounded(n) => n, + } + } + + pub fn is_bounded(&self) -> bool { + match *self { + Length::Unbounded => false, + Length::Bounded(_) => true, + } + } +} + +impl Display for Length { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(self, f) + } +} + +impl PartialEq for Length { + fn eq(&self, rhs: &Length) -> bool { + match (*self, *rhs) { + (Length::Unbounded, _) => false, + (_, Length::Unbounded) => false, + (Length::Bounded(a), Length::Bounded(ref b)) => a.eq(b), + } + } + + fn ne(&self, rhs: &Length) -> bool { + match (*self, *rhs) { + (Length::Unbounded, _) => false, + (_, Length::Unbounded) => false, + (Length::Bounded(a), Length::Bounded(ref b)) => a.ne(b), + } + } +} + +impl PartialEq for Length { + fn eq(&self, rhs: &usize) -> bool { + match *self { + Length::Unbounded => false, + Length::Bounded(n) => n.eq(rhs), + } + } + + fn ne(&self, rhs: &usize) -> bool { + match *self { + Length::Unbounded => false, + Length::Bounded(n) => n.eq(rhs), + } + } +} + +impl PartialOrd for Length { + fn partial_cmp(&self, rhs: &Length) -> Option { + match (*self, *rhs) { + (Length::Unbounded, Length::Unbounded) => None, + (Length::Unbounded, _) => Some(Ordering::Greater), + (_, Length::Unbounded) => Some(Ordering::Less), + (Length::Bounded(a), Length::Bounded(ref b)) => a.partial_cmp(b), + } + } +} + +impl PartialOrd for Length { + fn partial_cmp(&self, rhs: &usize) -> Option { + match *self { + Length::Unbounded => Some(Ordering::Greater), + Length::Bounded(n) => n.partial_cmp(rhs), + } + } +} diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs new file mode 100644 index 0000000..994c540 --- /dev/null +++ b/src/buffer/mod.rs @@ -0,0 +1,264 @@ +use core::ops::{Deref, DerefMut, Range}; + +use alloc::Vec; +use alloc::boxed::Box; +use alloc::borrow::{Cow, ToOwned}; + +pub mod length; + +use self::length::Length; + +pub trait Buffer +where + [T]: ToOwned, +{ + fn len(&self) -> Length; + fn commit(&mut self, slice: Option>); + unsafe fn slice_unchecked(&self, range: Range) -> &[T]; + + unsafe fn slice_unchecked_mut<'a>( + &'a self, + range: Range, + ) -> BufferSlice<'a, T> { + let index = range.start; + let slice = self.slice_unchecked(range); + BufferSlice::new(slice, index) + } + + fn slice(&self, range: Range) -> Option<&[T]> { + if self.len() >= range.end && self.len() > range.start { + unsafe { Some(self.slice_unchecked(range)) } + } else { + None + } + } + + fn slice_mut<'a>( + &'a mut self, + range: Range, + ) -> Option> { + if self.len() >= range.end && self.len() > range.start { + unsafe { Some(self.slice_unchecked_mut(range)) } + } else { + None + } + } +} + +pub struct BufferSlice<'a, T: 'a> +where + [T]: ToOwned, +{ + inner: Cow<'a, [T]>, + index: usize, +} + +impl BufferSlice<'static, T> +where + [T]: ToOwned, +{ + pub fn with_static(inner: &'static [T]) -> BufferSlice<'static, T> { + BufferSlice { + inner: Cow::Borrowed(inner), + index: 0, + } + } +} + +impl<'a, T> BufferSlice<'a, T> +where + [T]: ToOwned, +{ + pub fn new(inner: &'a [T], index: usize) -> BufferSlice<'a, T> { + BufferSlice { + inner: Cow::Borrowed(inner), + index, + } + } + + pub fn is_mutated(&self) -> bool { + match self.inner { + Cow::Borrowed(_) => false, + Cow::Owned(_) => true, + } + } + + #[inline] + pub fn at_index(&self) -> usize { + self.index + } +} + +impl<'a, T> BufferSlice<'a, T> +where + [T]: ToOwned>, +{ + pub fn commit(self) -> Option> { + if self.is_mutated() { + Some(BufferCommit::new(self.inner.into_owned(), self.index)) + } else { + None + } + } +} + +impl<'a, T> AsRef<[T]> for BufferSlice<'a, T> +where + [T]: ToOwned, +{ + fn as_ref(&self) -> &[T] { + self.inner.as_ref() + } +} + +impl<'a, T> AsMut<[T]> for BufferSlice<'a, T> +where + [T]: ToOwned, + <[T] as ToOwned>::Owned: AsMut<[T]>, +{ + fn as_mut(&mut self) -> &mut [T] { + self.inner.to_mut().as_mut() + } +} + +impl<'a, T> Deref for BufferSlice<'a, T> +where + [T]: ToOwned, +{ + type Target = [T]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +impl<'a, T> DerefMut for BufferSlice<'a, T> +where + [T]: ToOwned, + <[T] as ToOwned>::Owned: AsMut<[T]>, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut() + } +} + +pub struct BufferCommit { + inner: Vec, + index: usize, +} + +impl BufferCommit { + pub fn with_vec(inner: Vec) -> BufferCommit { + BufferCommit { inner, index: 0 } + } + + pub fn new(inner: Vec, index: usize) -> BufferCommit { + BufferCommit { inner, index } + } + + pub fn into_inner(self) -> Vec { + self.inner + } + + #[inline] + pub fn at_index(&self) -> usize { + self.index + } +} + +impl AsRef<[T]> for BufferCommit { + fn as_ref(&self) -> &[T] { + self.inner.as_ref() + } +} + +impl AsMut<[T]> for BufferCommit { + fn as_mut(&mut self) -> &mut [T] { + self.inner.as_mut() + } +} + +impl Deref for BufferCommit { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +impl DerefMut for BufferCommit { + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut() + } +} + +default impl Buffer for B +where + T: Clone, + [T]: ToOwned, + B: AsRef<[T]> + AsMut<[T]>, +{ + fn len(&self) -> Length { + Length::Bounded(self.as_ref().len()) + } + + fn commit(&mut self, slice: Option>) { + slice.map(|slice| { + let index = slice.at_index(); + let end = index + slice.as_ref().len(); + // XXX: it would be much better to drop the contents of dst and + // move the contents of slice instead of cloning + let dst = &mut self.as_mut()[index..end]; + dst.clone_from_slice(slice.as_ref()); + }); + } + + unsafe fn slice_unchecked(&self, range: Range) -> &[T] { + self.as_ref().get_unchecked(range) + } +} + +impl<'a, T> Buffer for &'a mut [T] +where + T: Clone, + [T]: ToOwned, +{ +} + +impl Buffer for Vec +where + T: Clone, + [T]: ToOwned, +{ +} + +impl Buffer for Box<[T]> +where + T: Clone, + [T]: ToOwned, +{ +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn buffer() { + let mut buffer = vec![0; 1024]; + let commit = { + let mut slice = buffer.slice_mut(256..512).unwrap(); + slice.iter_mut().for_each(|x| *x = 1); + slice.commit() + }; + buffer.commit(commit); + + for (i, &x) in buffer.iter().enumerate() { + if i < 256 || i >= 512 { + assert_eq!(x, 0); + } else { + assert_eq!(x, 1); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index deaeaa1..1ce4792 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,18 @@ +#![feature(alloc)] +#![feature(specialization)] +#![feature(swap_with_slice)] #![cfg_attr(not(test), no_std)] +extern crate alloc; #[macro_use] extern crate bitflags; +#[cfg(test)] +extern crate core; pub mod error; pub mod sys; +pub mod buffer; +pub mod fs; #[cfg(test)] mod tests { From 5991420aa8f064e18977a2fcd23264ba587a807f Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 08:25:14 +0100 Subject: [PATCH 15/72] add dynamic casting abilities to BufferSlice --- src/buffer/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 994c540..54ca4ba 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -1,3 +1,5 @@ +use core::mem; +use core::slice; use core::ops::{Deref, DerefMut, Range}; use alloc::Vec; @@ -89,6 +91,24 @@ where } } +impl<'a> BufferSlice<'a, u8> { + pub fn dynamic_cast(&self) -> (T, usize) { + assert!(self.inner.len() >= mem::size_of::()); + let index = self.index; + let cast = unsafe { + mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()) + }; + (cast, index) + } + + pub fn from_cast(cast: &T, index: usize) -> BufferSlice<'a, u8> { + let len = mem::size_of::(); + let ptr = cast as *const T as *const u8; + let slice = unsafe { slice::from_raw_parts(ptr, len) }; + BufferSlice::new(slice, index) + } +} + impl<'a, T> BufferSlice<'a, T> where [T]: ToOwned>, From 172c267917453e87d1884c9d1a70c01eb8779956 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 08:28:59 +0100 Subject: [PATCH 16/72] remove unmutable slices from `Buffer` --- src/buffer/mod.rs | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 54ca4ba..1aedf59 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -16,31 +16,17 @@ where { fn len(&self) -> Length; fn commit(&mut self, slice: Option>); - unsafe fn slice_unchecked(&self, range: Range) -> &[T]; - - unsafe fn slice_unchecked_mut<'a>( + unsafe fn slice_unchecked<'a>( &'a self, range: Range, - ) -> BufferSlice<'a, T> { - let index = range.start; - let slice = self.slice_unchecked(range); - BufferSlice::new(slice, index) - } + ) -> BufferSlice<'a, T>; - fn slice(&self, range: Range) -> Option<&[T]> { - if self.len() >= range.end && self.len() > range.start { - unsafe { Some(self.slice_unchecked(range)) } - } else { - None - } - } - - fn slice_mut<'a>( + fn slice<'a>( &'a mut self, range: Range, ) -> Option> { if self.len() >= range.end && self.len() > range.start { - unsafe { Some(self.slice_unchecked_mut(range)) } + unsafe { Some(self.slice_unchecked(range)) } } else { None } @@ -233,8 +219,12 @@ where }); } - unsafe fn slice_unchecked(&self, range: Range) -> &[T] { - self.as_ref().get_unchecked(range) + unsafe fn slice_unchecked<'a>( + &'a self, + range: Range, + ) -> BufferSlice<'a, T> { + let index = range.start; + BufferSlice::new(self.as_ref().get_unchecked(range), index) } } @@ -267,7 +257,7 @@ mod tests { fn buffer() { let mut buffer = vec![0; 1024]; let commit = { - let mut slice = buffer.slice_mut(256..512).unwrap(); + let mut slice = buffer.slice(256..512).unwrap(); slice.iter_mut().for_each(|x| *x = 1); slice.commit() }; From 6b34d3325a46a90b04146723ee24e4ca69aef7d0 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 08:38:44 +0100 Subject: [PATCH 17/72] redo definitions on casts --- src/buffer/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 1aedf59..1b6d7d5 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -78,16 +78,17 @@ where } impl<'a> BufferSlice<'a, u8> { - pub fn dynamic_cast(&self) -> (T, usize) { + pub unsafe fn dynamic_cast(&self) -> (T, usize) { assert!(self.inner.len() >= mem::size_of::()); let index = self.index; - let cast = unsafe { - mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()) - }; + let cast = mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()); (cast, index) } - pub fn from_cast(cast: &T, index: usize) -> BufferSlice<'a, u8> { + pub fn from_cast( + cast: &'a T, + index: usize, + ) -> BufferSlice<'a, u8> { let len = mem::size_of::(); let ptr = cast as *const T as *const u8; let slice = unsafe { slice::from_raw_parts(ptr, len) }; From bae7f23b3e259f24f884f5828d413867786b8ee3 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 08:39:23 +0100 Subject: [PATCH 18/72] use `&Buffer` instead of `&[u8]` on Superblock::find --- src/sys/superblock.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index e89a66c..b179d6f 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -1,6 +1,7 @@ use core::mem; use error::Error; +use buffer::Buffer; /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a /// volume @@ -38,6 +39,7 @@ pub const OS_LITE: u32 = 4; /// 512 byte sectors, the Superblock will begin at LBA 2 and will occupy all of /// sector 2 and 3. #[repr(C, packed)] +#[derive(Clone, Copy)] pub struct Superblock { // taken from https://wiki.osdev.org/Ext2 /// Total number of inodes in file system @@ -143,24 +145,23 @@ pub struct Superblock { } impl Superblock { - pub unsafe fn find<'a>( - haystack: &'a mut [u8], - offset: isize, - ) -> Result<&'a mut Superblock, Error> { - let offset = (1024 + offset) as usize; + pub fn find<'a>( + haystack: &'a Buffer, + ) -> Result<(Superblock, usize), Error> { + let offset = 1024; let end = offset + mem::size_of::(); if haystack.len() < end { return Err(Error::OutOfBounds(end)); } - let superblock: &mut Superblock = { - let ptr = haystack.as_mut_ptr().offset(offset as isize) - as *mut Superblock; - ptr.as_mut().unwrap() + let superblock = unsafe { + haystack + .slice_unchecked(offset..end) + .dynamic_cast::() }; - if superblock.magic != EXT2_MAGIC { - Err(Error::BadMagic(superblock.magic)) + if superblock.0.magic != EXT2_MAGIC { + Err(Error::BadMagic(superblock.0.magic)) } else { Ok(superblock) } @@ -243,16 +244,14 @@ mod tests { #[test] fn find() { let mut buffer = vec![0_u8; 4096]; - let addr = &buffer[1024] as *const _ as usize; // magic buffer[1024 + 56] = EXT2_MAGIC as u8; buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; - let superblock = unsafe { Superblock::find(&mut buffer, 0) }; + let superblock = Superblock::find(&buffer); assert!( superblock.is_ok(), "Err({:?})", superblock.err().unwrap_or_else(|| unreachable!()), ); - assert_eq!(superblock.unwrap() as *const _ as usize, addr); } } From 3d946eb721d847f2c7c06ee627f698b73b6939db Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 08:39:46 +0100 Subject: [PATCH 19/72] add safe `Ext2` wrapper struct --- src/fs.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/fs.rs diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 0000000..2d80417 --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,26 @@ +use error::Error; +use buffer::Buffer; +use sys::superblock::Superblock; + +/// Safe wrapper for raw sys structs +pub struct Ext2> { + buffer: B, + superblock: Option<(Superblock, usize)>, +} + +impl> Ext2 { + pub fn new(buffer: B) -> Ext2 { + Ext2 { + buffer, + superblock: None, + } + } + + pub fn init(&mut self) -> Result<(), Error> { + let superblock = Superblock::find(&self.buffer); + match superblock { + Ok(sb) => Ok(self.superblock = Some(sb)), + Err(err) => Err(err), + } + } +} From aee2f2def0975adb3abb1cde573ad446e22c278f Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 09:48:11 +0100 Subject: [PATCH 20/72] `impl` Buffer for `File` --- src/buffer/mod.rs | 161 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 47 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 1b6d7d5..e3be829 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -15,16 +15,14 @@ where [T]: ToOwned, { fn len(&self) -> Length; + // TODO: return Result fn commit(&mut self, slice: Option>); unsafe fn slice_unchecked<'a>( &'a self, range: Range, ) -> BufferSlice<'a, T>; - fn slice<'a>( - &'a mut self, - range: Range, - ) -> Option> { + fn slice<'a>(&'a self, range: Range) -> Option> { if self.len() >= range.end && self.len() > range.start { unsafe { Some(self.slice_unchecked(range)) } } else { @@ -51,6 +49,16 @@ where index: 0, } } + + pub fn new_owned( + inner: <[T] as ToOwned>::Owned, + index: usize, + ) -> BufferSlice<'static, T> { + BufferSlice { + inner: Cow::Owned(inner), + index, + } + } } impl<'a, T> BufferSlice<'a, T> @@ -199,55 +207,114 @@ impl DerefMut for BufferCommit { } } -default impl Buffer for B -where - T: Clone, - [T]: ToOwned, - B: AsRef<[T]> + AsMut<[T]>, -{ - fn len(&self) -> Length { - Length::Bounded(self.as_ref().len()) - } +macro_rules! impl_slice { + (@inner $buffer:ty $( , $lt:lifetime )* ) => { + impl<$( $lt, )* T> Buffer for $buffer + where + T: Clone, + [T]: ToOwned, + { + fn len(&self) -> Length { + Length::Bounded(>::as_ref(self).len()) + } - fn commit(&mut self, slice: Option>) { - slice.map(|slice| { - let index = slice.at_index(); - let end = index + slice.as_ref().len(); - // XXX: it would be much better to drop the contents of dst and - // move the contents of slice instead of cloning - let dst = &mut self.as_mut()[index..end]; - dst.clone_from_slice(slice.as_ref()); - }); - } + fn commit(&mut self, slice: Option>) { + slice.map(|slice| { + let index = slice.at_index(); + let end = index + slice.as_ref().len(); + // XXX: it would be much better to drop the contents of dst + // and move the contents of slice instead of cloning + let dst = + &mut >::as_mut(self)[index..end]; + dst.clone_from_slice(slice.as_ref()); + }); + } - unsafe fn slice_unchecked<'a>( - &'a self, - range: Range, - ) -> BufferSlice<'a, T> { - let index = range.start; - BufferSlice::new(self.as_ref().get_unchecked(range), index) - } + unsafe fn slice_unchecked<'a>( + &'a self, + range: Range, + ) -> BufferSlice<'a, T> { + let index = range.start; + BufferSlice::new( + >::as_ref(self).get_unchecked(range), + index, + ) + } + } + }; + ($buffer:ty) => { + impl_slice!(@inner $buffer); + }; + ($buffer:ty $( , $lt:lifetime )* ) => { + impl_slice!(@inner $buffer $( , $lt )* ); + }; } -impl<'a, T> Buffer for &'a mut [T] -where - T: Clone, - [T]: ToOwned, -{ -} +//impl_slice!('a, &'a mut [T]); +impl_slice!(Vec); +impl_slice!(Box<[T]>); -impl Buffer for Vec -where - T: Clone, - [T]: ToOwned, -{ -} +#[cfg(any(test, not(feature = "no_std")))] +mod file { + use std::ops::Range; + use std::io::{Read, Seek, SeekFrom, Write}; + use std::fs::File; + use std::cell::RefCell; -impl Buffer for Box<[T]> -where - T: Clone, - [T]: ToOwned, -{ + use super::{Buffer, BufferCommit, BufferSlice}; + use super::length::Length; + + impl Buffer for RefCell { + fn len(&self) -> Length { + Length::Bounded( + self.borrow() + .metadata() + .map(|data| data.len() as usize) + .unwrap_or(0), + ) + } + + fn commit(&mut self, slice: Option>) { + slice.map(|slice| { + let index = slice.at_index(); + let end = index + slice.as_ref().len(); + let mut refmut = self.borrow_mut(); + let _ = refmut + .seek(SeekFrom::Start(index as u64)) + .and_then(|_| refmut.write(&slice.as_ref()[index..end])); + }); + } + + unsafe fn slice_unchecked<'a>( + &'a self, + range: Range, + ) -> BufferSlice<'a, u8> { + let index = range.start; + let mut vec = Vec::with_capacity(range.end - range.start); + let mut refmut = self.borrow_mut(); + refmut + .seek(SeekFrom::Start(index as u64)) + .and_then(|_| refmut.read_exact(&mut vec[range])) + .unwrap_or_else(|err| { + panic!("could't read from File Buffer: {:?}", err) + }); + BufferSlice::new_owned(vec, index) + } + + fn slice<'a>( + &'a self, + range: Range, + ) -> Option> { + let index = range.start; + let mut vec = Vec::with_capacity(range.end - range.start); + let mut refmut = self.borrow_mut(); + refmut + .seek(SeekFrom::Start(index as u64)) + .and_then(|_| refmut.read_exact(&mut vec[range])) + .map(move |_| BufferSlice::new_owned(vec, index)) + .ok() + } + } } #[cfg(test)] From c06982b7ac611b78e1f1c39b99d624c3d688f0f1 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 13:28:18 +0100 Subject: [PATCH 21/72] add `Infallible`, for errors which never occur --- src/error.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/error.rs b/src/error.rs index d6aee4f..353d8f2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,3 +5,11 @@ pub enum Error { OutOfBounds(usize), BadBlockGroupCount(u32, u32), } + +impl From for Error { + fn from(_: Infallible) -> Error { + unreachable!() + } +} + +pub enum Infallible {} From 110d2ff4156b5af0109558ac233920d858eac7ca Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 13:29:22 +0100 Subject: [PATCH 22/72] add `no_std` as default feature --- Cargo.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ded51c2..a216e65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,9 @@ version = "0.1.0" authors = ["Szymon Walter "] [dependencies] -rlibc = "1.0" bitflags = "1.0" +rlibc = { version = "1.0", optional = true } + +[features] +default = ["no_std"] +no_std = ["rlibc"] From 55b23f497425314a2836ed91522cc78447ebab0d Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 13:30:42 +0100 Subject: [PATCH 23/72] add `Result` return type to `fn commit` --- src/buffer/mod.rs | 48 ++++++++++++++++++++++++++++--------------- src/fs.rs | 5 ++++- src/lib.rs | 5 +++-- src/sys/superblock.rs | 9 +++++--- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index e3be829..a4bd6dd 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -6,17 +6,22 @@ use alloc::Vec; use alloc::boxed::Box; use alloc::borrow::{Cow, ToOwned}; -pub mod length; +use error::Infallible; +pub mod length; use self::length::Length; pub trait Buffer where [T]: ToOwned, { + type Error; + fn len(&self) -> Length; - // TODO: return Result - fn commit(&mut self, slice: Option>); + fn commit( + &mut self, + slice: Option>, + ) -> Result<(), Self::Error>; unsafe fn slice_unchecked<'a>( &'a self, range: Range, @@ -214,11 +219,13 @@ macro_rules! impl_slice { T: Clone, [T]: ToOwned, { + type Error = Infallible; + fn len(&self) -> Length { Length::Bounded(>::as_ref(self).len()) } - fn commit(&mut self, slice: Option>) { + fn commit(&mut self, slice: Option>) -> Result<(), Infallible> { slice.map(|slice| { let index = slice.at_index(); let end = index + slice.as_ref().len(); @@ -228,6 +235,7 @@ macro_rules! impl_slice { &mut >::as_mut(self)[index..end]; dst.clone_from_slice(slice.as_ref()); }); + Ok(()) } unsafe fn slice_unchecked<'a>( @@ -250,14 +258,14 @@ macro_rules! impl_slice { }; } -//impl_slice!('a, &'a mut [T]); +//impl_slice!(&'a mut [T], 'a); impl_slice!(Vec); impl_slice!(Box<[T]>); #[cfg(any(test, not(feature = "no_std")))] mod file { use std::ops::Range; - use std::io::{Read, Seek, SeekFrom, Write}; + use std::io::{self, Read, Seek, SeekFrom, Write}; use std::fs::File; use std::cell::RefCell; @@ -265,6 +273,8 @@ mod file { use super::length::Length; impl Buffer for RefCell { + type Error = io::Error; + fn len(&self) -> Length { Length::Bounded( self.borrow() @@ -274,15 +284,21 @@ mod file { ) } - fn commit(&mut self, slice: Option>) { - slice.map(|slice| { - let index = slice.at_index(); - let end = index + slice.as_ref().len(); - let mut refmut = self.borrow_mut(); - let _ = refmut - .seek(SeekFrom::Start(index as u64)) - .and_then(|_| refmut.write(&slice.as_ref()[index..end])); - }); + fn commit( + &mut self, + slice: Option>, + ) -> Result<(), Self::Error> { + slice + .map(|slice| { + let index = slice.at_index(); + let end = index + slice.as_ref().len(); + let mut refmut = self.borrow_mut(); + refmut + .seek(SeekFrom::Start(index as u64)) + .and_then(|_| refmut.write(&slice.as_ref()[index..end])) + .map(|_| ()) + }) + .unwrap_or(Ok(())) } unsafe fn slice_unchecked<'a>( @@ -329,7 +345,7 @@ mod tests { slice.iter_mut().for_each(|x| *x = 1); slice.commit() }; - buffer.commit(commit); + assert!(buffer.commit(commit).is_ok()); for (i, &x) in buffer.iter().enumerate() { if i < 256 || i >= 512 { diff --git a/src/fs.rs b/src/fs.rs index 2d80417..bad1c3f 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -8,7 +8,10 @@ pub struct Ext2> { superblock: Option<(Superblock, usize)>, } -impl> Ext2 { +impl> Ext2 +where + Error: From, +{ pub fn new(buffer: B) -> Ext2 { Ext2 { buffer, diff --git a/src/lib.rs b/src/lib.rs index 1ce4792..3e10f43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,13 @@ #![feature(alloc)] #![feature(specialization)] #![feature(swap_with_slice)] -#![cfg_attr(not(test), no_std)] +#![feature(macro_lifetime_matcher)] +#![cfg_attr(all(not(test), feature = "no_std"), no_std)] extern crate alloc; #[macro_use] extern crate bitflags; -#[cfg(test)] +#[cfg(any(test, not(feature = "no_std")))] extern crate core; pub mod error; diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index b179d6f..d58d689 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -145,9 +145,12 @@ pub struct Superblock { } impl Superblock { - pub fn find<'a>( - haystack: &'a Buffer, - ) -> Result<(Superblock, usize), Error> { + pub fn find<'a, E>( + haystack: &'a Buffer, + ) -> Result<(Superblock, usize), Error> + where + Error: From, + { let offset = 1024; let end = offset + mem::size_of::(); if haystack.len() < end { From a8199f00d0c5714e48fa89d4deabb4568a667258 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 13:35:00 +0100 Subject: [PATCH 24/72] add `File` `Ext2` test --- ext2.bin | Bin 0 -> 4194304 bytes src/error.rs | 14 +++++++++++++- src/fs.rs | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 ext2.bin diff --git a/ext2.bin b/ext2.bin new file mode 100644 index 0000000000000000000000000000000000000000..939c3d1ac2af5ae801089b8652cc72f648c875e8 GIT binary patch literal 4194304 zcmeIuF;2n&7zNdGnT)e*c&pf)t*CNV!MDbm$_EqG|Xn#byo78vhh^p%JFS4uAy8GNToou(g zc~8saGxFKf%P@I;NH^DY for Error { @@ -12,4 +17,11 @@ impl From for Error { } } +#[cfg(any(test, not(feature = "no_std")))] +impl From for Error { + fn from(err: io::Error) -> Error { + Error::Io(err) + } +} + pub enum Infallible {} diff --git a/src/fs.rs b/src/fs.rs index bad1c3f..f802ded 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -27,3 +27,18 @@ where } } } + +#[cfg(test)] +mod tests { + use std::fs::File; + use std::cell::RefCell; + + use super::Ext2; + + #[test] + fn file() { + let file = RefCell::new(File::open("ext2.bin").unwrap()); + let mut fs = Ext2::new(file); + assert!(fs.init().is_ok()); + } +} From 0802005fa5f304ffa5a740ab017d785b9e18969f Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 17:05:01 +0100 Subject: [PATCH 25/72] uncomment `impl Buffer` for `&mut [T]` --- src/buffer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index a4bd6dd..9051e66 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -258,7 +258,7 @@ macro_rules! impl_slice { }; } -//impl_slice!(&'a mut [T], 'a); +impl_slice!(&'b mut [T], 'b); impl_slice!(Vec); impl_slice!(Box<[T]>); From 0d5b9aef123a641da74f39f0ac3d0847b0839d50 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 17:23:45 +0100 Subject: [PATCH 26/72] add PartialEq impl for Error --- src/error.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/error.rs b/src/error.rs index 8cb3fb6..83be4e2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -24,4 +24,30 @@ impl From for Error { } } +impl PartialEq for Error { + fn eq(&self, rhs: &Error) -> bool { + match (self, rhs) { + (&Error::BadMagic(a), &Error::BadMagic(b)) => a == b, + (&Error::OutOfBounds(a), &Error::OutOfBounds(b)) => a == b, + ( + &Error::BadBlockGroupCount(a1, a2), + &Error::BadBlockGroupCount(b1, b2), + ) => a1 == b1 && a2 == b2, + _ => false, + } + } + + fn ne(&self, rhs: &Error) -> bool { + match (self, rhs) { + (&Error::BadMagic(a), &Error::BadMagic(b)) => a != b, + (&Error::OutOfBounds(a), &Error::OutOfBounds(b)) => a != b, + ( + &Error::BadBlockGroupCount(a1, a2), + &Error::BadBlockGroupCount(b1, b2), + ) => a1 != b1 || a2 != b2, + _ => false, + } + } +} + pub enum Infallible {} From 1d8b1466ff20a6bce930f83c76d6dc3c3687ac21 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 17:31:01 +0100 Subject: [PATCH 27/72] mkfs.ext2 ext2.bin --- ext2.bin | Bin 4194304 -> 4194304 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ext2.bin b/ext2.bin index 939c3d1ac2af5ae801089b8652cc72f648c875e8..a8ac1e64f2a94367065eb6e69bbf4c8cd9ed3fa9 100644 GIT binary patch delta 2335 zcmeI!%WD%s9KiA4%xs%9Nt3o|YHN+A+Ny0djqg5`QvZNLs3Ps5ClQ2d!N*B3D?NDB z1>dhI9z7Hk^k_lw)U*GAAWG@Q3W~UXC!3UlIZ8dmflp?3=C?E1NtoZduB%>dz*V&T){dnI({QXGp+sU7HvREa^F5(qVDD_I|l1{eK zokTlk601gw!@%-b%CAxEJ)c$4tueHLUBwMttJYHWzJ4g!l#o}rTJKx&|M`Re!oT{g z_x&KK`q*@rm?`;t9S delta 1400 zcmZo@XkcmpV((u&7zFw*>|xljgMp#%M&E(o`xt8WGqCMsVEVk|l_DDh!@hm&7A&RQ z&Bp{9|NUbx{rp;N3)2S1-3&FG8oEjtyM36>3cq5gVPJUuZzE$aqsY8Y&Nv1jU}9)y qR Date: Mon, 19 Mar 2018 17:41:42 +0100 Subject: [PATCH 28/72] fix some slicing issues --- src/buffer/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 9051e66..6a7d137 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -306,11 +306,13 @@ mod file { range: Range, ) -> BufferSlice<'a, u8> { let index = range.start; - let mut vec = Vec::with_capacity(range.end - range.start); + let len = range.end - range.start; + let mut vec = Vec::with_capacity(len); + vec.set_len(len); let mut refmut = self.borrow_mut(); refmut .seek(SeekFrom::Start(index as u64)) - .and_then(|_| refmut.read_exact(&mut vec[range])) + .and_then(|_| refmut.read_exact(&mut vec[..])) .unwrap_or_else(|err| { panic!("could't read from File Buffer: {:?}", err) }); From ade142843c8bd153d488055bd808ea36bfbb2fe7 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 17:42:08 +0100 Subject: [PATCH 29/72] add `file_len` test and rewrite `file` test --- src/fs.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/fs.rs b/src/fs.rs index f802ded..1090b41 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -33,12 +33,20 @@ mod tests { use std::fs::File; use std::cell::RefCell; + use buffer::Buffer; + use super::Ext2; + #[test] + fn file_len() { + let file = RefCell::new(File::open("ext2.bin").unwrap()); + assert_eq!(unsafe { file.slice_unchecked(1024..2048).len() }, 1024); + } + #[test] fn file() { let file = RefCell::new(File::open("ext2.bin").unwrap()); let mut fs = Ext2::new(file); - assert!(fs.init().is_ok()); + assert_eq!(Ok(()), fs.init()); } } From d4348c3177b31e3dda4c2565feedd84fbc2957de Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 17:56:53 +0100 Subject: [PATCH 30/72] fill in the fs with some directories and files --- ext2.bin | Bin 4194304 -> 4194304 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ext2.bin b/ext2.bin index a8ac1e64f2a94367065eb6e69bbf4c8cd9ed3fa9..aa13d85580f8a1c5d625a06823825f898be6d778 100644 GIT binary patch delta 1860 zcmZo@Xkcmp;tf13tkL`o44)#gGpW(F1ph6130*-#9U zf5FVmzywhVCK>rAGFq|Jzu!|nkx>G!%MGd{5J*FGF`?*U0_$pk=+a!$_<~s;sLU6r z+6jo&;JO%5bS;|5XwA|H(PRqJ#2^6C1hNLC8AJm`890y}xERP@0>n#!c-cfoeU=u8 z0a6Vh1AqXe5gES#hLaadGf>rLMUMOSn+-TF;3Xn0rv)&{$cQj-G3DeJmuRQum*%A~ zFz^74zQWAHl#!pCx{>h&^Rf^o6M1EYlKgz#w9>rnN-nNMg_6v?N`(pwGllHbqP)}` zF5)c2@0?LtLJ>9^LZcysH%AYh1oBDQ7F5pgFfcOd0clXdtir&=qzB>v0S^N+Q+ZA? zl+D7FT2W%e3*=p3W@Q2wLK_(mGe?0$U?xCJgP6bv6o0|Y$r$A7=;G_DmkTV^z~Blq YAEO>zP_MYW03yBzUA$s&muKm=0O|3N!2kdN delta 1391 zcmZo@Xkcmp;tf13ta1Dd3|}V;vdFVedAdG|VY4aAb!MR8S7xTof*i~ajEox@Uomd} z@5#i($Uc#=ZgYbV2a7OBDGW1!0rTeB0Z&;r8*p5(CrnsR3t*Drd%?`bl#^dvqMeps onwPSX@f!285GE7Cx{0u0R0&b>Fd9sw!8DrRh$*os$SDeH07l~-LjV8( From e6acaad9a9eb807358e1794b95899f2dbe018a4d Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 18:10:27 +0100 Subject: [PATCH 31/72] port BlockGroupDescriptor table finding to Buffer --- src/sys/block_group.rs | 60 ++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 70c6ab2..cf7445b 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -1,7 +1,9 @@ use core::mem; -use core::slice; + +use alloc::Vec; use error::Error; +use buffer::Buffer; /// The Block Group Descriptor Table contains a descriptor for each block group /// within the file system. The number of block groups within the file system, @@ -16,6 +18,7 @@ use error::Error; /// Remember that blocks are numbered starting at 0, and that block numbers /// don't usually correspond to physical block addresses. #[repr(C, packed)] +#[derive(Clone, Copy)] pub struct BlockGroupDescriptor { /// Block address of block usage bitmap pub block_usage_addr: u32, @@ -34,21 +37,47 @@ pub struct BlockGroupDescriptor { } impl BlockGroupDescriptor { - pub unsafe fn find_descriptor_table<'a>( - haystack: &'a mut [u8], - offset: isize, + pub unsafe fn find_descriptor<'a, E>( + haystack: &'a Buffer, + offset: usize, + ) -> Result<(BlockGroupDescriptor, usize), Error> + where + Error: From, + { + let end = offset + mem::size_of::(); + if haystack.len() < end { + return Err(Error::OutOfBounds(end)); + } + + let descr = haystack + .slice_unchecked(offset..end) + .dynamic_cast::(); + + Ok(descr) + } + + pub fn find_descriptor_table<'a, E>( + haystack: &'a Buffer, count: usize, - ) -> Result<&'a mut [BlockGroupDescriptor], Error> { - let offset = (2048 + offset) as usize; + ) -> Result<(Vec, usize), Error> + where + Error: From, + { + let offset = 2048; // TODO: this assumes a block size let end = offset + count * mem::size_of::(); if haystack.len() < end { return Err(Error::OutOfBounds(end)); } - let ptr = haystack.as_mut_ptr().offset(offset as isize) - as *mut BlockGroupDescriptor; - let slice = slice::from_raw_parts_mut(ptr, count); - Ok(slice) + let mut vec = Vec::with_capacity(count); + for i in 0..count { + let offset = offset + i * mem::size_of::(); + vec.push(unsafe { + BlockGroupDescriptor::find_descriptor(haystack, offset)?.0 + }); + } + + Ok((vec, offset)) } } @@ -58,17 +87,14 @@ mod tests { #[test] fn find() { - let mut buffer = vec![0_u8; 4096]; - let addr = &buffer[2048] as *const _ as usize; - // magic - let table = unsafe { - BlockGroupDescriptor::find_descriptor_table(&mut buffer, 0, 0) - }; + let buffer = vec![0_u8; 4096]; + let table = BlockGroupDescriptor::find_descriptor_table(&buffer, 8); assert!( table.is_ok(), "Err({:?})", table.err().unwrap_or_else(|| unreachable!()), ); - assert_eq!(table.unwrap().as_ptr() as usize, addr); + let table = table.unwrap_or_else(|_| unreachable!()); + assert_eq!(table.0.len(), 8); } } From f1b5d2b2a085eb69b029f6a3dfe8974ec3466a35 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 18:38:33 +0100 Subject: [PATCH 32/72] rewrite fs to init in `new` --- src/fs.rs | 61 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index 1090b41..7d67234 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,30 +1,61 @@ use error::Error; -use buffer::Buffer; +use buffer::{Buffer, BufferSlice}; use sys::superblock::Superblock; +struct Struct { + pub inner: T, + pub offset: usize, +} + +impl From<(T, usize)> for Struct { + #[inline] + fn from((inner, offset): (T, usize)) -> Struct { + Struct { inner, offset } + } +} + /// Safe wrapper for raw sys structs pub struct Ext2> { buffer: B, - superblock: Option<(Superblock, usize)>, + superblock: Struct, } impl> Ext2 where Error: From, { - pub fn new(buffer: B) -> Ext2 { - Ext2 { - buffer, - superblock: None, - } + pub fn new(buffer: B) -> Result, Error> { + let superblock = Superblock::find(&buffer)?.into(); + Ok(Ext2 { buffer, superblock }) } - pub fn init(&mut self) -> Result<(), Error> { - let superblock = Superblock::find(&self.buffer); - match superblock { - Ok(sb) => Ok(self.superblock = Some(sb)), - Err(err) => Err(err), - } + pub fn update(&mut self) -> Result<(), Error> { + let slice = BufferSlice::from_cast( + &self.superblock.inner, + self.superblock.offset, + ); + let commit = slice.commit(); + self.buffer.commit(commit).map_err(|err| Error::from(err)) + } + + fn superblock(&self) -> &Superblock { + &self.superblock.inner + } + + fn superblock_mut(&mut self) -> &mut Superblock { + &mut self.superblock.inner + } + + pub fn total_block_count(&self) -> usize { + self.superblock().blocks_count as _ + } + + pub fn free_block_count(&self) -> usize { + self.superblock().free_blocks_count as _ + } + + pub fn block_size(&self) -> usize { + self.superblock().block_size() } } @@ -46,7 +77,7 @@ mod tests { #[test] fn file() { let file = RefCell::new(File::open("ext2.bin").unwrap()); - let mut fs = Ext2::new(file); - assert_eq!(Ok(()), fs.init()); + let fs = Ext2::new(file); + assert_eq!(Ok(()), fs.map(|_| ())); } } From 35170f2aeea6bca1613825b13933d492b6cca05f Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 19:32:36 +0100 Subject: [PATCH 33/72] add block group descriptor table loading to `Ext2` struct --- src/fs.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index 7d67234..c8b63cd 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,6 +1,9 @@ +use alloc::Vec; + use error::Error; use buffer::{Buffer, BufferSlice}; use sys::superblock::Superblock; +use sys::block_group::BlockGroupDescriptor; struct Struct { pub inner: T, @@ -18,6 +21,7 @@ impl From<(T, usize)> for Struct { pub struct Ext2> { buffer: B, superblock: Struct, + block_groups: Struct>, } impl> Ext2 @@ -25,8 +29,26 @@ where Error: From, { pub fn new(buffer: B) -> Result, Error> { - let superblock = Superblock::find(&buffer)?.into(); - Ok(Ext2 { buffer, superblock }) + let superblock = Struct::from(Superblock::find(&buffer)?); + let block_size = superblock.inner.block_size(); + let block_groups_offset = + (superblock.inner.first_data_block as usize + 1) * block_size; + let block_groups_count = superblock + .inner + .block_group_count() + .map(|count| count as usize) + .map_err(|(a, b)| Error::BadBlockGroupCount(a, b))?; + let block_groups = BlockGroupDescriptor::find_descriptor_table( + &buffer, + block_groups_offset, + block_groups_count, + )?; + let block_groups = Struct::from(block_groups); + Ok(Ext2 { + buffer, + superblock, + block_groups, + }) } pub fn update(&mut self) -> Result<(), Error> { @@ -46,6 +68,13 @@ where &mut self.superblock.inner } + pub fn block_group_count(&self) -> Result { + self.superblock() + .block_group_count() + .map(|count| count as usize) + .map_err(|(a, b)| Error::BadBlockGroupCount(a, b)) + } + pub fn total_block_count(&self) -> usize { self.superblock().blocks_count as _ } From 0fc2c934d9e65f3f977a3d48c03a914db166af96 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 19:33:20 +0100 Subject: [PATCH 34/72] add offset argument to BlockGroupDescriptor::find_... --- src/sys/block_group.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index cf7445b..05e0a95 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -56,14 +56,14 @@ impl BlockGroupDescriptor { Ok(descr) } - pub fn find_descriptor_table<'a, E>( + pub unsafe fn find_descriptor_table<'a, E>( haystack: &'a Buffer, + offset: usize, count: usize, ) -> Result<(Vec, usize), Error> where Error: From, { - let offset = 2048; // TODO: this assumes a block size let end = offset + count * mem::size_of::(); if haystack.len() < end { return Err(Error::OutOfBounds(end)); @@ -88,7 +88,8 @@ mod tests { #[test] fn find() { let buffer = vec![0_u8; 4096]; - let table = BlockGroupDescriptor::find_descriptor_table(&buffer, 8); + let table = + BlockGroupDescriptor::find_descriptor_table(&buffer, 2048, 8); assert!( table.is_ok(), "Err({:?})", From 959572eca14a82070b6a20c0ac64bf24fb19aaca Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 19:33:56 +0100 Subject: [PATCH 35/72] mark Superblock::find unsafe; add test --- src/sys/superblock.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index d58d689..b18bd1e 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -145,7 +145,7 @@ pub struct Superblock { } impl Superblock { - pub fn find<'a, E>( + pub unsafe fn find<'a, E>( haystack: &'a Buffer, ) -> Result<(Superblock, usize), Error> where @@ -257,4 +257,19 @@ mod tests { superblock.err().unwrap_or_else(|| unreachable!()), ); } + + #[test] + #[allow(unused_unsafe)] + fn superblock() { + use std::cell::RefCell; + use std::fs::File; + + let file = RefCell::new(File::open("ext2.bin").unwrap()); + let superblock = Superblock::find(&file); + assert!( + superblock.is_ok(), + "Err({:?})", + superblock.err().unwrap_or_else(|| unreachable!()), + ); + } } From fb1b5bdef542085b8f64f9518e03d3af68858edd Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 19:36:30 +0100 Subject: [PATCH 36/72] fix `unsafe` keywords --- src/fs.rs | 14 ++++++++------ src/sys/block_group.rs | 7 ++++--- src/sys/superblock.rs | 6 +++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index c8b63cd..84f9862 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -29,7 +29,7 @@ where Error: From, { pub fn new(buffer: B) -> Result, Error> { - let superblock = Struct::from(Superblock::find(&buffer)?); + let superblock = unsafe { Struct::from(Superblock::find(&buffer)?) }; let block_size = superblock.inner.block_size(); let block_groups_offset = (superblock.inner.first_data_block as usize + 1) * block_size; @@ -38,11 +38,13 @@ where .block_group_count() .map(|count| count as usize) .map_err(|(a, b)| Error::BadBlockGroupCount(a, b))?; - let block_groups = BlockGroupDescriptor::find_descriptor_table( - &buffer, - block_groups_offset, - block_groups_count, - )?; + let block_groups = unsafe { + BlockGroupDescriptor::find_descriptor_table( + &buffer, + block_groups_offset, + block_groups_count, + )? + }; let block_groups = Struct::from(block_groups); Ok(Ext2 { buffer, diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 05e0a95..4e5e65d 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -72,7 +72,7 @@ impl BlockGroupDescriptor { let mut vec = Vec::with_capacity(count); for i in 0..count { let offset = offset + i * mem::size_of::(); - vec.push(unsafe { + vec.push({ BlockGroupDescriptor::find_descriptor(haystack, offset)?.0 }); } @@ -88,8 +88,9 @@ mod tests { #[test] fn find() { let buffer = vec![0_u8; 4096]; - let table = - BlockGroupDescriptor::find_descriptor_table(&buffer, 2048, 8); + let table = unsafe { + BlockGroupDescriptor::find_descriptor_table(&buffer, 2048, 8) + }; assert!( table.is_ok(), "Err({:?})", diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index b18bd1e..3d16b05 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -157,7 +157,7 @@ impl Superblock { return Err(Error::OutOfBounds(end)); } - let superblock = unsafe { + let superblock = { haystack .slice_unchecked(offset..end) .dynamic_cast::() @@ -250,7 +250,7 @@ mod tests { // magic buffer[1024 + 56] = EXT2_MAGIC as u8; buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; - let superblock = Superblock::find(&buffer); + let superblock = unsafe { Superblock::find(&buffer) }; assert!( superblock.is_ok(), "Err({:?})", @@ -265,7 +265,7 @@ mod tests { use std::fs::File; let file = RefCell::new(File::open("ext2.bin").unwrap()); - let superblock = Superblock::find(&file); + let superblock = unsafe { Superblock::find(&file) }; assert!( superblock.is_ok(), "Err({:?})", From 1415941a960861d7b602ab5d8ee1a92a8766a7b0 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 19:41:45 +0100 Subject: [PATCH 37/72] update `update_global` method on `Ext2` --- src/fs.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index 84f9862..18a6ca1 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,3 +1,4 @@ +use core::mem; use alloc::Vec; use error::Error; @@ -53,13 +54,27 @@ where }) } - pub fn update(&mut self) -> Result<(), Error> { - let slice = BufferSlice::from_cast( - &self.superblock.inner, - self.superblock.offset, - ); - let commit = slice.commit(); - self.buffer.commit(commit).map_err(|err| Error::from(err)) + pub fn update_global(&mut self) -> Result<(), Error> { + // superblock + { + let slice = BufferSlice::from_cast( + &self.superblock.inner, + self.superblock.offset, + ); + let commit = slice.commit(); + self.buffer.commit(commit).map_err(|err| Error::from(err))?; + } + + // block group descriptors + let mut offset = self.block_groups.offset; + for descr in &self.block_groups.inner { + let slice = BufferSlice::from_cast(descr, offset); + let commit = slice.commit(); + self.buffer.commit(commit).map_err(|err| Error::from(err))?; + offset += mem::size_of::(); + } + + Ok(()) } fn superblock(&self) -> &Superblock { From 6ce24624a717f2e2d31ae1085dcdbb9a23e6e532 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 19:55:22 +0100 Subject: [PATCH 38/72] add `version` and `inode_size` methods --- src/fs.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/fs.rs b/src/fs.rs index 18a6ca1..537f7a1 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -5,6 +5,7 @@ use error::Error; use buffer::{Buffer, BufferSlice}; use sys::superblock::Superblock; use sys::block_group::BlockGroupDescriptor; +use sys::inode::Inode; struct Struct { pub inner: T, @@ -85,6 +86,19 @@ where &mut self.superblock.inner } + pub fn version(&self) -> (u32, u16) { + (self.superblock().rev_major, self.superblock().rev_minor) + } + + pub fn inode_size(&self) -> usize { + if self.version().0 == 0 { + mem::size_of::() + } else { + // note: inodes bigger than 128 are not supported + self.superblock().inode_size as usize + } + } + pub fn block_group_count(&self) -> Result { self.superblock() .block_group_count() @@ -124,6 +138,17 @@ mod tests { fn file() { let file = RefCell::new(File::open("ext2.bin").unwrap()); let fs = Ext2::new(file); - assert_eq!(Ok(()), fs.map(|_| ())); + + assert!( + fs.is_ok(), + "Err({:?})", + fs.err().unwrap_or_else(|| unreachable!()), + ); + + let fs = fs.unwrap(); + + let vers = fs.version(); + println!("version: {}.{}", vers.0, vers.1); + assert_eq!(128, fs.inode_size()); } } From eef8f86e8b1b8c1530ac8e70bb3448ecd2727774 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 20:25:35 +0100 Subject: [PATCH 39/72] add `find_inode` function do `impl Inode` --- src/sys/inode.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sys/inode.rs b/src/sys/inode.rs index d5cc47c..d391227 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -1,3 +1,8 @@ +use core::mem; + +use error::Error; +use buffer::Buffer; + /// An inode is a structure on the disk that represents a file, directory, /// symbolic link, etc. Inodes do not contain the data of the file / directory / /// etc. that they represent. Instead, they link to the blocks that actually @@ -6,6 +11,7 @@ /// array of inodes it is responsible for, and conversely every inode within a /// file system belongs to one of such tables (and one of such block groups). #[repr(C, packed)] +#[derive(Clone, Copy)] pub struct Inode { /// Type and Permissions (see below) pub type_perm: u16, @@ -60,6 +66,32 @@ pub struct Inode { pub _os_specific_2: [u8; 12], } +impl Inode { + pub unsafe fn find_inode<'a, E>( + haystack: &'a Buffer, + offset: usize, + size: usize, + ) -> Result<(Inode, usize), Error> + where + Error: From, + { + if size != mem::size_of::() { + unimplemented!("inodes with a size != 128"); + } + + let end = offset + size; + if haystack.len() < end { + return Err(Error::OutOfBounds(end)); + } + + let inode = haystack + .slice_unchecked(offset..end) + .dynamic_cast::(); + + Ok(inode) + } +} + bitflags! { pub struct TypePerm: u16 { /// FIFO From c798b2bdb2c9ed9cbf0a4115a69d886c4e938b7d Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 20:38:32 +0100 Subject: [PATCH 40/72] add Debug `impl`s --- src/sys/block_group.rs | 14 ++++++++++++ src/sys/inode.rs | 29 +++++++++++++++++++++++++ src/sys/superblock.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 4e5e65d..a856fbf 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -1,4 +1,5 @@ use core::mem; +use core::fmt::{self, Debug}; use alloc::Vec; @@ -36,6 +37,19 @@ pub struct BlockGroupDescriptor { _reserved: [u8; 14], } +impl Debug for BlockGroupDescriptor { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("BlockGroupDescriptor") + .field("block_usage_addr", unsafe { &self.block_usage_addr }) + .field("inode_usage_addr", unsafe { &self.inode_usage_addr }) + .field("inode_table_block", unsafe { &self.inode_table_block }) + .field("free_blocks_count", unsafe { &self.free_blocks_count }) + .field("free_inodes_count", unsafe { &self.free_inodes_count }) + .field("dirs_count", unsafe { &self.dirs_count }) + .finish() + } +} + impl BlockGroupDescriptor { pub unsafe fn find_descriptor<'a, E>( haystack: &'a Buffer, diff --git a/src/sys/inode.rs b/src/sys/inode.rs index d391227..f40015f 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -1,4 +1,5 @@ use core::mem; +use core::fmt::{self, Debug}; use error::Error; use buffer::Buffer; @@ -66,6 +67,34 @@ pub struct Inode { pub _os_specific_2: [u8; 12], } +impl Debug for Inode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Inode") + .field("type_perm", unsafe { &self.type_perm }) + .field("uid", unsafe { &self.uid }) + .field("size_low", unsafe { &self.size_low }) + .field("atime", unsafe { &self.atime }) + .field("ctime", unsafe { &self.ctime }) + .field("mtime", unsafe { &self.mtime }) + .field("dtime", unsafe { &self.dtime }) + .field("gid", unsafe { &self.gid }) + .field("hard_links", unsafe { &self.hard_links }) + .field("sectors_count", unsafe { &self.sectors_count }) + .field("flags", unsafe { &self.flags }) + .field("os_specific_1", &self._os_specific_1) + .field("direct_pointer", unsafe { &self.direct_pointer }) + .field("indirect_pointer", unsafe { &self.indirect_pointer }) + .field("doubly_indirect", unsafe { &self.doubly_indirect }) + .field("triply_indirect", unsafe { &self.triply_indirect }) + .field("gen_number", unsafe { &self.gen_number }) + .field("ext_attribute_block", unsafe { &self.ext_attribute_block }) + .field("size_high", unsafe { &self.size_high }) + .field("frag_block_addr", unsafe { &self.frag_block_addr }) + .field("os_specific_2", &self._os_specific_2) + .finish() + } +} + impl Inode { pub unsafe fn find_inode<'a, E>( haystack: &'a Buffer, diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 3d16b05..e1ab61d 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -1,4 +1,5 @@ use core::mem; +use core::fmt::{self, Debug}; use error::Error; use buffer::Buffer; @@ -144,6 +145,54 @@ pub struct Superblock { _reserved: [u8; 788], } +impl Debug for Superblock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Superblock") + .field("inodes_count", unsafe { &self.inodes_count }) + .field("blocks_count", unsafe { &self.blocks_count }) + .field("r_blocks_count", unsafe { &self.r_blocks_count }) + .field("free_blocks_count", unsafe { &self.free_blocks_count }) + .field("free_inodes_count", unsafe { &self.free_inodes_count }) + .field("first_data_block", unsafe { &self.first_data_block }) + .field("log_block_size", unsafe { &self.log_block_size }) + .field("log_frag_size", unsafe { &self.log_frag_size }) + .field("blocks_per_group", unsafe { &self.blocks_per_group }) + .field("frags_per_group", unsafe { &self.frags_per_group }) + .field("inodes_per_group", unsafe { &self.inodes_per_group }) + .field("mtime", unsafe { &self.mtime }) + .field("wtime", unsafe { &self.wtime }) + .field("mnt_count", unsafe { &self.mnt_count }) + .field("max_mnt_count", unsafe { &self.max_mnt_count }) + .field("magic", unsafe { &self.magic }) + .field("state", unsafe { &self.state }) + .field("errors", unsafe { &self.errors }) + .field("rev_minor", unsafe { &self.rev_minor }) + .field("lastcheck", unsafe { &self.lastcheck }) + .field("checkinterval", unsafe { &self.checkinterval }) + .field("creator_os", unsafe { &self.creator_os }) + .field("rev_major", unsafe { &self.rev_major }) + .field("block_uid", unsafe { &self.block_uid }) + .field("block_gid", unsafe { &self.block_gid }) + .field("first_inode", unsafe { &self.first_inode }) + .field("inode_size", unsafe { &self.inode_size }) + .field("block_group", unsafe { &self.block_group }) + .field("features_opt", unsafe { &self.features_opt }) + .field("features_req", unsafe { &self.features_req }) + .field("features_ronly", unsafe { &self.features_ronly }) + .field("fs_id", &self.fs_id) + .field("volume_name", &self.volume_name) + .field("last_mnt_path", &self.last_mnt_path.as_ref()) + .field("compression", unsafe { &self.compression }) + .field("prealloc_blocks_files", &self.prealloc_blocks_files) + .field("prealloc_blocks_dirs", &self.prealloc_blocks_dirs) + .field("journal_id", &self.journal_id) + .field("journal_inode", unsafe { &self.journal_inode }) + .field("journal_dev", unsafe { &self.journal_dev }) + .field("journal_orphan_head", unsafe { &self.journal_orphan_head }) + .finish() + } +} + impl Superblock { pub unsafe fn find<'a, E>( haystack: &'a Buffer, From 7dd27917bd8ac190807e9485c4c4a28452aad744 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 20:42:27 +0100 Subject: [PATCH 41/72] add `in_use` method for `Inode` to check whether there are any hard links --- src/sys/inode.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sys/inode.rs b/src/sys/inode.rs index f40015f..3e6241b 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -119,6 +119,10 @@ impl Inode { Ok(inode) } + + pub fn in_use(&self) -> bool { + self.hard_links > 0 + } } bitflags! { From 95533395d90816e90fff18fe40255faacae32f27 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 20:49:59 +0100 Subject: [PATCH 42/72] add methods for querying and manipulating inodes to `Ext2` --- src/fs.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/fs.rs b/src/fs.rs index 537f7a1..9fd028b 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -78,6 +78,48 @@ where Ok(()) } + pub fn update_inode( + &mut self, + &(ref inode, offset): &(Inode, usize), + ) -> Result<(), Error> { + let slice = BufferSlice::from_cast(inode, offset); + let commit = slice.commit(); + self.buffer.commit(commit).map_err(|err| Error::from(err)) + } + + pub fn inode_nth( + &self, + block_group: usize, + index: usize, + ) -> Option<(Inode, usize)> { + self.inodes_nth(block_group, index) + .and_then(|mut inodes| inodes.next()) + } + + pub fn inodes<'a>(&'a self, block_group: usize) -> Inodes<'a, B> { + self.inodes_nth(block_group, 1).unwrap() + } + + pub fn inodes_nth<'a>( + &'a self, + block_group: usize, + index: usize, + ) -> Option> { + assert!(index > 0, "inodes are 1-indexed"); + if index > self.inodes_count() { + None + } else { + Some(Inodes { + buffer: &self.buffer, + block_size: self.block_size(), + inode_size: self.inode_size(), + inodes_block: self.inodes_block(block_group), + inodes_count: self.inodes_count(), + index, + }) + } + } + fn superblock(&self) -> &Superblock { &self.superblock.inner } @@ -99,6 +141,14 @@ where } } + pub fn inodes_block(&self, block_group: usize) -> usize { + self.block_groups.inner[block_group].inode_table_block as _ + } + + pub fn inodes_count(&self) -> usize { + self.superblock().inodes_per_group as _ + } + pub fn block_group_count(&self) -> Result { self.superblock() .block_group_count() @@ -119,6 +169,35 @@ where } } +pub struct Inodes<'a, B: 'a + Buffer> { + buffer: &'a B, + block_size: usize, + inode_size: usize, + inodes_block: usize, + inodes_count: usize, + index: usize, +} + +impl<'a, B: 'a + Buffer> Iterator for Inodes<'a, B> +where + Error: From, +{ + type Item = (Inode, usize); + + fn next(&mut self) -> Option { + if self.index < self.inodes_count { + let offset = self.inodes_block * self.block_size + + (self.index - 1) * self.inode_size; + self.index += 1; + unsafe { + Inode::find_inode(self.buffer, offset, self.inode_size).ok() + } + } else { + None + } + } +} + #[cfg(test)] mod tests { use std::fs::File; @@ -151,4 +230,23 @@ mod tests { println!("version: {}.{}", vers.0, vers.1); assert_eq!(128, fs.inode_size()); } + + #[test] + fn inodes() { + let file = RefCell::new(File::open("ext2.bin").unwrap()); + let fs = Ext2::new(file); + + assert!( + fs.is_ok(), + "Err({:?})", + fs.err().unwrap_or_else(|| unreachable!()), + ); + + let fs = fs.unwrap(); + + let inodes = fs.inodes(0).filter(|inode| inode.0.in_use()); + for inode in inodes { + println!("{:?}", inode); + } + } } From d1905db9175e6caae0faf1871855bf613c48237c Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 21:09:48 +0100 Subject: [PATCH 43/72] make `update_global` and `update_inode` private --- src/fs.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index 9fd028b..dabbdfc 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -55,7 +55,8 @@ where }) } - pub fn update_global(&mut self) -> Result<(), Error> { + #[allow(dead_code)] + fn update_global(&mut self) -> Result<(), Error> { // superblock { let slice = BufferSlice::from_cast( @@ -78,7 +79,8 @@ where Ok(()) } - pub fn update_inode( + #[allow(dead_code)] + fn update_inode( &mut self, &(ref inode, offset): &(Inode, usize), ) -> Result<(), Error> { @@ -124,6 +126,7 @@ where &self.superblock.inner } + #[allow(dead_code)] fn superblock_mut(&mut self) -> &mut Superblock { &mut self.superblock.inner } From f816ebdbe7b212b76fdb2854221030ca42863e8a Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Mon, 19 Mar 2018 21:42:45 +0100 Subject: [PATCH 44/72] allow indexing inodes independent of the block group --- src/fs.rs | 65 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index dabbdfc..cdf80fd 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -89,36 +89,28 @@ where self.buffer.commit(commit).map_err(|err| Error::from(err)) } - pub fn inode_nth( - &self, - block_group: usize, - index: usize, - ) -> Option<(Inode, usize)> { - self.inodes_nth(block_group, index) - .and_then(|mut inodes| inodes.next()) + pub fn root_inode(&self) -> (Inode, usize) { + self.inode_nth(2).unwrap() } - pub fn inodes<'a>(&'a self, block_group: usize) -> Inodes<'a, B> { - self.inodes_nth(block_group, 1).unwrap() + pub fn inode_nth(&self, index: usize) -> Option<(Inode, usize)> { + self.inodes_nth(index).next() } - pub fn inodes_nth<'a>( - &'a self, - block_group: usize, - index: usize, - ) -> Option> { + pub fn inodes<'a>(&'a self) -> Inodes<'a, B> { + self.inodes_nth(1) + } + + pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, B> { assert!(index > 0, "inodes are 1-indexed"); - if index > self.inodes_count() { - None - } else { - Some(Inodes { - buffer: &self.buffer, - block_size: self.block_size(), - inode_size: self.inode_size(), - inodes_block: self.inodes_block(block_group), - inodes_count: self.inodes_count(), - index, - }) + Inodes { + buffer: &self.buffer, + block_groups: &self.block_groups.inner, + block_size: self.block_size(), + inode_size: self.inode_size(), + inodes_per_group: self.inodes_count(), + inodes_count: self.total_inodes_count(), + index, } } @@ -144,14 +136,14 @@ where } } - pub fn inodes_block(&self, block_group: usize) -> usize { - self.block_groups.inner[block_group].inode_table_block as _ - } - pub fn inodes_count(&self) -> usize { self.superblock().inodes_per_group as _ } + pub fn total_inodes_count(&self) -> usize { + self.superblock().inodes_count as _ + } + pub fn block_group_count(&self) -> Result { self.superblock() .block_group_count() @@ -174,9 +166,10 @@ where pub struct Inodes<'a, B: 'a + Buffer> { buffer: &'a B, + block_groups: &'a [BlockGroupDescriptor], block_size: usize, inode_size: usize, - inodes_block: usize, + inodes_per_group: usize, inodes_count: usize, index: usize, } @@ -189,9 +182,15 @@ where fn next(&mut self) -> Option { if self.index < self.inodes_count { - let offset = self.inodes_block * self.block_size - + (self.index - 1) * self.inode_size; + let block_group = (self.index - 1) / self.inodes_per_group; + let index = (self.index - 1) % self.inodes_per_group; self.index += 1; + + let inodes_block = + self.block_groups[block_group].inode_table_block as usize; + + let offset = + inodes_block * self.block_size + index * self.inode_size; unsafe { Inode::find_inode(self.buffer, offset, self.inode_size).ok() } @@ -247,7 +246,7 @@ mod tests { let fs = fs.unwrap(); - let inodes = fs.inodes(0).filter(|inode| inode.0.in_use()); + let inodes = fs.inodes().filter(|inode| inode.0.in_use()); for inode in inodes { println!("{:?}", inode); } From cb1de4b2e31f4b6fcece956ea87f1fae5136f3f0 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 07:21:24 +0100 Subject: [PATCH 45/72] add a way to address block in an ext2 fs --- src/block.rs | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 122 insertions(+) create mode 100644 src/block.rs diff --git a/src/block.rs b/src/block.rs new file mode 100644 index 0000000..357cefb --- /dev/null +++ b/src/block.rs @@ -0,0 +1,121 @@ +use core::marker::PhantomData; +use core::ops::{Add, Sub}; + +pub trait Size { + // log_block_size = log_2(block_size) - 10 + // i.e. block_size = 1024 << log_block_size + const LOG_SIZE: u32; + const SIZE: usize = 1024 << Self::LOG_SIZE; + const OFFSET_MASK: usize = Self::SIZE - 1; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Size1024; +impl Size for Size1024 { + const LOG_SIZE: u32 = 0; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Size2048; +impl Size for Size2048 { + const LOG_SIZE: u32 = 1; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Size4096; +impl Size for Size4096 { + const LOG_SIZE: u32 = 2; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Size8192; +impl Size for Size8192 { + const LOG_SIZE: u32 = 3; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Address { + block: usize, + offset: usize, + _phantom: PhantomData, +} + +impl Address { + pub fn new(block: usize, offset: usize) -> Address { + let block = block + offset >> (S::LOG_SIZE + 10); + let offset = offset & S::OFFSET_MASK; + let _phantom = PhantomData; + Address { + block, + offset, + _phantom, + } + } + + pub fn into_index(&self) -> Option { + self.block + .checked_shl(S::LOG_SIZE + 10) + .and_then(|block| block.checked_add(self.offset)) + } + + pub fn block(&self) -> usize { + self.block + } + + pub fn offset(&self) -> usize { + self.offset + } +} + +impl From for Address { + fn from(idx: usize) -> Address { + let block = idx >> (S::LOG_SIZE + 10); + let offset = idx & S::OFFSET_MASK; + Address::new(block, offset) + } +} + +impl Add for Address { + type Output = Address; + fn add(self, rhs: Address) -> Address { + let offset = self.offset + rhs.offset; + let block = offset >> (S::LOG_SIZE + 10); + let offset = offset & S::OFFSET_MASK; + Address::new(self.block + rhs.block + block, offset) + } +} + +impl Sub for Address { + type Output = Address; + fn sub(mut self, rhs: Address) -> Address { + if rhs.offset > self.offset { + self.offset += S::SIZE; + self.block -= 1; + } + let offset = self.offset - rhs.offset; + Address::new(self.block - rhs.block, offset) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn arithmetic() { + assert_eq!( + Address::::new(0, 1024), + Address::::new(1, 0), + ); + + let a = Address::::new(0, 1024); + let b = Address::::new(0, 1024); + assert_eq!(a + b, Address::::new(1, 0)); + assert_eq!((a + b).into_index(), Some(2048)); + + let a = Address::::new(0, 4096); + let b = Address::::new(0, 512); + assert_eq!(a - b, Address::::new(3, 512)); + assert_eq!((a + b).into_index(), Some(3584)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 3e10f43..4052a75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ extern crate core; pub mod error; pub mod sys; +pub mod block; pub mod buffer; pub mod fs; From e456764a20b268bdfe635c8711b4f0744015a40b Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:01:44 +0100 Subject: [PATCH 46/72] rename `ext2.bin` to `ext2.img` to better reflect its contents --- ext2.img | Bin 0 -> 4194304 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ext2.img diff --git a/ext2.img b/ext2.img new file mode 100644 index 0000000000000000000000000000000000000000..aa13d85580f8a1c5d625a06823825f898be6d778 GIT binary patch literal 4194304 zcmeF(&1)QG7y$5hXEruX(xhqyJ-K4_Qrs2~QoKlt^;SW9OHV=*Ecq%;LXwjS^{gK1 z_ecGxUUTzQ(32+*9{Mi`!BPrE1fde2$?morQTZ57Jeiqy-kE3K-@DJ;GAU^U z2<%ybYRvp#N=twrG=&ox8mD`-!Jk27h?|@OP(g z7xNrwj&GmG7Pq+XQyVPr`)U^u*j<5#;`R?m9EvzIbStm63VnCex;p^^1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNC9Ca`voR(!8R>kNS%uGP{#mS5Li5_sXi{hjY6YI7y&D@-56fY zi}&C8_^#r3Gm2|h^L)emuQFKnj+@85ar5f@=H5n6EB{N)+^@v8IJ25(8}es6$iK8j z{wvF?`QwrAROCGo@${Yil@0m7Y&`DY`n$YM{^I+WMgC&$t!=DI>TS#RRqS7h_&Va7 zw*E4^Z*Gx)Ddu0?qsZGHjovbM-+s)+E%I-FwGjje5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PJU^fh;CIkSbX{wvGKPtH(iq93M)3*~IkB?2)nQxv8_o zxRkEt)$H}@$;KohQU4u2EssxtKv{um*@4CpAkcLJ>c8uj)Px9> z7Eu4CsSG60bpqz34n2$U93|D~x6B+zvN>c8uj)Px9>7Eu4CsSG60bpqz34n z2$U93|D~x6B+zvN>c8uj)Px9>7Eu4CsSG60Z31~rsCWhRL_83&FQPYMe?(tI<9`HF zIuQGV5knCNBOZ*<2oUI8fhTLT)6>t4%}tFj_VvA1n>{zRSX(&$Ty1>x!qn(QQT-YL z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+Kqm_f#KRAy zN>-0;7I8RbS-m)jHjwgceqyG%U(H4rW}iI}M?d8~+1T9F_~QB*e+UrhRDq(NTlL>~ z7c}aBF#1>X{gqcw4!?NnWPS2%bAs3M!Akv3XMJY=eB;E`zxFRQFR&p%fB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAVA>HcIZF`0001BkiYdkzCy@=0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*26h7h3fW1Z literal 0 HcmV?d00001 From 5cfa684c031965a05568d358950894b25afc9952 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:03:09 +0100 Subject: [PATCH 47/72] rename `ext2.bin` to `ext2.img` --- src/fs.rs | 6 +++--- src/sys/superblock.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index cdf80fd..837a550 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -211,13 +211,13 @@ mod tests { #[test] fn file_len() { - let file = RefCell::new(File::open("ext2.bin").unwrap()); + let file = RefCell::new(File::open("ext2.img").unwrap()); assert_eq!(unsafe { file.slice_unchecked(1024..2048).len() }, 1024); } #[test] fn file() { - let file = RefCell::new(File::open("ext2.bin").unwrap()); + let file = RefCell::new(File::open("ext2.img").unwrap()); let fs = Ext2::new(file); assert!( @@ -235,7 +235,7 @@ mod tests { #[test] fn inodes() { - let file = RefCell::new(File::open("ext2.bin").unwrap()); + let file = RefCell::new(File::open("ext2.img").unwrap()); let fs = Ext2::new(file); assert!( diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index e1ab61d..77cb82a 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -313,7 +313,7 @@ mod tests { use std::cell::RefCell; use std::fs::File; - let file = RefCell::new(File::open("ext2.bin").unwrap()); + let file = RefCell::new(File::open("ext2.img").unwrap()); let superblock = unsafe { Superblock::find(&file) }; assert!( superblock.is_ok(), From 3dca5904a1e8117e1495561495229fc68dc70a4a Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:03:18 +0100 Subject: [PATCH 48/72] i accidentaly --- ext2.bin | Bin 4194304 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 ext2.bin diff --git a/ext2.bin b/ext2.bin deleted file mode 100644 index aa13d85580f8a1c5d625a06823825f898be6d778..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4194304 zcmeF(&1)QG7y$5hXEruX(xhqyJ-K4_Qrs2~QoKlt^;SW9OHV=*Ecq%;LXwjS^{gK1 z_ecGxUUTzQ(32+*9{Mi`!BPrE1fde2$?morQTZ57Jeiqy-kE3K-@DJ;GAU^U z2<%ybYRvp#N=twrG=&ox8mD`-!Jk27h?|@OP(g z7xNrwj&GmG7Pq+XQyVPr`)U^u*j<5#;`R?m9EvzIbStm63VnCex;p^^1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNC9Ca`voR(!8R>kNS%uGP{#mS5Li5_sXi{hjY6YI7y&D@-56fY zi}&C8_^#r3Gm2|h^L)emuQFKnj+@85ar5f@=H5n6EB{N)+^@v8IJ25(8}es6$iK8j z{wvF?`QwrAROCGo@${Yil@0m7Y&`DY`n$YM{^I+WMgC&$t!=DI>TS#RRqS7h_&Va7 zw*E4^Z*Gx)Ddu0?qsZGHjovbM-+s)+E%I-FwGjje5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PJU^fh;CIkSbX{wvGKPtH(iq93M)3*~IkB?2)nQxv8_o zxRkEt)$H}@$;KohQU4u2EssxtKv{um*@4CpAkcLJ>c8uj)Px9> z7Eu4CsSG60bpqz34n2$U93|D~x6B+zvN>c8uj)Px9>7Eu4CsSG60bpqz34n z2$U93|D~x6B+zvN>c8uj)Px9>7Eu4CsSG60Z31~rsCWhRL_83&FQPYMe?(tI<9`HF zIuQGV5knCNBOZ*<2oUI8fhTLT)6>t4%}tFj_VvA1n>{zRSX(&$Ty1>x!qn(QQT-YL z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+Kqm_f#KRAy zN>-0;7I8RbS-m)jHjwgceqyG%U(H4rW}iI}M?d8~+1T9F_~QB*e+UrhRDq(NTlL>~ z7c}aBF#1>X{gqcw4!?NnWPS2%bAs3M!Akv3XMJY=eB;E`zxFRQFR&p%fB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAVA>HcIZF`0001BkiYdkzCy@=0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*26h7h3fW1Z From 69b3ba755281d9b5e5a5c3bf61002d49ae70f3fe Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:13:21 +0100 Subject: [PATCH 49/72] `impl` `Debug`, `LowerHex`, `Display` for `Address` --- src/block.rs | 25 ++++++++++++++++++++++++- src/lib.rs | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/block.rs b/src/block.rs index 357cefb..4c43dc1 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,5 +1,6 @@ use core::marker::PhantomData; use core::ops::{Add, Sub}; +use core::fmt::{self, Debug, Display, LowerHex}; pub trait Size { // log_block_size = log_2(block_size) - 10 @@ -33,7 +34,7 @@ impl Size for Size8192 { const LOG_SIZE: u32 = 3; } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Address { block: usize, offset: usize, @@ -67,6 +68,28 @@ impl Address { } } +impl Debug for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = format!("Address<{}>", S::SIZE); + f.debug_struct(&name) + .field("block", &self.block) + .field("offset", &self.offset) + .finish() + } +} + +impl Display for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}:{}", self.block, self.offset) + } +} + +impl LowerHex for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:x}:{:x}", self.block, self.offset) + } +} + impl From for Address { fn from(idx: usize) -> Address { let block = idx >> (S::LOG_SIZE + 10); diff --git a/src/lib.rs b/src/lib.rs index 4052a75..da79cff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![feature(macro_lifetime_matcher)] #![cfg_attr(all(not(test), feature = "no_std"), no_std)] +#[macro_use] extern crate alloc; #[macro_use] extern crate bitflags; From e6ebd09b3e28dfb6f05e445a5edce14678279266 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:14:24 +0100 Subject: [PATCH 50/72] `derive` `PartialOrd` and `Ord` for `Address` --- src/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block.rs b/src/block.rs index 4c43dc1..92b77c3 100644 --- a/src/block.rs +++ b/src/block.rs @@ -34,7 +34,7 @@ impl Size for Size8192 { const LOG_SIZE: u32 = 3; } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Address { block: usize, offset: usize, From b55633205e3227764410a9e71538f8c64629872c Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:16:30 +0100 Subject: [PATCH 51/72] add `block_size` and `log_block_size` methods to `Address` --- src/block.rs | 8 ++++++++ src/lib.rs | 1 + 2 files changed, 9 insertions(+) diff --git a/src/block.rs b/src/block.rs index 92b77c3..3342ae6 100644 --- a/src/block.rs +++ b/src/block.rs @@ -59,6 +59,14 @@ impl Address { .and_then(|block| block.checked_add(self.offset)) } + pub const fn block_size(&self) -> usize { + S::SIZE + } + + pub const fn log_block_size(&self) -> u32 { + S::LOG_SIZE + } + pub fn block(&self) -> usize { self.block } diff --git a/src/lib.rs b/src/lib.rs index da79cff..c44f259 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![feature(specialization)] #![feature(swap_with_slice)] #![feature(macro_lifetime_matcher)] +#![feature(const_fn)] #![cfg_attr(all(not(test), feature = "no_std"), no_std)] #[macro_use] From 677c072b4550cd76e23426e16128c1d5b8e54c40 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:21:05 +0100 Subject: [PATCH 52/72] fix arithmetic errors --- src/block.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/block.rs b/src/block.rs index 3342ae6..7d267d5 100644 --- a/src/block.rs +++ b/src/block.rs @@ -43,7 +43,7 @@ pub struct Address { impl Address { pub fn new(block: usize, offset: usize) -> Address { - let block = block + offset >> (S::LOG_SIZE + 10); + let block = block + (offset >> (S::LOG_SIZE + 10)); let offset = offset & S::OFFSET_MASK; let _phantom = PhantomData; Address { @@ -147,6 +147,6 @@ mod tests { let a = Address::::new(0, 4096); let b = Address::::new(0, 512); assert_eq!(a - b, Address::::new(3, 512)); - assert_eq!((a + b).into_index(), Some(3584)); + assert_eq!((a - b).into_index(), Some(3584)); } } From 2966b628fa4c9d8cdde99613acdeeb21f2329578 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:30:40 +0100 Subject: [PATCH 53/72] rewrite how block addresses are constructed --- src/block.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/block.rs b/src/block.rs index 7d267d5..5423631 100644 --- a/src/block.rs +++ b/src/block.rs @@ -42,9 +42,7 @@ pub struct Address { } impl Address { - pub fn new(block: usize, offset: usize) -> Address { - let block = block + (offset >> (S::LOG_SIZE + 10)); - let offset = offset & S::OFFSET_MASK; + pub unsafe fn new_unchecked(block: usize, offset: usize) -> Address { let _phantom = PhantomData; Address { block, @@ -53,6 +51,12 @@ impl Address { } } + pub fn new(block: usize, offset: isize) -> Address { + let block = (block as isize + (offset >> (S::LOG_SIZE + 10))) as usize; + let offset = offset.abs() as usize & S::OFFSET_MASK; + unsafe { Address::new_unchecked(block, offset) } + } + pub fn into_index(&self) -> Option { self.block .checked_shl(S::LOG_SIZE + 10) @@ -102,29 +106,27 @@ impl From for Address { fn from(idx: usize) -> Address { let block = idx >> (S::LOG_SIZE + 10); let offset = idx & S::OFFSET_MASK; - Address::new(block, offset) + Address::new(block, offset as isize) } } impl Add for Address { type Output = Address; fn add(self, rhs: Address) -> Address { - let offset = self.offset + rhs.offset; - let block = offset >> (S::LOG_SIZE + 10); - let offset = offset & S::OFFSET_MASK; - Address::new(self.block + rhs.block + block, offset) + Address::new( + self.block + rhs.block, + (self.offset + rhs.offset) as isize, + ) } } impl Sub for Address { type Output = Address; - fn sub(mut self, rhs: Address) -> Address { - if rhs.offset > self.offset { - self.offset += S::SIZE; - self.block -= 1; - } - let offset = self.offset - rhs.offset; - Address::new(self.block - rhs.block, offset) + fn sub(self, rhs: Address) -> Address { + Address::new( + self.block + rhs.block, + self.offset as isize - rhs.offset as isize, + ) } } @@ -139,6 +141,11 @@ mod tests { Address::::new(1, 0), ); + assert_eq!( + Address::::new(2, -512), + Address::::new(1, 512), + ); + let a = Address::::new(0, 1024); let b = Address::::new(0, 1024); assert_eq!(a + b, Address::::new(1, 0)); From 63f02036012e9e80934fd50faa7b690d9cf7d795 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:33:17 +0100 Subject: [PATCH 54/72] add assert to block address unsafe constructos --- src/block.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/block.rs b/src/block.rs index 5423631..b9b353e 100644 --- a/src/block.rs +++ b/src/block.rs @@ -43,6 +43,7 @@ pub struct Address { impl Address { pub unsafe fn new_unchecked(block: usize, offset: usize) -> Address { + assert!(offset < S::SIZE, "offset out of block bounds"); let _phantom = PhantomData; Address { block, From 88b1e3b668c33e5a7312e7c16f00a19281b4da2b Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 10:42:22 +0100 Subject: [PATCH 55/72] `impl Step` for block `Address` to allow range iterating --- src/block.rs | 34 ++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 35 insertions(+) diff --git a/src/block.rs b/src/block.rs index b9b353e..96aa8b8 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,6 +1,8 @@ +use core::mem; use core::marker::PhantomData; use core::ops::{Add, Sub}; use core::fmt::{self, Debug, Display, LowerHex}; +use core::iter::Step; pub trait Size { // log_block_size = log_2(block_size) - 10 @@ -81,6 +83,38 @@ impl Address { } } +impl Step for Address { + fn steps_between(start: &Self, end: &Self) -> Option { + if end.block >= start.block { + Some(end.block - start.block) + } else { + None + } + } + + fn replace_one(&mut self) -> Self { + mem::replace(self, Address::new(1, 0)) + } + + fn replace_zero(&mut self) -> Self { + mem::replace(self, Address::new(0, 0)) + } + + fn add_one(&self) -> Self { + Address::new(self.block + 1, 0) + } + + fn sub_one(&self) -> Self { + Address::new(self.block - 1, 0) + } + + fn add_usize(&self, n: usize) -> Option { + self.block + .checked_add(n) + .map(|block| Address::new(block, 0)) + } +} + impl Debug for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let name = format!("Address<{}>", S::SIZE); diff --git a/src/lib.rs b/src/lib.rs index c44f259..9dd208d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(swap_with_slice)] #![feature(macro_lifetime_matcher)] #![feature(const_fn)] +#![feature(step_trait)] #![cfg_attr(all(not(test), feature = "no_std"), no_std)] #[macro_use] From 7e0af1b8f6bed94d46bf8de2d88f5336e8b3e616 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 11:05:56 +0100 Subject: [PATCH 56/72] add generic `Idx` type argument to `Buffer` and `Length` --- src/buffer/length.rs | 74 ++++++++++++++++++++++-------------------- src/buffer/mod.rs | 17 +++++----- src/fs.rs | 9 ++--- src/sys/block_group.rs | 12 +++---- src/sys/inode.rs | 6 ++-- src/sys/superblock.rs | 6 ++-- 6 files changed, 65 insertions(+), 59 deletions(-) diff --git a/src/buffer/length.rs b/src/buffer/length.rs index e198377..a370002 100644 --- a/src/buffer/length.rs +++ b/src/buffer/length.rs @@ -2,28 +2,30 @@ use core::fmt::{self, Debug, Display}; use core::cmp::Ordering; #[derive(Clone, Copy, Debug, Hash)] -pub enum Length { +pub enum Length { Unbounded, - Bounded(usize), + Bounded(Idx), } -impl Length { - pub fn try_len(&self) -> Option { +impl Length { + pub fn try_len(&self) -> Option { match *self { Length::Unbounded => None, Length::Bounded(n) => Some(n), } } - pub unsafe fn len(&self) -> usize { + pub unsafe fn len(&self) -> Idx { match *self { - Length::Unbounded => { - panic!("attempt to convert `Length::Unbounded` to `usize`") - } + Length::Unbounded => panic!( + "attempt to convert `Length::Unbounded` to `Length::Idx`" + ), Length::Bounded(n) => n, } } +} +impl Length { pub fn is_bounded(&self) -> bool { match *self { Length::Unbounded => false, @@ -32,62 +34,64 @@ impl Length { } } -impl Display for Length { +impl Display for Length { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(self, f) } } -impl PartialEq for Length { - fn eq(&self, rhs: &Length) -> bool { - match (*self, *rhs) { - (Length::Unbounded, _) => false, - (_, Length::Unbounded) => false, - (Length::Bounded(a), Length::Bounded(ref b)) => a.eq(b), +impl PartialEq for Length { + fn eq(&self, rhs: &Self) -> bool { + match (self, rhs) { + (&Length::Unbounded, _) => false, + (_, &Length::Unbounded) => false, + (&Length::Bounded(ref a), &Length::Bounded(ref b)) => a.eq(b), } } - fn ne(&self, rhs: &Length) -> bool { - match (*self, *rhs) { - (Length::Unbounded, _) => false, - (_, Length::Unbounded) => false, - (Length::Bounded(a), Length::Bounded(ref b)) => a.ne(b), + fn ne(&self, rhs: &Self) -> bool { + match (self, rhs) { + (&Length::Unbounded, _) => false, + (_, &Length::Unbounded) => false, + (&Length::Bounded(ref a), &Length::Bounded(ref b)) => a.ne(b), } } } -impl PartialEq for Length { - fn eq(&self, rhs: &usize) -> bool { +impl PartialEq for Length { + fn eq(&self, rhs: &Idx) -> bool { match *self { Length::Unbounded => false, - Length::Bounded(n) => n.eq(rhs), + Length::Bounded(ref n) => n.eq(rhs), } } - fn ne(&self, rhs: &usize) -> bool { + fn ne(&self, rhs: &Idx) -> bool { match *self { Length::Unbounded => false, - Length::Bounded(n) => n.eq(rhs), + Length::Bounded(ref n) => n.eq(rhs), } } } -impl PartialOrd for Length { - fn partial_cmp(&self, rhs: &Length) -> Option { - match (*self, *rhs) { - (Length::Unbounded, Length::Unbounded) => None, - (Length::Unbounded, _) => Some(Ordering::Greater), - (_, Length::Unbounded) => Some(Ordering::Less), - (Length::Bounded(a), Length::Bounded(ref b)) => a.partial_cmp(b), +impl PartialOrd for Length { + fn partial_cmp(&self, rhs: &Self) -> Option { + match (self, rhs) { + (&Length::Unbounded, &Length::Unbounded) => None, + (&Length::Unbounded, _) => Some(Ordering::Greater), + (_, &Length::Unbounded) => Some(Ordering::Less), + (&Length::Bounded(ref a), &Length::Bounded(ref b)) => { + a.partial_cmp(b) + } } } } -impl PartialOrd for Length { - fn partial_cmp(&self, rhs: &usize) -> Option { +impl PartialOrd for Length { + fn partial_cmp(&self, rhs: &Idx) -> Option { match *self { Length::Unbounded => Some(Ordering::Greater), - Length::Bounded(n) => n.partial_cmp(rhs), + Length::Bounded(ref n) => n.partial_cmp(rhs), } } } diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 6a7d137..7b52be0 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -11,23 +11,24 @@ use error::Infallible; pub mod length; use self::length::Length; -pub trait Buffer +pub trait Buffer where [T]: ToOwned, + Idx: PartialEq + PartialOrd, { type Error; - fn len(&self) -> Length; + fn len(&self) -> Length; fn commit( &mut self, slice: Option>, ) -> Result<(), Self::Error>; unsafe fn slice_unchecked<'a>( &'a self, - range: Range, + range: Range, ) -> BufferSlice<'a, T>; - fn slice<'a>(&'a self, range: Range) -> Option> { + fn slice<'a>(&'a self, range: Range) -> Option> { if self.len() >= range.end && self.len() > range.start { unsafe { Some(self.slice_unchecked(range)) } } else { @@ -214,14 +215,14 @@ impl DerefMut for BufferCommit { macro_rules! impl_slice { (@inner $buffer:ty $( , $lt:lifetime )* ) => { - impl<$( $lt, )* T> Buffer for $buffer + impl<$( $lt, )* T> Buffer for $buffer where T: Clone, [T]: ToOwned, { type Error = Infallible; - fn len(&self) -> Length { + fn len(&self) -> Length { Length::Bounded(>::as_ref(self).len()) } @@ -272,10 +273,10 @@ mod file { use super::{Buffer, BufferCommit, BufferSlice}; use super::length::Length; - impl Buffer for RefCell { + impl Buffer for RefCell { type Error = io::Error; - fn len(&self) -> Length { + fn len(&self) -> Length { Length::Bounded( self.borrow() .metadata() diff --git a/src/fs.rs b/src/fs.rs index 837a550..2acc507 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -2,6 +2,7 @@ use core::mem; use alloc::Vec; use error::Error; +use block::Address; // TODO use buffer::{Buffer, BufferSlice}; use sys::superblock::Superblock; use sys::block_group::BlockGroupDescriptor; @@ -20,13 +21,13 @@ impl From<(T, usize)> for Struct { } /// Safe wrapper for raw sys structs -pub struct Ext2> { +pub struct Ext2> { buffer: B, superblock: Struct, block_groups: Struct>, } -impl> Ext2 +impl> Ext2 where Error: From, { @@ -164,7 +165,7 @@ where } } -pub struct Inodes<'a, B: 'a + Buffer> { +pub struct Inodes<'a, B: 'a + Buffer> { buffer: &'a B, block_groups: &'a [BlockGroupDescriptor], block_size: usize, @@ -174,7 +175,7 @@ pub struct Inodes<'a, B: 'a + Buffer> { index: usize, } -impl<'a, B: 'a + Buffer> Iterator for Inodes<'a, B> +impl<'a, B: 'a + Buffer> Iterator for Inodes<'a, B> where Error: From, { diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index a856fbf..6963bc5 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -51,12 +51,12 @@ impl Debug for BlockGroupDescriptor { } impl BlockGroupDescriptor { - pub unsafe fn find_descriptor<'a, E>( - haystack: &'a Buffer, + pub unsafe fn find_descriptor>( + haystack: &B, offset: usize, ) -> Result<(BlockGroupDescriptor, usize), Error> where - Error: From, + Error: From, { let end = offset + mem::size_of::(); if haystack.len() < end { @@ -70,13 +70,13 @@ impl BlockGroupDescriptor { Ok(descr) } - pub unsafe fn find_descriptor_table<'a, E>( - haystack: &'a Buffer, + pub unsafe fn find_descriptor_table>( + haystack: &B, offset: usize, count: usize, ) -> Result<(Vec, usize), Error> where - Error: From, + Error: From, { let end = offset + count * mem::size_of::(); if haystack.len() < end { diff --git a/src/sys/inode.rs b/src/sys/inode.rs index 3e6241b..52ba803 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -96,13 +96,13 @@ impl Debug for Inode { } impl Inode { - pub unsafe fn find_inode<'a, E>( - haystack: &'a Buffer, + pub unsafe fn find_inode>( + haystack: &B, offset: usize, size: usize, ) -> Result<(Inode, usize), Error> where - Error: From, + Error: From, { if size != mem::size_of::() { unimplemented!("inodes with a size != 128"); diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 77cb82a..d2cb36c 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -194,11 +194,11 @@ impl Debug for Superblock { } impl Superblock { - pub unsafe fn find<'a, E>( - haystack: &'a Buffer, + pub unsafe fn find>( + haystack: &B, ) -> Result<(Superblock, usize), Error> where - Error: From, + Error: From, { let offset = 1024; let end = offset + mem::size_of::(); From 7c57c047bce4a10df0e060ce0b8fed0c66bfccb6 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:30:36 +0100 Subject: [PATCH 57/72] make `Buffer` generic over its index, instead of `usize` --- src/block.rs | 78 +++++++++++++-------- src/buffer/mod.rs | 153 ++++++++++++++++++++++++----------------- src/error.rs | 1 + src/fs.rs | 82 ++++++++++++++-------- src/sys/block_group.rs | 47 +++++++++---- src/sys/inode.rs | 18 +++-- src/sys/superblock.rs | 20 ++++-- 7 files changed, 251 insertions(+), 148 deletions(-) diff --git a/src/block.rs b/src/block.rs index 96aa8b8..88475e2 100644 --- a/src/block.rs +++ b/src/block.rs @@ -4,39 +4,33 @@ use core::ops::{Add, Sub}; use core::fmt::{self, Debug, Display, LowerHex}; use core::iter::Step; -pub trait Size { - // log_block_size = log_2(block_size) - 10 - // i.e. block_size = 1024 << log_block_size +pub trait Size: PartialOrd { + // log_block_size = log_2(block_size) const LOG_SIZE: u32; - const SIZE: usize = 1024 << Self::LOG_SIZE; + const SIZE: usize = 1 << Self::LOG_SIZE; const OFFSET_MASK: usize = Self::SIZE - 1; } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Size1024; -impl Size for Size1024 { - const LOG_SIZE: u32 = 0; +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct Size512; +impl Size for Size512 { + const LOG_SIZE: u32 = 9; } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Size2048; impl Size for Size2048 { - const LOG_SIZE: u32 = 1; + const LOG_SIZE: u32 = 11; } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Size4096; impl Size for Size4096 { - const LOG_SIZE: u32 = 2; + const LOG_SIZE: u32 = 12; } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Size8192; -impl Size for Size8192 { - const LOG_SIZE: u32 = 3; -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +/// Address in a physical sector +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Address { block: usize, offset: usize, @@ -55,14 +49,30 @@ impl Address { } pub fn new(block: usize, offset: isize) -> Address { - let block = (block as isize + (offset >> (S::LOG_SIZE + 10))) as usize; + let block = (block as isize + (offset >> S::LOG_SIZE)) as usize; let offset = offset.abs() as usize & S::OFFSET_MASK; unsafe { Address::new_unchecked(block, offset) } } + pub fn with_block_size( + block: usize, + offset: usize, + log_block_size: u32, + ) -> Address { + let log_diff = log_block_size as isize - S::LOG_SIZE as isize; + let top_offset = offset >> S::LOG_SIZE; + let offset = offset >> log_diff; + let block = block << log_diff | top_offset; + Address::new(block, offset as isize) + } + + pub fn index64(&self) -> u64 { + ((self.block as u64) << S::LOG_SIZE) + self.offset as u64 + } + pub fn into_index(&self) -> Option { self.block - .checked_shl(S::LOG_SIZE + 10) + .checked_shl(S::LOG_SIZE) .and_then(|block| block.checked_add(self.offset)) } @@ -137,9 +147,17 @@ impl LowerHex for Address { } } +impl From for Address { + fn from(idx: u64) -> Address { + let block = idx >> S::LOG_SIZE; + let offset = idx & S::OFFSET_MASK as u64; + Address::new(block as usize, offset as isize) + } +} + impl From for Address { fn from(idx: usize) -> Address { - let block = idx >> (S::LOG_SIZE + 10); + let block = idx >> S::LOG_SIZE; let offset = idx & S::OFFSET_MASK; Address::new(block, offset as isize) } @@ -172,13 +190,13 @@ mod tests { #[test] fn arithmetic() { assert_eq!( - Address::::new(0, 1024), - Address::::new(1, 0), + Address::::new(0, 512), + Address::::new(1, 0), ); assert_eq!( - Address::::new(2, -512), - Address::::new(1, 512), + Address::::new(2, -256), + Address::::new(1, 256), ); let a = Address::::new(0, 1024); @@ -186,9 +204,9 @@ mod tests { assert_eq!(a + b, Address::::new(1, 0)); assert_eq!((a + b).into_index(), Some(2048)); - let a = Address::::new(0, 4096); - let b = Address::::new(0, 512); - assert_eq!(a - b, Address::::new(3, 512)); - assert_eq!((a - b).into_index(), Some(3584)); + let a = Address::::new(0, 2048); + let b = Address::::new(0, 256); + assert_eq!(a - b, Address::::new(3, 256)); + assert_eq!((a - b).into_index(), Some(1792)); } } diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 7b52be0..d3b5446 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -7,6 +7,7 @@ use alloc::boxed::Box; use alloc::borrow::{Cow, ToOwned}; use error::Infallible; +use block::{Address, Size}; pub mod length; use self::length::Length; @@ -21,14 +22,17 @@ where fn len(&self) -> Length; fn commit( &mut self, - slice: Option>, + slice: Option>, ) -> Result<(), Self::Error>; unsafe fn slice_unchecked<'a>( &'a self, range: Range, - ) -> BufferSlice<'a, T>; + ) -> BufferSlice<'a, T, Idx>; - fn slice<'a>(&'a self, range: Range) -> Option> { + fn slice<'a>( + &'a self, + range: Range, + ) -> Option> { if self.len() >= range.end && self.len() > range.start { unsafe { Some(self.slice_unchecked(range)) } } else { @@ -37,29 +41,34 @@ where } } -pub struct BufferSlice<'a, T: 'a> +pub struct BufferSlice<'a, T: 'a, Idx> where [T]: ToOwned, { inner: Cow<'a, [T]>, - index: usize, + index: Idx, } -impl BufferSlice<'static, T> +impl BufferSlice<'static, T, Idx> where [T]: ToOwned, { - pub fn with_static(inner: &'static [T]) -> BufferSlice<'static, T> { + pub fn with_static(inner: &'static [T]) -> BufferSlice<'static, T, Idx> { BufferSlice { inner: Cow::Borrowed(inner), - index: 0, + index: Idx::default(), } } +} +impl BufferSlice<'static, T, Idx> +where + [T]: ToOwned, +{ pub fn new_owned( inner: <[T] as ToOwned>::Owned, - index: usize, - ) -> BufferSlice<'static, T> { + index: Idx, + ) -> BufferSlice<'static, T, Idx> { BufferSlice { inner: Cow::Owned(inner), index, @@ -67,11 +76,11 @@ where } } -impl<'a, T> BufferSlice<'a, T> +impl<'a, T, Idx> BufferSlice<'a, T, Idx> where [T]: ToOwned, { - pub fn new(inner: &'a [T], index: usize) -> BufferSlice<'a, T> { + pub fn new(inner: &'a [T], index: Idx) -> BufferSlice<'a, T, Idx> { BufferSlice { inner: Cow::Borrowed(inner), index, @@ -85,14 +94,13 @@ where } } - #[inline] - pub fn at_index(&self) -> usize { - self.index + pub fn at_index(&self) -> &Idx { + &self.index } } -impl<'a> BufferSlice<'a, u8> { - pub unsafe fn dynamic_cast(&self) -> (T, usize) { +impl<'a, Idx: Copy> BufferSlice<'a, u8, Idx> { + pub unsafe fn dynamic_cast(&self) -> (T, Idx) { assert!(self.inner.len() >= mem::size_of::()); let index = self.index; let cast = mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()); @@ -101,8 +109,8 @@ impl<'a> BufferSlice<'a, u8> { pub fn from_cast( cast: &'a T, - index: usize, - ) -> BufferSlice<'a, u8> { + index: Idx, + ) -> BufferSlice<'a, u8, Idx> { let len = mem::size_of::(); let ptr = cast as *const T as *const u8; let slice = unsafe { slice::from_raw_parts(ptr, len) }; @@ -110,11 +118,11 @@ impl<'a> BufferSlice<'a, u8> { } } -impl<'a, T> BufferSlice<'a, T> +impl<'a, T, Idx> BufferSlice<'a, T, Idx> where [T]: ToOwned>, { - pub fn commit(self) -> Option> { + pub fn commit(self) -> Option> { if self.is_mutated() { Some(BufferCommit::new(self.inner.into_owned(), self.index)) } else { @@ -123,7 +131,7 @@ where } } -impl<'a, T> AsRef<[T]> for BufferSlice<'a, T> +impl<'a, T, Idx> AsRef<[T]> for BufferSlice<'a, T, Idx> where [T]: ToOwned, { @@ -132,7 +140,7 @@ where } } -impl<'a, T> AsMut<[T]> for BufferSlice<'a, T> +impl<'a, T, Idx> AsMut<[T]> for BufferSlice<'a, T, Idx> where [T]: ToOwned, <[T] as ToOwned>::Owned: AsMut<[T]>, @@ -142,7 +150,7 @@ where } } -impl<'a, T> Deref for BufferSlice<'a, T> +impl<'a, T, Idx> Deref for BufferSlice<'a, T, Idx> where [T]: ToOwned, { @@ -153,7 +161,7 @@ where } } -impl<'a, T> DerefMut for BufferSlice<'a, T> +impl<'a, T, Idx> DerefMut for BufferSlice<'a, T, Idx> where [T]: ToOwned, <[T] as ToOwned>::Owned: AsMut<[T]>, @@ -163,17 +171,22 @@ where } } -pub struct BufferCommit { +pub struct BufferCommit { inner: Vec, - index: usize, + index: Idx, } -impl BufferCommit { - pub fn with_vec(inner: Vec) -> BufferCommit { - BufferCommit { inner, index: 0 } +impl BufferCommit { + pub fn with_vec(inner: Vec) -> BufferCommit { + BufferCommit { + inner, + index: Idx::default(), + } } +} - pub fn new(inner: Vec, index: usize) -> BufferCommit { +impl BufferCommit { + pub fn new(inner: Vec, index: Idx) -> BufferCommit { BufferCommit { inner, index } } @@ -181,25 +194,24 @@ impl BufferCommit { self.inner } - #[inline] - pub fn at_index(&self) -> usize { - self.index + pub fn at_index(&self) -> &Idx { + &self.index } } -impl AsRef<[T]> for BufferCommit { +impl AsRef<[T]> for BufferCommit { fn as_ref(&self) -> &[T] { self.inner.as_ref() } } -impl AsMut<[T]> for BufferCommit { +impl AsMut<[T]> for BufferCommit { fn as_mut(&mut self) -> &mut [T] { self.inner.as_mut() } } -impl Deref for BufferCommit { +impl Deref for BufferCommit { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -207,7 +219,7 @@ impl Deref for BufferCommit { } } -impl DerefMut for BufferCommit { +impl DerefMut for BufferCommit { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } @@ -215,20 +227,20 @@ impl DerefMut for BufferCommit { macro_rules! impl_slice { (@inner $buffer:ty $( , $lt:lifetime )* ) => { - impl<$( $lt, )* T> Buffer for $buffer + impl<$( $lt, )* S: Size + PartialOrd + Copy, T> Buffer> for $buffer where T: Clone, [T]: ToOwned, { type Error = Infallible; - fn len(&self) -> Length { - Length::Bounded(>::as_ref(self).len()) + fn len(&self) -> Length> { + Length::Bounded(Address::from(>::as_ref(self).len())) } - fn commit(&mut self, slice: Option>) -> Result<(), Infallible> { + fn commit(&mut self, slice: Option>>) -> Result<(), Infallible> { slice.map(|slice| { - let index = slice.at_index(); + let index = slice.at_index().index64() as usize; let end = index + slice.as_ref().len(); // XXX: it would be much better to drop the contents of dst // and move the contents of slice instead of cloning @@ -241,9 +253,10 @@ macro_rules! impl_slice { unsafe fn slice_unchecked<'a>( &'a self, - range: Range, - ) -> BufferSlice<'a, T> { + range: Range>, + ) -> BufferSlice<'a, T, Address> { let index = range.start; + let range = range.start.index64() as usize..range.end.index64() as usize; BufferSlice::new( >::as_ref(self).get_unchecked(range), index, @@ -270,33 +283,35 @@ mod file { use std::fs::File; use std::cell::RefCell; + use block::{Address, Size}; + use super::{Buffer, BufferCommit, BufferSlice}; use super::length::Length; - impl Buffer for RefCell { + impl Buffer> for RefCell { type Error = io::Error; - fn len(&self) -> Length { + fn len(&self) -> Length> { Length::Bounded( self.borrow() .metadata() - .map(|data| data.len() as usize) - .unwrap_or(0), + .map(|data| Address::from(data.len())) + .unwrap_or(Address::from(0_usize)), ) } fn commit( &mut self, - slice: Option>, + slice: Option>>, ) -> Result<(), Self::Error> { slice .map(|slice| { - let index = slice.at_index(); - let end = index + slice.as_ref().len(); + let index = *slice.at_index(); + let end = index + Address::from(slice.as_ref().len()); let mut refmut = self.borrow_mut(); refmut - .seek(SeekFrom::Start(index as u64)) - .and_then(|_| refmut.write(&slice.as_ref()[index..end])) + .seek(SeekFrom::Start(index.index64())) + .and_then(|_| refmut.write(slice.as_ref())) .map(|_| ()) }) .unwrap_or(Ok(())) @@ -304,15 +319,15 @@ mod file { unsafe fn slice_unchecked<'a>( &'a self, - range: Range, - ) -> BufferSlice<'a, u8> { + range: Range>, + ) -> BufferSlice<'a, u8, Address> { let index = range.start; let len = range.end - range.start; - let mut vec = Vec::with_capacity(len); - vec.set_len(len); + let mut vec = Vec::with_capacity(len.index64() as usize); + vec.set_len(len.index64() as usize); let mut refmut = self.borrow_mut(); refmut - .seek(SeekFrom::Start(index as u64)) + .seek(SeekFrom::Start(index.index64())) .and_then(|_| refmut.read_exact(&mut vec[..])) .unwrap_or_else(|err| { panic!("could't read from File Buffer: {:?}", err) @@ -322,14 +337,16 @@ mod file { fn slice<'a>( &'a self, - range: Range, - ) -> Option> { + range: Range>, + ) -> Option>> { let index = range.start; - let mut vec = Vec::with_capacity(range.end - range.start); + let mut vec = Vec::with_capacity( + (range.end - range.start).index64() as usize, + ); let mut refmut = self.borrow_mut(); refmut - .seek(SeekFrom::Start(index as u64)) - .and_then(|_| refmut.read_exact(&mut vec[range])) + .seek(SeekFrom::Start(index.index64())) + .and_then(|_| refmut.read_exact(&mut vec[..])) .map(move |_| BufferSlice::new_owned(vec, index)) .ok() } @@ -338,13 +355,19 @@ mod file { #[cfg(test)] mod tests { + use block::{Address, Size512}; use super::*; #[test] fn buffer() { let mut buffer = vec![0; 1024]; let commit = { - let mut slice = buffer.slice(256..512).unwrap(); + let mut slice = buffer + .slice( + Address::::from(256_usize) + ..Address::::from(512_usize), + ) + .unwrap(); slice.iter_mut().for_each(|x| *x = 1); slice.commit() }; diff --git a/src/error.rs b/src/error.rs index 83be4e2..7c3a8f9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,6 +6,7 @@ use std::io; pub enum Error { BadMagic(u16), OutOfBounds(usize), + AddressOutOfBounds(usize, usize, usize), BadBlockGroupCount(u32, u32), #[cfg(any(test, not(feature = "no_std")))] Io(io::Error), diff --git a/src/fs.rs b/src/fs.rs index 2acc507..1c90de1 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,41 +1,45 @@ use core::mem; +use core::marker::PhantomData; + use alloc::Vec; use error::Error; -use block::Address; // TODO +use block::{Address, Size}; use buffer::{Buffer, BufferSlice}; use sys::superblock::Superblock; use sys::block_group::BlockGroupDescriptor; use sys::inode::Inode; -struct Struct { +struct Struct { pub inner: T, - pub offset: usize, + pub offset: Address, } -impl From<(T, usize)> for Struct { +impl From<(T, Address)> for Struct { #[inline] - fn from((inner, offset): (T, usize)) -> Struct { + fn from((inner, offset): (T, Address)) -> Struct { Struct { inner, offset } } } /// Safe wrapper for raw sys structs -pub struct Ext2> { +pub struct Ext2>> { buffer: B, - superblock: Struct, - block_groups: Struct>, + superblock: Struct, + block_groups: Struct, S>, } -impl> Ext2 +impl>> Ext2 where Error: From, { - pub fn new(buffer: B) -> Result, Error> { + pub fn new(buffer: B) -> Result, Error> { let superblock = unsafe { Struct::from(Superblock::find(&buffer)?) }; - let block_size = superblock.inner.block_size(); - let block_groups_offset = - (superblock.inner.first_data_block as usize + 1) * block_size; + let block_groups_offset = Address::with_block_size( + superblock.inner.first_data_block as usize + 1, + 0, + superblock.inner.log_block_size + 10, + ); let block_groups_count = superblock .inner .block_group_count() @@ -74,7 +78,8 @@ where let slice = BufferSlice::from_cast(descr, offset); let commit = slice.commit(); self.buffer.commit(commit).map_err(|err| Error::from(err))?; - offset += mem::size_of::(); + offset = + offset + Address::from(mem::size_of::()); } Ok(()) @@ -83,35 +88,36 @@ where #[allow(dead_code)] fn update_inode( &mut self, - &(ref inode, offset): &(Inode, usize), + &(ref inode, offset): &(Inode, Address), ) -> Result<(), Error> { let slice = BufferSlice::from_cast(inode, offset); let commit = slice.commit(); self.buffer.commit(commit).map_err(|err| Error::from(err)) } - pub fn root_inode(&self) -> (Inode, usize) { + pub fn root_inode(&self) -> (Inode, Address) { self.inode_nth(2).unwrap() } - pub fn inode_nth(&self, index: usize) -> Option<(Inode, usize)> { + pub fn inode_nth(&self, index: usize) -> Option<(Inode, Address)> { self.inodes_nth(index).next() } - pub fn inodes<'a>(&'a self) -> Inodes<'a, B> { + pub fn inodes<'a>(&'a self) -> Inodes<'a, S, B> { self.inodes_nth(1) } - pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, B> { + pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, B> { assert!(index > 0, "inodes are 1-indexed"); Inodes { buffer: &self.buffer, block_groups: &self.block_groups.inner, - block_size: self.block_size(), + log_block_size: self.log_block_size(), inode_size: self.inode_size(), inodes_per_group: self.inodes_count(), inodes_count: self.total_inodes_count(), index, + _phantom: PhantomData, } } @@ -163,23 +169,29 @@ where pub fn block_size(&self) -> usize { self.superblock().block_size() } + + pub fn log_block_size(&self) -> u32 { + self.superblock().log_block_size + } } -pub struct Inodes<'a, B: 'a + Buffer> { +pub struct Inodes<'a, S: Size, B: 'a + Buffer>> { buffer: &'a B, block_groups: &'a [BlockGroupDescriptor], - block_size: usize, + log_block_size: u32, inode_size: usize, inodes_per_group: usize, inodes_count: usize, index: usize, + _phantom: PhantomData, } -impl<'a, B: 'a + Buffer> Iterator for Inodes<'a, B> +impl<'a, S: Size + Copy, B: 'a + Buffer>> Iterator + for Inodes<'a, S, B> where Error: From, { - type Item = (Inode, usize); + type Item = (Inode, Address); fn next(&mut self) -> Option { if self.index < self.inodes_count { @@ -190,8 +202,11 @@ where let inodes_block = self.block_groups[block_group].inode_table_block as usize; - let offset = - inodes_block * self.block_size + index * self.inode_size; + let offset = Address::with_block_size( + inodes_block, + index * self.inode_size, + self.log_block_size, + ); unsafe { Inode::find_inode(self.buffer, offset, self.inode_size).ok() } @@ -206,6 +221,7 @@ mod tests { use std::fs::File; use std::cell::RefCell; + use block::{Address, Size512}; use buffer::Buffer; use super::Ext2; @@ -213,13 +229,21 @@ mod tests { #[test] fn file_len() { let file = RefCell::new(File::open("ext2.img").unwrap()); - assert_eq!(unsafe { file.slice_unchecked(1024..2048).len() }, 1024); + assert_eq!( + unsafe { + file.slice_unchecked( + Address::::from(1024_usize) + ..Address::::from(2048_usize), + ).len() + }, + 1024 + ); } #[test] fn file() { let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::new(file); + let fs = Ext2::::new(file); assert!( fs.is_ok(), @@ -237,7 +261,7 @@ mod tests { #[test] fn inodes() { let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::new(file); + let fs = Ext2::::new(file); assert!( fs.is_ok(), diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 6963bc5..aeb8738 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -4,6 +4,7 @@ use core::fmt::{self, Debug}; use alloc::Vec; use error::Error; +use block::{Address, Size}; use buffer::Buffer; /// The Block Group Descriptor Table contains a descriptor for each block group @@ -51,16 +52,24 @@ impl Debug for BlockGroupDescriptor { } impl BlockGroupDescriptor { - pub unsafe fn find_descriptor>( + pub unsafe fn find_descriptor< + S: Size + Copy + PartialOrd, + B: Buffer>, + >( haystack: &B, - offset: usize, - ) -> Result<(BlockGroupDescriptor, usize), Error> + offset: Address, + ) -> Result<(BlockGroupDescriptor, Address), Error> where Error: From, { - let end = offset + mem::size_of::(); + let end = + offset + Address::from(mem::size_of::()); if haystack.len() < end { - return Err(Error::OutOfBounds(end)); + return Err(Error::AddressOutOfBounds( + end.block(), + end.offset(), + end.block_size(), + )); } let descr = haystack @@ -70,22 +79,31 @@ impl BlockGroupDescriptor { Ok(descr) } - pub unsafe fn find_descriptor_table>( + pub unsafe fn find_descriptor_table< + S: Size + Copy + PartialOrd, + B: Buffer>, + >( haystack: &B, - offset: usize, + offset: Address, count: usize, - ) -> Result<(Vec, usize), Error> + ) -> Result<(Vec, Address), Error> where Error: From, { - let end = offset + count * mem::size_of::(); + let end = offset + + Address::from(count * mem::size_of::()); if haystack.len() < end { - return Err(Error::OutOfBounds(end)); + return Err(Error::AddressOutOfBounds( + end.block(), + end.offset(), + end.block_size(), + )); } let mut vec = Vec::with_capacity(count); for i in 0..count { - let offset = offset + i * mem::size_of::(); + let offset = offset + + Address::from(i * mem::size_of::()); vec.push({ BlockGroupDescriptor::find_descriptor(haystack, offset)?.0 }); @@ -97,13 +115,18 @@ impl BlockGroupDescriptor { #[cfg(test)] mod tests { + use block::{Address, Size512}; use super::*; #[test] fn find() { let buffer = vec![0_u8; 4096]; let table = unsafe { - BlockGroupDescriptor::find_descriptor_table(&buffer, 2048, 8) + BlockGroupDescriptor::find_descriptor_table( + &buffer, + Address::::new(4, 0), + 8, + ) }; assert!( table.is_ok(), diff --git a/src/sys/inode.rs b/src/sys/inode.rs index 52ba803..bd37647 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -2,6 +2,7 @@ use core::mem; use core::fmt::{self, Debug}; use error::Error; +use block::{Address, Size}; use buffer::Buffer; /// An inode is a structure on the disk that represents a file, directory, @@ -96,11 +97,14 @@ impl Debug for Inode { } impl Inode { - pub unsafe fn find_inode>( + pub unsafe fn find_inode< + S: Size + Copy + PartialOrd, + B: Buffer>, + >( haystack: &B, - offset: usize, + offset: Address, size: usize, - ) -> Result<(Inode, usize), Error> + ) -> Result<(Inode, Address), Error> where Error: From, { @@ -108,9 +112,13 @@ impl Inode { unimplemented!("inodes with a size != 128"); } - let end = offset + size; + let end = offset + Address::from(size); if haystack.len() < end { - return Err(Error::OutOfBounds(end)); + return Err(Error::AddressOutOfBounds( + end.block(), + end.offset(), + end.block_size(), + )); } let inode = haystack diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index d2cb36c..8db45f3 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -2,6 +2,7 @@ use core::mem; use core::fmt::{self, Debug}; use error::Error; +use block::{Address, Size}; use buffer::Buffer; /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a @@ -194,16 +195,20 @@ impl Debug for Superblock { } impl Superblock { - pub unsafe fn find>( + pub unsafe fn find>>( haystack: &B, - ) -> Result<(Superblock, usize), Error> + ) -> Result<(Superblock, Address), Error> where Error: From, { - let offset = 1024; - let end = offset + mem::size_of::(); + let offset = Address::from(1024_usize); + let end = offset + Address::from(mem::size_of::()); if haystack.len() < end { - return Err(Error::OutOfBounds(end)); + return Err(Error::AddressOutOfBounds( + end.block(), + end.offset(), + end.block_size(), + )); } let superblock = { @@ -291,6 +296,7 @@ bitflags! { #[cfg(test)] mod tests { + use block::Size512; use super::*; #[test] @@ -299,7 +305,7 @@ mod tests { // magic buffer[1024 + 56] = EXT2_MAGIC as u8; buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; - let superblock = unsafe { Superblock::find(&buffer) }; + let superblock = unsafe { Superblock::find::(&buffer) }; assert!( superblock.is_ok(), "Err({:?})", @@ -314,7 +320,7 @@ mod tests { use std::fs::File; let file = RefCell::new(File::open("ext2.img").unwrap()); - let superblock = unsafe { Superblock::find(&file) }; + let superblock = unsafe { Superblock::find::(&file) }; assert!( superblock.is_ok(), "Err({:?})", From 764c4de6bf2a108cca99f1e866ccae5d2aa329d4 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:35:05 +0100 Subject: [PATCH 58/72] fix `with_block_size` --- src/block.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/block.rs b/src/block.rs index 88475e2..83af087 100644 --- a/src/block.rs +++ b/src/block.rs @@ -61,7 +61,7 @@ impl Address { ) -> Address { let log_diff = log_block_size as isize - S::LOG_SIZE as isize; let top_offset = offset >> S::LOG_SIZE; - let offset = offset >> log_diff; + let offset = offset & ((1 << log_block_size) - 1); let block = block << log_diff | top_offset; Address::new(block, offset as isize) } @@ -187,6 +187,19 @@ impl Sub for Address { mod tests { use super::*; + #[test] + fn conv() { + assert_eq!(Address::::new(0, 1024).into_index(), Some(1024)); + assert_eq!( + Address::::from(1024_usize).into_index(), + Some(1024) + ); + assert_eq!( + Address::::with_block_size(1, 256, 10).into_index(), + Some(1024 + 256) + ); + } + #[test] fn arithmetic() { assert_eq!( From fbdbeb284237f6df4b3251401787c13aa000822b Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:38:22 +0100 Subject: [PATCH 59/72] fix `Address::sub` --- src/block.rs | 2 +- src/fs.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/block.rs b/src/block.rs index 83af087..ad60f7a 100644 --- a/src/block.rs +++ b/src/block.rs @@ -177,7 +177,7 @@ impl Sub for Address { type Output = Address; fn sub(self, rhs: Address) -> Address { Address::new( - self.block + rhs.block, + self.block - rhs.block, self.offset as isize - rhs.offset as isize, ) } diff --git a/src/fs.rs b/src/fs.rs index 1c90de1..e100351 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -229,6 +229,11 @@ mod tests { #[test] fn file_len() { let file = RefCell::new(File::open("ext2.img").unwrap()); + assert_eq!( + Address::::from(2048_usize) + - Address::::from(1024_usize), + Address::::new(2, 0) + ); assert_eq!( unsafe { file.slice_unchecked( From 6e867492464c11b04684ee0c9f8cb4e58f8daa02 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:39:45 +0100 Subject: [PATCH 60/72] fix bad log(block_size) --- src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fs.rs b/src/fs.rs index e100351..9004ab2 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -171,7 +171,7 @@ where } pub fn log_block_size(&self) -> u32 { - self.superblock().log_block_size + self.superblock().log_block_size + 10 } } From ab069b60e6c5f89e2cb6be749d349ceb7e61839a Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:46:27 +0100 Subject: [PATCH 61/72] rename `block` to `sector` to better reflect its purpose --- src/buffer/mod.rs | 6 ++-- src/fs.rs | 4 +-- src/lib.rs | 2 +- src/{block.rs => sector.rs} | 64 ++++++++++++++++++------------------- src/sys/block_group.rs | 12 +++---- src/sys/inode.rs | 6 ++-- src/sys/superblock.rs | 8 ++--- 7 files changed, 51 insertions(+), 51 deletions(-) rename src/{block.rs => sector.rs} (75%) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index d3b5446..57b4ca5 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -7,7 +7,7 @@ use alloc::boxed::Box; use alloc::borrow::{Cow, ToOwned}; use error::Infallible; -use block::{Address, Size}; +use sector::{Address, Size}; pub mod length; use self::length::Length; @@ -283,7 +283,7 @@ mod file { use std::fs::File; use std::cell::RefCell; - use block::{Address, Size}; + use sector::{Address, Size}; use super::{Buffer, BufferCommit, BufferSlice}; use super::length::Length; @@ -355,7 +355,7 @@ mod file { #[cfg(test)] mod tests { - use block::{Address, Size512}; + use sector::{Address, Size512}; use super::*; #[test] diff --git a/src/fs.rs b/src/fs.rs index 9004ab2..f4a7d2a 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use alloc::Vec; use error::Error; -use block::{Address, Size}; +use sector::{Address, Size}; use buffer::{Buffer, BufferSlice}; use sys::superblock::Superblock; use sys::block_group::BlockGroupDescriptor; @@ -221,7 +221,7 @@ mod tests { use std::fs::File; use std::cell::RefCell; - use block::{Address, Size512}; + use sector::{Address, Size512}; use buffer::Buffer; use super::Ext2; diff --git a/src/lib.rs b/src/lib.rs index 9dd208d..b803f88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ extern crate core; pub mod error; pub mod sys; -pub mod block; +pub mod sector; pub mod buffer; pub mod fs; diff --git a/src/block.rs b/src/sector.rs similarity index 75% rename from src/block.rs rename to src/sector.rs index ad60f7a..997f4f8 100644 --- a/src/block.rs +++ b/src/sector.rs @@ -5,7 +5,7 @@ use core::fmt::{self, Debug, Display, LowerHex}; use core::iter::Step; pub trait Size: PartialOrd { - // log_block_size = log_2(block_size) + // log_sector_size = log_2(sector_size) const LOG_SIZE: u32; const SIZE: usize = 1 << Self::LOG_SIZE; const OFFSET_MASK: usize = Self::SIZE - 1; @@ -32,26 +32,26 @@ impl Size for Size4096 { /// Address in a physical sector #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Address { - block: usize, + sector: usize, offset: usize, _phantom: PhantomData, } impl Address { - pub unsafe fn new_unchecked(block: usize, offset: usize) -> Address { - assert!(offset < S::SIZE, "offset out of block bounds"); + pub unsafe fn new_unchecked(sector: usize, offset: usize) -> Address { + assert!(offset < S::SIZE, "offset out of sector bounds"); let _phantom = PhantomData; Address { - block, + sector, offset, _phantom, } } - pub fn new(block: usize, offset: isize) -> Address { - let block = (block as isize + (offset >> S::LOG_SIZE)) as usize; + pub fn new(sector: usize, offset: isize) -> Address { + let sector = (sector as isize + (offset >> S::LOG_SIZE)) as usize; let offset = offset.abs() as usize & S::OFFSET_MASK; - unsafe { Address::new_unchecked(block, offset) } + unsafe { Address::new_unchecked(sector, offset) } } pub fn with_block_size( @@ -62,30 +62,30 @@ impl Address { let log_diff = log_block_size as isize - S::LOG_SIZE as isize; let top_offset = offset >> S::LOG_SIZE; let offset = offset & ((1 << log_block_size) - 1); - let block = block << log_diff | top_offset; - Address::new(block, offset as isize) + let sector = block << log_diff | top_offset; + Address::new(sector, offset as isize) } pub fn index64(&self) -> u64 { - ((self.block as u64) << S::LOG_SIZE) + self.offset as u64 + ((self.sector as u64) << S::LOG_SIZE) + self.offset as u64 } pub fn into_index(&self) -> Option { - self.block + self.sector .checked_shl(S::LOG_SIZE) - .and_then(|block| block.checked_add(self.offset)) + .and_then(|sector| sector.checked_add(self.offset)) } - pub const fn block_size(&self) -> usize { + pub const fn sector_size(&self) -> usize { S::SIZE } - pub const fn log_block_size(&self) -> u32 { + pub const fn log_sector_size(&self) -> u32 { S::LOG_SIZE } - pub fn block(&self) -> usize { - self.block + pub fn sector(&self) -> usize { + self.sector } pub fn offset(&self) -> usize { @@ -95,8 +95,8 @@ impl Address { impl Step for Address { fn steps_between(start: &Self, end: &Self) -> Option { - if end.block >= start.block { - Some(end.block - start.block) + if end.sector >= start.sector { + Some(end.sector - start.sector) } else { None } @@ -111,17 +111,17 @@ impl Step for Address { } fn add_one(&self) -> Self { - Address::new(self.block + 1, 0) + Address::new(self.sector + 1, 0) } fn sub_one(&self) -> Self { - Address::new(self.block - 1, 0) + Address::new(self.sector - 1, 0) } fn add_usize(&self, n: usize) -> Option { - self.block + self.sector .checked_add(n) - .map(|block| Address::new(block, 0)) + .map(|sector| Address::new(sector, 0)) } } @@ -129,7 +129,7 @@ impl Debug for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let name = format!("Address<{}>", S::SIZE); f.debug_struct(&name) - .field("block", &self.block) + .field("sector", &self.sector) .field("offset", &self.offset) .finish() } @@ -137,29 +137,29 @@ impl Debug for Address { impl Display for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}:{}", self.block, self.offset) + write!(f, "{}:{}", self.sector, self.offset) } } impl LowerHex for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:x}:{:x}", self.block, self.offset) + write!(f, "{:x}:{:x}", self.sector, self.offset) } } impl From for Address { fn from(idx: u64) -> Address { - let block = idx >> S::LOG_SIZE; + let sector = idx >> S::LOG_SIZE; let offset = idx & S::OFFSET_MASK as u64; - Address::new(block as usize, offset as isize) + Address::new(sector as usize, offset as isize) } } impl From for Address { fn from(idx: usize) -> Address { - let block = idx >> S::LOG_SIZE; + let sector = idx >> S::LOG_SIZE; let offset = idx & S::OFFSET_MASK; - Address::new(block, offset as isize) + Address::new(sector, offset as isize) } } @@ -167,7 +167,7 @@ impl Add for Address { type Output = Address; fn add(self, rhs: Address) -> Address { Address::new( - self.block + rhs.block, + self.sector + rhs.sector, (self.offset + rhs.offset) as isize, ) } @@ -177,7 +177,7 @@ impl Sub for Address { type Output = Address; fn sub(self, rhs: Address) -> Address { Address::new( - self.block - rhs.block, + self.sector - rhs.sector, self.offset as isize - rhs.offset as isize, ) } diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index aeb8738..56c9dbf 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -4,7 +4,7 @@ use core::fmt::{self, Debug}; use alloc::Vec; use error::Error; -use block::{Address, Size}; +use sector::{Address, Size}; use buffer::Buffer; /// The Block Group Descriptor Table contains a descriptor for each block group @@ -66,9 +66,9 @@ impl BlockGroupDescriptor { offset + Address::from(mem::size_of::()); if haystack.len() < end { return Err(Error::AddressOutOfBounds( - end.block(), + end.sector(), end.offset(), - end.block_size(), + end.sector_size(), )); } @@ -94,9 +94,9 @@ impl BlockGroupDescriptor { + Address::from(count * mem::size_of::()); if haystack.len() < end { return Err(Error::AddressOutOfBounds( - end.block(), + end.sector(), end.offset(), - end.block_size(), + end.sector_size(), )); } @@ -115,7 +115,7 @@ impl BlockGroupDescriptor { #[cfg(test)] mod tests { - use block::{Address, Size512}; + use sector::{Address, Size512}; use super::*; #[test] diff --git a/src/sys/inode.rs b/src/sys/inode.rs index bd37647..44f8cd0 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -2,7 +2,7 @@ use core::mem; use core::fmt::{self, Debug}; use error::Error; -use block::{Address, Size}; +use sector::{Address, Size}; use buffer::Buffer; /// An inode is a structure on the disk that represents a file, directory, @@ -115,9 +115,9 @@ impl Inode { let end = offset + Address::from(size); if haystack.len() < end { return Err(Error::AddressOutOfBounds( - end.block(), + end.sector(), end.offset(), - end.block_size(), + end.sector_size(), )); } diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 8db45f3..eab0395 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -2,7 +2,7 @@ use core::mem; use core::fmt::{self, Debug}; use error::Error; -use block::{Address, Size}; +use sector::{Address, Size}; use buffer::Buffer; /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a @@ -205,9 +205,9 @@ impl Superblock { let end = offset + Address::from(mem::size_of::()); if haystack.len() < end { return Err(Error::AddressOutOfBounds( - end.block(), + end.sector(), end.offset(), - end.block_size(), + end.sector_size(), )); } @@ -296,7 +296,7 @@ bitflags! { #[cfg(test)] mod tests { - use block::Size512; + use sector::Size512; use super::*; #[test] From ce162aae909243ca1b2dab86dee8562d67d3d41a Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:49:44 +0100 Subject: [PATCH 62/72] rename `buffer` to `volume` to better reflect its purpose --- src/fs.rs | 50 +++++++------- src/lib.rs | 2 +- src/sys/block_group.rs | 18 ++--- src/sys/inode.rs | 8 +-- src/sys/superblock.rs | 16 ++--- src/{buffer => volume}/length.rs | 0 src/{buffer => volume}/mod.rs | 114 +++++++++++++++---------------- 7 files changed, 104 insertions(+), 104 deletions(-) rename src/{buffer => volume}/length.rs (100%) rename src/{buffer => volume}/mod.rs (73%) diff --git a/src/fs.rs b/src/fs.rs index f4a7d2a..0e3f567 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -5,7 +5,7 @@ use alloc::Vec; use error::Error; use sector::{Address, Size}; -use buffer::{Buffer, BufferSlice}; +use volume::{Volume, VolumeSlice}; use sys::superblock::Superblock; use sys::block_group::BlockGroupDescriptor; use sys::inode::Inode; @@ -23,18 +23,18 @@ impl From<(T, Address)> for Struct { } /// Safe wrapper for raw sys structs -pub struct Ext2>> { - buffer: B, +pub struct Ext2>> { + volume: V, superblock: Struct, block_groups: Struct, S>, } -impl>> Ext2 +impl>> Ext2 where - Error: From, + Error: From, { - pub fn new(buffer: B) -> Result, Error> { - let superblock = unsafe { Struct::from(Superblock::find(&buffer)?) }; + pub fn new(volume: V) -> Result, Error> { + let superblock = unsafe { Struct::from(Superblock::find(&volume)?) }; let block_groups_offset = Address::with_block_size( superblock.inner.first_data_block as usize + 1, 0, @@ -47,14 +47,14 @@ where .map_err(|(a, b)| Error::BadBlockGroupCount(a, b))?; let block_groups = unsafe { BlockGroupDescriptor::find_descriptor_table( - &buffer, + &volume, block_groups_offset, block_groups_count, )? }; let block_groups = Struct::from(block_groups); Ok(Ext2 { - buffer, + volume, superblock, block_groups, }) @@ -64,20 +64,20 @@ where fn update_global(&mut self) -> Result<(), Error> { // superblock { - let slice = BufferSlice::from_cast( + let slice = VolumeSlice::from_cast( &self.superblock.inner, self.superblock.offset, ); let commit = slice.commit(); - self.buffer.commit(commit).map_err(|err| Error::from(err))?; + self.volume.commit(commit).map_err(|err| Error::from(err))?; } // block group descriptors let mut offset = self.block_groups.offset; for descr in &self.block_groups.inner { - let slice = BufferSlice::from_cast(descr, offset); + let slice = VolumeSlice::from_cast(descr, offset); let commit = slice.commit(); - self.buffer.commit(commit).map_err(|err| Error::from(err))?; + self.volume.commit(commit).map_err(|err| Error::from(err))?; offset = offset + Address::from(mem::size_of::()); } @@ -90,9 +90,9 @@ where &mut self, &(ref inode, offset): &(Inode, Address), ) -> Result<(), Error> { - let slice = BufferSlice::from_cast(inode, offset); + let slice = VolumeSlice::from_cast(inode, offset); let commit = slice.commit(); - self.buffer.commit(commit).map_err(|err| Error::from(err)) + self.volume.commit(commit).map_err(|err| Error::from(err)) } pub fn root_inode(&self) -> (Inode, Address) { @@ -103,14 +103,14 @@ where self.inodes_nth(index).next() } - pub fn inodes<'a>(&'a self) -> Inodes<'a, S, B> { + pub fn inodes<'a>(&'a self) -> Inodes<'a, S, V> { self.inodes_nth(1) } - pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, B> { + pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, V> { assert!(index > 0, "inodes are 1-indexed"); Inodes { - buffer: &self.buffer, + volume: &self.volume, block_groups: &self.block_groups.inner, log_block_size: self.log_block_size(), inode_size: self.inode_size(), @@ -175,8 +175,8 @@ where } } -pub struct Inodes<'a, S: Size, B: 'a + Buffer>> { - buffer: &'a B, +pub struct Inodes<'a, S: Size, V: 'a + Volume>> { + volume: &'a V, block_groups: &'a [BlockGroupDescriptor], log_block_size: u32, inode_size: usize, @@ -186,10 +186,10 @@ pub struct Inodes<'a, S: Size, B: 'a + Buffer>> { _phantom: PhantomData, } -impl<'a, S: Size + Copy, B: 'a + Buffer>> Iterator - for Inodes<'a, S, B> +impl<'a, S: Size + Copy, V: 'a + Volume>> Iterator + for Inodes<'a, S, V> where - Error: From, + Error: From, { type Item = (Inode, Address); @@ -208,7 +208,7 @@ where self.log_block_size, ); unsafe { - Inode::find_inode(self.buffer, offset, self.inode_size).ok() + Inode::find_inode(self.volume, offset, self.inode_size).ok() } } else { None @@ -222,7 +222,7 @@ mod tests { use std::cell::RefCell; use sector::{Address, Size512}; - use buffer::Buffer; + use volume::Volume; use super::Ext2; diff --git a/src/lib.rs b/src/lib.rs index b803f88..0e47614 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate core; pub mod error; pub mod sys; pub mod sector; -pub mod buffer; +pub mod volume; pub mod fs; #[cfg(test)] diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 56c9dbf..2cc40e7 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -5,7 +5,7 @@ use alloc::Vec; use error::Error; use sector::{Address, Size}; -use buffer::Buffer; +use volume::Volume; /// The Block Group Descriptor Table contains a descriptor for each block group /// within the file system. The number of block groups within the file system, @@ -54,13 +54,13 @@ impl Debug for BlockGroupDescriptor { impl BlockGroupDescriptor { pub unsafe fn find_descriptor< S: Size + Copy + PartialOrd, - B: Buffer>, + V: Volume>, >( - haystack: &B, + haystack: &V, offset: Address, ) -> Result<(BlockGroupDescriptor, Address), Error> where - Error: From, + Error: From, { let end = offset + Address::from(mem::size_of::()); @@ -81,14 +81,14 @@ impl BlockGroupDescriptor { pub unsafe fn find_descriptor_table< S: Size + Copy + PartialOrd, - B: Buffer>, + V: Volume>, >( - haystack: &B, + haystack: &V, offset: Address, count: usize, ) -> Result<(Vec, Address), Error> where - Error: From, + Error: From, { let end = offset + Address::from(count * mem::size_of::()); @@ -120,10 +120,10 @@ mod tests { #[test] fn find() { - let buffer = vec![0_u8; 4096]; + let volume = vec![0_u8; 4096]; let table = unsafe { BlockGroupDescriptor::find_descriptor_table( - &buffer, + &volume, Address::::new(4, 0), 8, ) diff --git a/src/sys/inode.rs b/src/sys/inode.rs index 44f8cd0..e537ccb 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -3,7 +3,7 @@ use core::fmt::{self, Debug}; use error::Error; use sector::{Address, Size}; -use buffer::Buffer; +use volume::Volume; /// An inode is a structure on the disk that represents a file, directory, /// symbolic link, etc. Inodes do not contain the data of the file / directory / @@ -99,14 +99,14 @@ impl Debug for Inode { impl Inode { pub unsafe fn find_inode< S: Size + Copy + PartialOrd, - B: Buffer>, + V: Volume>, >( - haystack: &B, + haystack: &V, offset: Address, size: usize, ) -> Result<(Inode, Address), Error> where - Error: From, + Error: From, { if size != mem::size_of::() { unimplemented!("inodes with a size != 128"); diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index eab0395..6f44b6a 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -3,7 +3,7 @@ use core::fmt::{self, Debug}; use error::Error; use sector::{Address, Size}; -use buffer::Buffer; +use volume::Volume; /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a /// volume @@ -195,11 +195,11 @@ impl Debug for Superblock { } impl Superblock { - pub unsafe fn find>>( - haystack: &B, + pub unsafe fn find>>( + haystack: &V, ) -> Result<(Superblock, Address), Error> where - Error: From, + Error: From, { let offset = Address::from(1024_usize); let end = offset + Address::from(mem::size_of::()); @@ -301,11 +301,11 @@ mod tests { #[test] fn find() { - let mut buffer = vec![0_u8; 4096]; + let mut volume = vec![0_u8; 4096]; // magic - buffer[1024 + 56] = EXT2_MAGIC as u8; - buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; - let superblock = unsafe { Superblock::find::(&buffer) }; + volume[1024 + 56] = EXT2_MAGIC as u8; + volume[1024 + 57] = (EXT2_MAGIC >> 8) as u8; + let superblock = unsafe { Superblock::find::(&volume) }; assert!( superblock.is_ok(), "Err({:?})", diff --git a/src/buffer/length.rs b/src/volume/length.rs similarity index 100% rename from src/buffer/length.rs rename to src/volume/length.rs diff --git a/src/buffer/mod.rs b/src/volume/mod.rs similarity index 73% rename from src/buffer/mod.rs rename to src/volume/mod.rs index 57b4ca5..165bd3f 100644 --- a/src/buffer/mod.rs +++ b/src/volume/mod.rs @@ -12,7 +12,7 @@ use sector::{Address, Size}; pub mod length; use self::length::Length; -pub trait Buffer +pub trait Volume where [T]: ToOwned, Idx: PartialEq + PartialOrd, @@ -22,17 +22,17 @@ where fn len(&self) -> Length; fn commit( &mut self, - slice: Option>, + slice: Option>, ) -> Result<(), Self::Error>; unsafe fn slice_unchecked<'a>( &'a self, range: Range, - ) -> BufferSlice<'a, T, Idx>; + ) -> VolumeSlice<'a, T, Idx>; fn slice<'a>( &'a self, range: Range, - ) -> Option> { + ) -> Option> { if self.len() >= range.end && self.len() > range.start { unsafe { Some(self.slice_unchecked(range)) } } else { @@ -41,7 +41,7 @@ where } } -pub struct BufferSlice<'a, T: 'a, Idx> +pub struct VolumeSlice<'a, T: 'a, Idx> where [T]: ToOwned, { @@ -49,39 +49,39 @@ where index: Idx, } -impl BufferSlice<'static, T, Idx> +impl VolumeSlice<'static, T, Idx> where [T]: ToOwned, { - pub fn with_static(inner: &'static [T]) -> BufferSlice<'static, T, Idx> { - BufferSlice { + pub fn with_static(inner: &'static [T]) -> VolumeSlice<'static, T, Idx> { + VolumeSlice { inner: Cow::Borrowed(inner), index: Idx::default(), } } } -impl BufferSlice<'static, T, Idx> +impl VolumeSlice<'static, T, Idx> where [T]: ToOwned, { pub fn new_owned( inner: <[T] as ToOwned>::Owned, index: Idx, - ) -> BufferSlice<'static, T, Idx> { - BufferSlice { + ) -> VolumeSlice<'static, T, Idx> { + VolumeSlice { inner: Cow::Owned(inner), index, } } } -impl<'a, T, Idx> BufferSlice<'a, T, Idx> +impl<'a, T, Idx> VolumeSlice<'a, T, Idx> where [T]: ToOwned, { - pub fn new(inner: &'a [T], index: Idx) -> BufferSlice<'a, T, Idx> { - BufferSlice { + pub fn new(inner: &'a [T], index: Idx) -> VolumeSlice<'a, T, Idx> { + VolumeSlice { inner: Cow::Borrowed(inner), index, } @@ -99,7 +99,7 @@ where } } -impl<'a, Idx: Copy> BufferSlice<'a, u8, Idx> { +impl<'a, Idx: Copy> VolumeSlice<'a, u8, Idx> { pub unsafe fn dynamic_cast(&self) -> (T, Idx) { assert!(self.inner.len() >= mem::size_of::()); let index = self.index; @@ -110,28 +110,28 @@ impl<'a, Idx: Copy> BufferSlice<'a, u8, Idx> { pub fn from_cast( cast: &'a T, index: Idx, - ) -> BufferSlice<'a, u8, Idx> { + ) -> VolumeSlice<'a, u8, Idx> { let len = mem::size_of::(); let ptr = cast as *const T as *const u8; let slice = unsafe { slice::from_raw_parts(ptr, len) }; - BufferSlice::new(slice, index) + VolumeSlice::new(slice, index) } } -impl<'a, T, Idx> BufferSlice<'a, T, Idx> +impl<'a, T, Idx> VolumeSlice<'a, T, Idx> where [T]: ToOwned>, { - pub fn commit(self) -> Option> { + pub fn commit(self) -> Option> { if self.is_mutated() { - Some(BufferCommit::new(self.inner.into_owned(), self.index)) + Some(VolumeCommit::new(self.inner.into_owned(), self.index)) } else { None } } } -impl<'a, T, Idx> AsRef<[T]> for BufferSlice<'a, T, Idx> +impl<'a, T, Idx> AsRef<[T]> for VolumeSlice<'a, T, Idx> where [T]: ToOwned, { @@ -140,7 +140,7 @@ where } } -impl<'a, T, Idx> AsMut<[T]> for BufferSlice<'a, T, Idx> +impl<'a, T, Idx> AsMut<[T]> for VolumeSlice<'a, T, Idx> where [T]: ToOwned, <[T] as ToOwned>::Owned: AsMut<[T]>, @@ -150,7 +150,7 @@ where } } -impl<'a, T, Idx> Deref for BufferSlice<'a, T, Idx> +impl<'a, T, Idx> Deref for VolumeSlice<'a, T, Idx> where [T]: ToOwned, { @@ -161,7 +161,7 @@ where } } -impl<'a, T, Idx> DerefMut for BufferSlice<'a, T, Idx> +impl<'a, T, Idx> DerefMut for VolumeSlice<'a, T, Idx> where [T]: ToOwned, <[T] as ToOwned>::Owned: AsMut<[T]>, @@ -171,23 +171,23 @@ where } } -pub struct BufferCommit { +pub struct VolumeCommit { inner: Vec, index: Idx, } -impl BufferCommit { - pub fn with_vec(inner: Vec) -> BufferCommit { - BufferCommit { +impl VolumeCommit { + pub fn with_vec(inner: Vec) -> VolumeCommit { + VolumeCommit { inner, index: Idx::default(), } } } -impl BufferCommit { - pub fn new(inner: Vec, index: Idx) -> BufferCommit { - BufferCommit { inner, index } +impl VolumeCommit { + pub fn new(inner: Vec, index: Idx) -> VolumeCommit { + VolumeCommit { inner, index } } pub fn into_inner(self) -> Vec { @@ -199,19 +199,19 @@ impl BufferCommit { } } -impl AsRef<[T]> for BufferCommit { +impl AsRef<[T]> for VolumeCommit { fn as_ref(&self) -> &[T] { self.inner.as_ref() } } -impl AsMut<[T]> for BufferCommit { +impl AsMut<[T]> for VolumeCommit { fn as_mut(&mut self) -> &mut [T] { self.inner.as_mut() } } -impl Deref for BufferCommit { +impl Deref for VolumeCommit { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -219,15 +219,15 @@ impl Deref for BufferCommit { } } -impl DerefMut for BufferCommit { +impl DerefMut for VolumeCommit { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } } macro_rules! impl_slice { - (@inner $buffer:ty $( , $lt:lifetime )* ) => { - impl<$( $lt, )* S: Size + PartialOrd + Copy, T> Buffer> for $buffer + (@inner $volume:ty $( , $lt:lifetime )* ) => { + impl<$( $lt, )* S: Size + PartialOrd + Copy, T> Volume> for $volume where T: Clone, [T]: ToOwned, @@ -238,7 +238,7 @@ macro_rules! impl_slice { Length::Bounded(Address::from(>::as_ref(self).len())) } - fn commit(&mut self, slice: Option>>) -> Result<(), Infallible> { + fn commit(&mut self, slice: Option>>) -> Result<(), Infallible> { slice.map(|slice| { let index = slice.at_index().index64() as usize; let end = index + slice.as_ref().len(); @@ -254,21 +254,21 @@ macro_rules! impl_slice { unsafe fn slice_unchecked<'a>( &'a self, range: Range>, - ) -> BufferSlice<'a, T, Address> { + ) -> VolumeSlice<'a, T, Address> { let index = range.start; let range = range.start.index64() as usize..range.end.index64() as usize; - BufferSlice::new( + VolumeSlice::new( >::as_ref(self).get_unchecked(range), index, ) } } }; - ($buffer:ty) => { - impl_slice!(@inner $buffer); + ($volume:ty) => { + impl_slice!(@inner $volume); }; - ($buffer:ty $( , $lt:lifetime )* ) => { - impl_slice!(@inner $buffer $( , $lt )* ); + ($volume:ty $( , $lt:lifetime )* ) => { + impl_slice!(@inner $volume $( , $lt )* ); }; } @@ -285,10 +285,10 @@ mod file { use sector::{Address, Size}; - use super::{Buffer, BufferCommit, BufferSlice}; + use super::{Volume, VolumeCommit, VolumeSlice}; use super::length::Length; - impl Buffer> for RefCell { + impl Volume> for RefCell { type Error = io::Error; fn len(&self) -> Length> { @@ -302,7 +302,7 @@ mod file { fn commit( &mut self, - slice: Option>>, + slice: Option>>, ) -> Result<(), Self::Error> { slice .map(|slice| { @@ -320,7 +320,7 @@ mod file { unsafe fn slice_unchecked<'a>( &'a self, range: Range>, - ) -> BufferSlice<'a, u8, Address> { + ) -> VolumeSlice<'a, u8, Address> { let index = range.start; let len = range.end - range.start; let mut vec = Vec::with_capacity(len.index64() as usize); @@ -330,15 +330,15 @@ mod file { .seek(SeekFrom::Start(index.index64())) .and_then(|_| refmut.read_exact(&mut vec[..])) .unwrap_or_else(|err| { - panic!("could't read from File Buffer: {:?}", err) + panic!("could't read from File Volume: {:?}", err) }); - BufferSlice::new_owned(vec, index) + VolumeSlice::new_owned(vec, index) } fn slice<'a>( &'a self, range: Range>, - ) -> Option>> { + ) -> Option>> { let index = range.start; let mut vec = Vec::with_capacity( (range.end - range.start).index64() as usize, @@ -347,7 +347,7 @@ mod file { refmut .seek(SeekFrom::Start(index.index64())) .and_then(|_| refmut.read_exact(&mut vec[..])) - .map(move |_| BufferSlice::new_owned(vec, index)) + .map(move |_| VolumeSlice::new_owned(vec, index)) .ok() } } @@ -359,10 +359,10 @@ mod tests { use super::*; #[test] - fn buffer() { - let mut buffer = vec![0; 1024]; + fn volume() { + let mut volume = vec![0; 1024]; let commit = { - let mut slice = buffer + let mut slice = volume .slice( Address::::from(256_usize) ..Address::::from(512_usize), @@ -371,9 +371,9 @@ mod tests { slice.iter_mut().for_each(|x| *x = 1); slice.commit() }; - assert!(buffer.commit(commit).is_ok()); + assert!(volume.commit(commit).is_ok()); - for (i, &x) in buffer.iter().enumerate() { + for (i, &x) in volume.iter().enumerate() { if i < 256 || i >= 512 { assert_eq!(x, 0); } else { From 02f70ee9743f78ab3595f651d769e7fb5a8edc68 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:53:27 +0100 Subject: [PATCH 63/72] add 1024 sized sectors --- src/sector.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sector.rs b/src/sector.rs index 997f4f8..cb84a61 100644 --- a/src/sector.rs +++ b/src/sector.rs @@ -17,6 +17,12 @@ impl Size for Size512 { const LOG_SIZE: u32 = 9; } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct Size1024; +impl Size for Size1024 { + const LOG_SIZE: u32 = 10; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Size2048; impl Size for Size2048 { From a1436f2d260a96b08ca31f8cf7851aa3f8c22beb Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:57:00 +0100 Subject: [PATCH 64/72] satisfy lints --- src/sys/superblock.rs | 1 - src/volume/mod.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 6f44b6a..301bb35 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -314,7 +314,6 @@ mod tests { } #[test] - #[allow(unused_unsafe)] fn superblock() { use std::cell::RefCell; use std::fs::File; diff --git a/src/volume/mod.rs b/src/volume/mod.rs index 165bd3f..98192c2 100644 --- a/src/volume/mod.rs +++ b/src/volume/mod.rs @@ -307,7 +307,6 @@ mod file { slice .map(|slice| { let index = *slice.at_index(); - let end = index + Address::from(slice.as_ref().len()); let mut refmut = self.borrow_mut(); refmut .seek(SeekFrom::Start(index.index64())) From 6c2dc293e0e4e6e34fdd68efb071960e081254b0 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 12:58:39 +0100 Subject: [PATCH 65/72] shorten too long lines --- src/volume/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/volume/mod.rs b/src/volume/mod.rs index 98192c2..898c324 100644 --- a/src/volume/mod.rs +++ b/src/volume/mod.rs @@ -227,7 +227,8 @@ impl DerefMut for VolumeCommit { macro_rules! impl_slice { (@inner $volume:ty $( , $lt:lifetime )* ) => { - impl<$( $lt, )* S: Size + PartialOrd + Copy, T> Volume> for $volume + impl<$( $lt, )* S: Size + PartialOrd + Copy, T> Volume> + for $volume where T: Clone, [T]: ToOwned, @@ -235,10 +236,15 @@ macro_rules! impl_slice { type Error = Infallible; fn len(&self) -> Length> { - Length::Bounded(Address::from(>::as_ref(self).len())) + Length::Bounded( + Address::from(>::as_ref(self).len()) + ) } - fn commit(&mut self, slice: Option>>) -> Result<(), Infallible> { + fn commit( + &mut self, + slice: Option>>, + ) -> Result<(), Infallible> { slice.map(|slice| { let index = slice.at_index().index64() as usize; let end = index + slice.as_ref().len(); @@ -256,7 +262,8 @@ macro_rules! impl_slice { range: Range>, ) -> VolumeSlice<'a, T, Address> { let index = range.start; - let range = range.start.index64() as usize..range.end.index64() as usize; + let range = range.start.index64() as usize + ..range.end.index64() as usize; VolumeSlice::new( >::as_ref(self).get_unchecked(range), index, From 2a755f740d43fb0910e093387562c9028dd5b2b9 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 13:42:52 +0100 Subject: [PATCH 66/72] fix `sector::Address::with_block_size` --- src/sector.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sector.rs b/src/sector.rs index cb84a61..85c4e63 100644 --- a/src/sector.rs +++ b/src/sector.rs @@ -62,14 +62,17 @@ impl Address { pub fn with_block_size( block: usize, - offset: usize, + offset: isize, log_block_size: u32, ) -> Address { + let block = (block as isize + (offset >> log_block_size)) as usize; + let offset = offset.abs() as usize & ((1 << log_block_size) - 1); + let log_diff = log_block_size as isize - S::LOG_SIZE as isize; let top_offset = offset >> S::LOG_SIZE; - let offset = offset & ((1 << log_block_size) - 1); + let offset = offset & ((1 << S::LOG_SIZE) - 1); let sector = block << log_diff | top_offset; - Address::new(sector, offset as isize) + unsafe { Address::new_unchecked(sector, offset) } } pub fn index64(&self) -> u64 { @@ -204,6 +207,14 @@ mod tests { Address::::with_block_size(1, 256, 10).into_index(), Some(1024 + 256) ); + assert_eq!( + Address::::with_block_size(2, 0, 10).into_index(), + Some(2048) + ); + assert_eq!( + Address::::with_block_size(0, 1792, 10).into_index(), + Some(1792) + ); } #[test] From d24fde3c3d4e50384d92c8f1f4cd7165d62ba441 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 14:34:06 +0100 Subject: [PATCH 67/72] fix safe read reading zero bytes --- src/volume/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/volume/mod.rs b/src/volume/mod.rs index 898c324..f9c5738 100644 --- a/src/volume/mod.rs +++ b/src/volume/mod.rs @@ -349,6 +349,9 @@ mod file { let mut vec = Vec::with_capacity( (range.end - range.start).index64() as usize, ); + unsafe { + vec.set_len((range.end - range.start).index64() as usize); + } let mut refmut = self.borrow_mut(); refmut .seek(SeekFrom::Start(index.index64())) From 83a9d706a3a1828c8135b0a9ef6104f68d532683 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 14:56:09 +0100 Subject: [PATCH 68/72] rename `Volume::len` to `Volume::size` --- src/sys/block_group.rs | 4 ++-- src/sys/inode.rs | 6 +----- src/sys/superblock.rs | 2 +- src/volume/mod.rs | 8 ++++---- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/sys/block_group.rs b/src/sys/block_group.rs index 2cc40e7..5a713d8 100644 --- a/src/sys/block_group.rs +++ b/src/sys/block_group.rs @@ -64,7 +64,7 @@ impl BlockGroupDescriptor { { let end = offset + Address::from(mem::size_of::()); - if haystack.len() < end { + if haystack.size() < end { return Err(Error::AddressOutOfBounds( end.sector(), end.offset(), @@ -92,7 +92,7 @@ impl BlockGroupDescriptor { { let end = offset + Address::from(count * mem::size_of::()); - if haystack.len() < end { + if haystack.size() < end { return Err(Error::AddressOutOfBounds( end.sector(), end.offset(), diff --git a/src/sys/inode.rs b/src/sys/inode.rs index e537ccb..a969fef 100644 --- a/src/sys/inode.rs +++ b/src/sys/inode.rs @@ -113,7 +113,7 @@ impl Inode { } let end = offset + Address::from(size); - if haystack.len() < end { + if haystack.size() < end { return Err(Error::AddressOutOfBounds( end.sector(), end.offset(), @@ -127,10 +127,6 @@ impl Inode { Ok(inode) } - - pub fn in_use(&self) -> bool { - self.hard_links > 0 - } } bitflags! { diff --git a/src/sys/superblock.rs b/src/sys/superblock.rs index 301bb35..2ad9cc6 100644 --- a/src/sys/superblock.rs +++ b/src/sys/superblock.rs @@ -203,7 +203,7 @@ impl Superblock { { let offset = Address::from(1024_usize); let end = offset + Address::from(mem::size_of::()); - if haystack.len() < end { + if haystack.size() < end { return Err(Error::AddressOutOfBounds( end.sector(), end.offset(), diff --git a/src/volume/mod.rs b/src/volume/mod.rs index f9c5738..1103013 100644 --- a/src/volume/mod.rs +++ b/src/volume/mod.rs @@ -19,7 +19,7 @@ where { type Error; - fn len(&self) -> Length; + fn size(&self) -> Length; fn commit( &mut self, slice: Option>, @@ -33,7 +33,7 @@ where &'a self, range: Range, ) -> Option> { - if self.len() >= range.end && self.len() > range.start { + if self.size() >= range.end && self.size() > range.start { unsafe { Some(self.slice_unchecked(range)) } } else { None @@ -235,7 +235,7 @@ macro_rules! impl_slice { { type Error = Infallible; - fn len(&self) -> Length> { + fn size(&self) -> Length> { Length::Bounded( Address::from(>::as_ref(self).len()) ) @@ -298,7 +298,7 @@ mod file { impl Volume> for RefCell { type Error = io::Error; - fn len(&self) -> Length> { + fn size(&self) -> Length> { Length::Bounded( self.borrow() .metadata() From 30aed8bde77af56e27c3407e1e0b3fe782e90be7 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 15:17:16 +0100 Subject: [PATCH 69/72] add an `InodeBlocks` `Iterator` for iterating over the blocks of an inode --- ext2.img | Bin 4194304 -> 4194304 bytes src/fs.rs | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 1 + 3 files changed, 214 insertions(+), 7 deletions(-) diff --git a/ext2.img b/ext2.img index aa13d85580f8a1c5d625a06823825f898be6d778..89fa28bbc23f6814adf7bd700376eb65363c831c 100644 GIT binary patch delta 283 zcmWN=w++HT063Co!tqd{N{u?b^wG}%gA@!g%m|~5G0p^&Ofk(24Q82Ro&^?JVwn}1 utg^;B8*H-0HaqOH$36!fa>Ow$PB`U^bJ|>R$rab!aLXO{JiLT+{NDa5T21T# delta 283 zcmWN=H4eg10D$4tu!p<5Ymwrzv9omGG%sOb;~q>UVc;Mfqcc1ImwZx6Rq|!(#=~{4 z%G=Vv7wzmiH(}p}tx%;#od!Mh(nmi76bv%NFe8jI#yAs9GQ~7A%reJ33oNq4GApdI u#yT5pvc)z#?6Su`2OM(5F())R<&1MKXmQCE*W7T+9rrx&_!0K$_xuA>;Z6 { pub inner: T, @@ -90,11 +91,41 @@ where &mut self, &(ref inode, offset): &(Inode, Address), ) -> Result<(), Error> { - let slice = VolumeSlice::from_cast(inode, offset); + let slice = VolumeSlice::from_cast(&inode.inner, offset); let commit = slice.commit(); self.volume.commit(commit).map_err(|err| Error::from(err)) } + pub fn read_inode( + &self, + buf: &mut [u8], + inode: &Inode, + ) -> Result { + let total_size = inode.size(); + let mut read_size = 0; + let block_size = self.block_size(); + let offset = 0; + + for (data, _) in InodeBlocks::new(self, &inode) { + let data_size = block_size + .min(total_size - read_size) + .min(buf.len() - offset); + let end = offset + data_size; + buf[offset..end].copy_from_slice(&data[..data_size]); + read_size += data_size; + } + + Ok(read_size) + } + + pub fn write_inode( + &self, + &(ref inode, offset): &(Inode, Address), + buf: &[u8], + ) -> Result { + unimplemented!() + } + pub fn root_inode(&self) -> (Inode, Address) { self.inode_nth(2).unwrap() } @@ -173,6 +204,14 @@ where pub fn log_block_size(&self) -> u32 { self.superblock().log_block_size + 10 } + + pub fn sector_size(&self) -> usize { + S::SIZE + } + + pub fn log_sector_size(&self) -> u32 { + S::LOG_SIZE + } } pub struct Inodes<'a, S: Size, V: 'a + Volume>> { @@ -204,18 +243,141 @@ where let offset = Address::with_block_size( inodes_block, - index * self.inode_size, + (index * self.inode_size) as isize, self.log_block_size, ); - unsafe { - Inode::find_inode(self.volume, offset, self.inode_size).ok() - } + let raw = unsafe { + RawInode::find_inode(self.volume, offset, self.inode_size).ok() + }; + raw.map(|(raw, offset)| (Inode::new(raw), offset)) } else { None } } } +#[derive(Debug, Clone)] +pub struct Inode { + inner: RawInode, +} + +impl Inode { + pub fn new(inner: RawInode) -> Inode { + Inode { inner } + } + + pub fn block(&self, index: usize) -> Option> { + // number of blocks in direct table: 12 + // number of blocks in indirect table: block_size/4 + // why? + // - a block is n bytes long + // - a block address occupies 32 bits, or 4 bytes + // - thus, n/4 + // number of blocks in doubly table: (block_size/4)^2 + // why? + // - every entry in the doubly table points to another block + // - that's n/4 blocks, where n is the block size + // - every block contains n/4 block pointers + // - that's n/4 blocks with n/4 pointers each = (n/4)^2 + // number of blocks in triply table: (block_size/4)^3 + + let bs4 = self.block_size() / 4; + if index < 12 { + NonZero::new(self.inner.direct_pointer[index] as usize) + } else if index < bs4 { + unimplemented!("indirect pointer table"); + } else if index < bs4 * bs4 { + unimplemented!("doubly indirect pointer table"); + } else if index < bs4 * bs4 * bs4 { + unimplemented!("triply indirect pointer table"); + } else { + None + } + } + + pub fn in_use(&self) -> bool { + self.inner.hard_links > 0 + } + + pub fn uid(&self) -> u16 { + self.inner.uid + } + + pub fn sectors(&self) -> usize { + self.inner.sectors_count as usize + } + + pub fn size32(&self) -> u32 { + self.inner.size_low + } + + pub fn size64(&self) -> u64 { + self.inner.size_low as u64 | (self.inner.size_high as u64) << 32 + } + + #[cfg(target_pointer_width = "64")] + #[inline] + pub fn size(&self) -> usize { + self.size64() as usize + } + + #[cfg(target_pointer_width = "32")] + #[inline] + pub fn size(&self) -> usize { + self.size32() as usize + } +} + +pub struct InodeBlocks<'a, 'b, S: 'a + Size, V: 'a + Volume>> { + fs: &'a Ext2, + inode: &'b Inode, + index: usize, +} + +impl<'a, 'b, S: Size + Copy, V: 'a + Volume>> + InodeBlocks<'a, 'b, S, V> +where + Error: From, +{ + pub fn new( + fs: &'a Ext2, + inode: &'b Inode, + ) -> InodeBlocks<'a, 'b, S, V> { + InodeBlocks { + fs: fs, + inode, + index: 0, + } + } +} + +impl<'a, 'b, S: Size + Copy, V: 'a + Volume>> Iterator + for InodeBlocks<'a, 'b, S, V> +where + Error: From, +{ + type Item = (VolumeSlice<'a, u8, Address>, Address); + + fn next(&mut self) -> Option { + let block = self.inode.block(self.index); + block + .map(|block| { + let block = block.get(); + self.index += 1; + Address::with_block_size(block, 0, self.fs.log_block_size()) + ..Address::with_block_size( + block + 1, + 0, + self.fs.log_block_size(), + ) + }) + .and_then(|block| { + let offset = block.start; + self.fs.volume.slice(block).map(|slice| (slice, offset)) + }) + } +} + #[cfg(test)] mod tests { use std::fs::File; @@ -224,7 +386,7 @@ mod tests { use sector::{Address, Size512}; use volume::Volume; - use super::Ext2; + use super::{Ext2, InodeBlocks}; #[test] fn file_len() { @@ -281,4 +443,48 @@ mod tests { println!("{:?}", inode); } } + + #[test] + fn inode_blocks() { + use std::str; + let file = RefCell::new(File::open("ext2.img").unwrap()); + let fs = Ext2::::new(file).unwrap(); + + let inodes = fs.inodes().filter(|inode| { + inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 + }); + for inode in inodes { + println!("{:?}", inode.0); + let size = inode.0.size(); + for block in InodeBlocks::new(&fs, &inode.0) { + let (data, _) = block; + assert_eq!(data.len(), fs.block_size()); + println!("{:?}", &data[..size]); + let _ = str::from_utf8(&data[..size]) + .map(|string| println!("{}", string)); + } + } + } + + #[test] + fn read_inode() { + use std::str; + let file = RefCell::new(File::open("ext2.img").unwrap()); + let fs = Ext2::::new(file).unwrap(); + + let inodes = fs.inodes().filter(|inode| { + inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 + }); + for (inode, _) in inodes { + let mut buf = Vec::with_capacity(inode.size()); + unsafe { + buf.set_len(inode.size()); + } + let size = fs.read_inode(&mut buf[..], &inode); + assert_eq!(size, Ok(inode.size())); + unsafe { + buf.set_len(size.unwrap()); + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index 0e47614..59a6381 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![feature(macro_lifetime_matcher)] #![feature(const_fn)] #![feature(step_trait)] +#![feature(nonzero)] #![cfg_attr(all(not(test), feature = "no_std"), no_std)] #[macro_use] From e6218401ce63523c347c42639aabd3835c579484 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Tue, 20 Mar 2018 15:44:12 +0100 Subject: [PATCH 70/72] implement doubly indirect pointer tables --- src/fs.rs | 126 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index bbb010b..ef40187 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,5 +1,5 @@ use core::mem; -use core::marker::PhantomData; +use core::fmt::{self, Debug}; use core::nonzero::NonZero; use alloc::Vec; @@ -86,27 +86,17 @@ where Ok(()) } - #[allow(dead_code)] - fn update_inode( - &mut self, - &(ref inode, offset): &(Inode, Address), - ) -> Result<(), Error> { - let slice = VolumeSlice::from_cast(&inode.inner, offset); - let commit = slice.commit(); - self.volume.commit(commit).map_err(|err| Error::from(err)) - } - - pub fn read_inode( - &self, + pub fn read_inode<'a>( + &'a self, buf: &mut [u8], - inode: &Inode, + inode: &Inode<'a, S, V>, ) -> Result { let total_size = inode.size(); let mut read_size = 0; let block_size = self.block_size(); let offset = 0; - for (data, _) in InodeBlocks::new(self, &inode) { + for (data, _) in InodeBlocks::new(&inode) { let data_size = block_size .min(total_size - read_size) .min(buf.len() - offset); @@ -118,19 +108,22 @@ where Ok(read_size) } - pub fn write_inode( - &self, - &(ref inode, offset): &(Inode, Address), - buf: &[u8], + pub fn write_inode<'a>( + &'a self, + _inode: &(Inode<'a, S, V>, Address), + _buf: &[u8], ) -> Result { unimplemented!() } - pub fn root_inode(&self) -> (Inode, Address) { + pub fn root_inode<'a>(&'a self) -> (Inode<'a, S, V>, Address) { self.inode_nth(2).unwrap() } - pub fn inode_nth(&self, index: usize) -> Option<(Inode, Address)> { + pub fn inode_nth<'a>( + &'a self, + index: usize, + ) -> Option<(Inode<'a, S, V>, Address)> { self.inodes_nth(index).next() } @@ -141,17 +134,18 @@ where pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, V> { assert!(index > 0, "inodes are 1-indexed"); Inodes { - volume: &self.volume, + fs: self, block_groups: &self.block_groups.inner, log_block_size: self.log_block_size(), inode_size: self.inode_size(), inodes_per_group: self.inodes_count(), inodes_count: self.total_inodes_count(), index, - _phantom: PhantomData, } } +} +impl>> Ext2 { fn superblock(&self) -> &Superblock { &self.superblock.inner } @@ -165,9 +159,9 @@ where (self.superblock().rev_major, self.superblock().rev_minor) } - pub fn inode_size(&self) -> usize { + pub fn inode_size<'a>(&'a self) -> usize { if self.version().0 == 0 { - mem::size_of::() + mem::size_of::>() } else { // note: inodes bigger than 128 are not supported self.superblock().inode_size as usize @@ -214,15 +208,20 @@ where } } -pub struct Inodes<'a, S: Size, V: 'a + Volume>> { - volume: &'a V, +impl>> Debug for Ext2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Ext2<{}>", S::SIZE) + } +} + +pub struct Inodes<'a, S: 'a + Size, V: 'a + Volume>> { + fs: &'a Ext2, block_groups: &'a [BlockGroupDescriptor], log_block_size: u32, inode_size: usize, inodes_per_group: usize, inodes_count: usize, index: usize, - _phantom: PhantomData, } impl<'a, S: Size + Copy, V: 'a + Volume>> Iterator @@ -230,7 +229,7 @@ impl<'a, S: Size + Copy, V: 'a + Volume>> Iterator where Error: From, { - type Item = (Inode, Address); + type Item = (Inode<'a, S, V>, Address); fn next(&mut self) -> Option { if self.index < self.inodes_count { @@ -247,9 +246,10 @@ where self.log_block_size, ); let raw = unsafe { - RawInode::find_inode(self.volume, offset, self.inode_size).ok() + RawInode::find_inode(&self.fs.volume, offset, self.inode_size) + .ok() }; - raw.map(|(raw, offset)| (Inode::new(raw), offset)) + raw.map(|(raw, offset)| (Inode::new(self.fs, raw), offset)) } else { None } @@ -257,13 +257,14 @@ where } #[derive(Debug, Clone)] -pub struct Inode { +pub struct Inode<'a, S: 'a + Size, V: 'a + Volume>> { + fs: &'a Ext2, inner: RawInode, } -impl Inode { - pub fn new(inner: RawInode) -> Inode { - Inode { inner } +impl<'a, S: 'a + Size + Copy, V: 'a + Volume>> Inode<'a, S, V> { + pub fn new(fs: &'a Ext2, inner: RawInode) -> Inode<'a, S, V> { + Inode { fs, inner } } pub fn block(&self, index: usize) -> Option> { @@ -281,14 +282,25 @@ impl Inode { // - that's n/4 blocks with n/4 pointers each = (n/4)^2 // number of blocks in triply table: (block_size/4)^3 - let bs4 = self.block_size() / 4; + let bs4 = self.fs.block_size() / 4; if index < 12 { NonZero::new(self.inner.direct_pointer[index] as usize) - } else if index < bs4 { - unimplemented!("indirect pointer table"); - } else if index < bs4 * bs4 { + } else if index < bs4 + 12 { + let block = self.inner.indirect_pointer as usize; + let offset = index - 12; + let addr = Address::with_block_size( + block, + offset as isize, + self.fs.log_block_size(), + ); + let size = Address::from(4_usize); + let slice = self.fs.volume.slice(addr..addr + size); + slice.and_then(|slice| unsafe { + NonZero::new(u32::from_le(slice.dynamic_cast::().0) as usize) + }) + } else if index < bs4 * bs4 + bs4 + 12 { unimplemented!("doubly indirect pointer table"); - } else if index < bs4 * bs4 * bs4 { + } else if index < bs4 * bs4 * bs4 + bs4 * bs4 + bs4 + 12 { unimplemented!("triply indirect pointer table"); } else { None @@ -328,9 +340,9 @@ impl Inode { } } -pub struct InodeBlocks<'a, 'b, S: 'a + Size, V: 'a + Volume>> { - fs: &'a Ext2, - inode: &'b Inode, +pub struct InodeBlocks<'a: 'b, 'b, S: 'a + Size, V: 'a + Volume>> +{ + inode: &'b Inode<'a, S, V>, index: usize, } @@ -339,15 +351,8 @@ impl<'a, 'b, S: Size + Copy, V: 'a + Volume>> where Error: From, { - pub fn new( - fs: &'a Ext2, - inode: &'b Inode, - ) -> InodeBlocks<'a, 'b, S, V> { - InodeBlocks { - fs: fs, - inode, - index: 0, - } + pub fn new(inode: &'b Inode<'a, S, V>) -> InodeBlocks<'a, 'b, S, V> { + InodeBlocks { inode, index: 0 } } } @@ -364,16 +369,24 @@ where .map(|block| { let block = block.get(); self.index += 1; - Address::with_block_size(block, 0, self.fs.log_block_size()) + Address::with_block_size( + block, + 0, + self.inode.fs.log_block_size(), + ) ..Address::with_block_size( block + 1, 0, - self.fs.log_block_size(), + self.inode.fs.log_block_size(), ) }) .and_then(|block| { let offset = block.start; - self.fs.volume.slice(block).map(|slice| (slice, offset)) + self.inode + .fs + .volume + .slice(block) + .map(|slice| (slice, offset)) }) } } @@ -456,7 +469,7 @@ mod tests { for inode in inodes { println!("{:?}", inode.0); let size = inode.0.size(); - for block in InodeBlocks::new(&fs, &inode.0) { + for block in InodeBlocks::new(&inode.0) { let (data, _) = block; assert_eq!(data.len(), fs.block_size()); println!("{:?}", &data[..size]); @@ -468,7 +481,6 @@ mod tests { #[test] fn read_inode() { - use std::str; let file = RefCell::new(File::open("ext2.img").unwrap()); let fs = Ext2::::new(file).unwrap(); From d5423d7199ed8b45f08d8a1884150e7b6c5dbae5 Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Wed, 21 Mar 2018 18:17:36 +0100 Subject: [PATCH 71/72] Change sector::Address implementation to use u32 This way a `u64` is guaranteed to be able to index specific bytes in a Volume. --- src/error.rs | 2 +- src/fs.rs | 27 +++++++++---------- src/sector.rs | 69 +++++++++++++++++++++-------------------------- src/volume/mod.rs | 30 ++++++++++----------- 4 files changed, 59 insertions(+), 69 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7c3a8f9..0c5b8be 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,7 +6,7 @@ use std::io; pub enum Error { BadMagic(u16), OutOfBounds(usize), - AddressOutOfBounds(usize, usize, usize), + AddressOutOfBounds(u32, u32, usize), BadBlockGroupCount(u32, u32), #[cfg(any(test, not(feature = "no_std")))] Io(io::Error), diff --git a/src/fs.rs b/src/fs.rs index ef40187..385765a 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -37,7 +37,7 @@ where pub fn new(volume: V) -> Result, Error> { let superblock = unsafe { Struct::from(Superblock::find(&volume)?) }; let block_groups_offset = Address::with_block_size( - superblock.inner.first_data_block as usize + 1, + superblock.inner.first_data_block + 1, 0, superblock.inner.log_block_size + 10, ); @@ -237,12 +237,11 @@ where let index = (self.index - 1) % self.inodes_per_group; self.index += 1; - let inodes_block = - self.block_groups[block_group].inode_table_block as usize; + let inodes_block = self.block_groups[block_group].inode_table_block; let offset = Address::with_block_size( inodes_block, - (index * self.inode_size) as isize, + (index * self.inode_size) as i32, self.log_block_size, ); let raw = unsafe { @@ -267,7 +266,7 @@ impl<'a, S: 'a + Size + Copy, V: 'a + Volume>> Inode<'a, S, V> { Inode { fs, inner } } - pub fn block(&self, index: usize) -> Option> { + pub fn block(&self, index: usize) -> Option> { // number of blocks in direct table: 12 // number of blocks in indirect table: block_size/4 // why? @@ -284,19 +283,19 @@ impl<'a, S: 'a + Size + Copy, V: 'a + Volume>> Inode<'a, S, V> { let bs4 = self.fs.block_size() / 4; if index < 12 { - NonZero::new(self.inner.direct_pointer[index] as usize) + NonZero::new(self.inner.direct_pointer[index]) } else if index < bs4 + 12 { - let block = self.inner.indirect_pointer as usize; + let block = self.inner.indirect_pointer; let offset = index - 12; let addr = Address::with_block_size( block, - offset as isize, + offset as i32, self.fs.log_block_size(), ); - let size = Address::from(4_usize); + let size = Address::from(4_u64); let slice = self.fs.volume.slice(addr..addr + size); slice.and_then(|slice| unsafe { - NonZero::new(u32::from_le(slice.dynamic_cast::().0) as usize) + NonZero::new(u32::from_le(slice.dynamic_cast::().0)) }) } else if index < bs4 * bs4 + bs4 + 12 { unimplemented!("doubly indirect pointer table"); @@ -405,15 +404,15 @@ mod tests { fn file_len() { let file = RefCell::new(File::open("ext2.img").unwrap()); assert_eq!( - Address::::from(2048_usize) - - Address::::from(1024_usize), + Address::::from(2048_u64) + - Address::::from(1024_u64), Address::::new(2, 0) ); assert_eq!( unsafe { file.slice_unchecked( - Address::::from(1024_usize) - ..Address::::from(2048_usize), + Address::::from(1024_u64) + ..Address::::from(2048_u64), ).len() }, 1024 diff --git a/src/sector.rs b/src/sector.rs index 85c4e63..de229fd 100644 --- a/src/sector.rs +++ b/src/sector.rs @@ -8,7 +8,7 @@ pub trait Size: PartialOrd { // log_sector_size = log_2(sector_size) const LOG_SIZE: u32; const SIZE: usize = 1 << Self::LOG_SIZE; - const OFFSET_MASK: usize = Self::SIZE - 1; + const OFFSET_MASK: u32 = (Self::SIZE - 1) as u32; } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] @@ -38,14 +38,14 @@ impl Size for Size4096 { /// Address in a physical sector #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Address { - sector: usize, - offset: usize, + sector: u32, + offset: u32, _phantom: PhantomData, } impl Address { - pub unsafe fn new_unchecked(sector: usize, offset: usize) -> Address { - assert!(offset < S::SIZE, "offset out of sector bounds"); + pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address { + assert!((offset as usize) < S::SIZE, "offset out of sector bounds"); let _phantom = PhantomData; Address { sector, @@ -54,37 +54,31 @@ impl Address { } } - pub fn new(sector: usize, offset: isize) -> Address { - let sector = (sector as isize + (offset >> S::LOG_SIZE)) as usize; - let offset = offset.abs() as usize & S::OFFSET_MASK; + pub fn new(sector: u32, offset: i32) -> Address { + let sector = (sector as i32 + (offset >> S::LOG_SIZE)) as u32; + let offset = offset.abs() as u32 & S::OFFSET_MASK; unsafe { Address::new_unchecked(sector, offset) } } pub fn with_block_size( - block: usize, - offset: isize, + block: u32, + offset: i32, log_block_size: u32, ) -> Address { - let block = (block as isize + (offset >> log_block_size)) as usize; - let offset = offset.abs() as usize & ((1 << log_block_size) - 1); + let block = (block as i32 + (offset >> log_block_size)) as u32; + let offset = offset.abs() as u32 & ((1 << log_block_size) - 1); - let log_diff = log_block_size as isize - S::LOG_SIZE as isize; + let log_diff = log_block_size as i32 - S::LOG_SIZE as i32; let top_offset = offset >> S::LOG_SIZE; let offset = offset & ((1 << S::LOG_SIZE) - 1); let sector = block << log_diff | top_offset; unsafe { Address::new_unchecked(sector, offset) } } - pub fn index64(&self) -> u64 { + pub fn into_index(&self) -> u64 { ((self.sector as u64) << S::LOG_SIZE) + self.offset as u64 } - pub fn into_index(&self) -> Option { - self.sector - .checked_shl(S::LOG_SIZE) - .and_then(|sector| sector.checked_add(self.offset)) - } - pub const fn sector_size(&self) -> usize { S::SIZE } @@ -93,11 +87,11 @@ impl Address { S::LOG_SIZE } - pub fn sector(&self) -> usize { + pub fn sector(&self) -> u32 { self.sector } - pub fn offset(&self) -> usize { + pub fn offset(&self) -> u32 { self.offset } } @@ -105,7 +99,7 @@ impl Address { impl Step for Address { fn steps_between(start: &Self, end: &Self) -> Option { if end.sector >= start.sector { - Some(end.sector - start.sector) + Some(end.sector as usize - start.sector as usize) } else { None } @@ -129,7 +123,7 @@ impl Step for Address { fn add_usize(&self, n: usize) -> Option { self.sector - .checked_add(n) + .checked_add(n as u32) .map(|sector| Address::new(sector, 0)) } } @@ -160,15 +154,15 @@ impl From for Address { fn from(idx: u64) -> Address { let sector = idx >> S::LOG_SIZE; let offset = idx & S::OFFSET_MASK as u64; - Address::new(sector as usize, offset as isize) + Address::new(sector as u32, offset as i32) } } impl From for Address { fn from(idx: usize) -> Address { let sector = idx >> S::LOG_SIZE; - let offset = idx & S::OFFSET_MASK; - Address::new(sector, offset as isize) + let offset = idx & S::OFFSET_MASK as usize; + Address::new(sector as u32, offset as i32) } } @@ -177,7 +171,7 @@ impl Add for Address { fn add(self, rhs: Address) -> Address { Address::new( self.sector + rhs.sector, - (self.offset + rhs.offset) as isize, + (self.offset + rhs.offset) as i32, ) } } @@ -187,7 +181,7 @@ impl Sub for Address { fn sub(self, rhs: Address) -> Address { Address::new( self.sector - rhs.sector, - self.offset as isize - rhs.offset as isize, + self.offset as i32 - rhs.offset as i32, ) } } @@ -198,22 +192,19 @@ mod tests { #[test] fn conv() { - assert_eq!(Address::::new(0, 1024).into_index(), Some(1024)); - assert_eq!( - Address::::from(1024_usize).into_index(), - Some(1024) - ); + assert_eq!(Address::::new(0, 1024).into_index(), 1024); + assert_eq!(Address::::from(1024_u64).into_index(), 1024); assert_eq!( Address::::with_block_size(1, 256, 10).into_index(), - Some(1024 + 256) + 1024 + 256 ); assert_eq!( Address::::with_block_size(2, 0, 10).into_index(), - Some(2048) + 2048 ); assert_eq!( Address::::with_block_size(0, 1792, 10).into_index(), - Some(1792) + 1792 ); } @@ -232,11 +223,11 @@ mod tests { let a = Address::::new(0, 1024); let b = Address::::new(0, 1024); assert_eq!(a + b, Address::::new(1, 0)); - assert_eq!((a + b).into_index(), Some(2048)); + assert_eq!((a + b).into_index(), 2048); let a = Address::::new(0, 2048); let b = Address::::new(0, 256); assert_eq!(a - b, Address::::new(3, 256)); - assert_eq!((a - b).into_index(), Some(1792)); + assert_eq!((a - b).into_index(), 1792); } } diff --git a/src/volume/mod.rs b/src/volume/mod.rs index 1103013..054dd37 100644 --- a/src/volume/mod.rs +++ b/src/volume/mod.rs @@ -246,7 +246,7 @@ macro_rules! impl_slice { slice: Option>>, ) -> Result<(), Infallible> { slice.map(|slice| { - let index = slice.at_index().index64() as usize; + let index = slice.at_index().into_index() as usize; let end = index + slice.as_ref().len(); // XXX: it would be much better to drop the contents of dst // and move the contents of slice instead of cloning @@ -262,8 +262,8 @@ macro_rules! impl_slice { range: Range>, ) -> VolumeSlice<'a, T, Address> { let index = range.start; - let range = range.start.index64() as usize - ..range.end.index64() as usize; + let range = range.start.into_index() as usize + ..range.end.into_index() as usize; VolumeSlice::new( >::as_ref(self).get_unchecked(range), index, @@ -303,7 +303,7 @@ mod file { self.borrow() .metadata() .map(|data| Address::from(data.len())) - .unwrap_or(Address::from(0_usize)), + .unwrap_or(Address::new(0, 0)), ) } @@ -316,7 +316,7 @@ mod file { let index = *slice.at_index(); let mut refmut = self.borrow_mut(); refmut - .seek(SeekFrom::Start(index.index64())) + .seek(SeekFrom::Start(index.into_index())) .and_then(|_| refmut.write(slice.as_ref())) .map(|_| ()) }) @@ -329,11 +329,11 @@ mod file { ) -> VolumeSlice<'a, u8, Address> { let index = range.start; let len = range.end - range.start; - let mut vec = Vec::with_capacity(len.index64() as usize); - vec.set_len(len.index64() as usize); + let mut vec = Vec::with_capacity(len.into_index() as usize); + vec.set_len(len.into_index() as usize); let mut refmut = self.borrow_mut(); refmut - .seek(SeekFrom::Start(index.index64())) + .seek(SeekFrom::Start(index.into_index())) .and_then(|_| refmut.read_exact(&mut vec[..])) .unwrap_or_else(|err| { panic!("could't read from File Volume: {:?}", err) @@ -346,15 +346,15 @@ mod file { range: Range>, ) -> Option>> { let index = range.start; - let mut vec = Vec::with_capacity( - (range.end - range.start).index64() as usize, - ); + let mut vec = Vec::with_capacity((range.end - range.start) + .into_index() + as usize); unsafe { - vec.set_len((range.end - range.start).index64() as usize); + vec.set_len((range.end - range.start).into_index() as usize); } let mut refmut = self.borrow_mut(); refmut - .seek(SeekFrom::Start(index.index64())) + .seek(SeekFrom::Start(index.into_index())) .and_then(|_| refmut.read_exact(&mut vec[..])) .map(move |_| VolumeSlice::new_owned(vec, index)) .ok() @@ -373,8 +373,8 @@ mod tests { let commit = { let mut slice = volume .slice( - Address::::from(256_usize) - ..Address::::from(512_usize), + Address::::from(256_u64) + ..Address::::from(512_u64), ) .unwrap(); slice.iter_mut().for_each(|x| *x = 1); From c42fb978c2e78a5540d022500f59db9e8383c8cf Mon Sep 17 00:00:00 2001 From: Szymon Walter Date: Wed, 21 Mar 2018 18:45:07 +0100 Subject: [PATCH 72/72] add README and LICENSE --- LICENSE.md | 22 ++++++++++++++++++++++ README.md | 3 +++ 2 files changed, 25 insertions(+) create mode 100644 LICENSE.md create mode 100644 README.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..9894777 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,22 @@ +# ext2-rs +## an ext2 implementation + +Copyright © 2018, Szymon Walter + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +#### walter.szymon.98@gmail.com diff --git a/README.md b/README.md new file mode 100644 index 0000000..8dd53d6 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# ext2-rs + +An OS and architecture independent implementation of ext2 in pure Rust.