Skip to content

Commit 1543007

Browse files
committed
add write_at default method implementation
1 parent 80c7a36 commit 1543007

File tree

2 files changed

+132
-9
lines changed

2 files changed

+132
-9
lines changed

filesystem/src/block/mem.rs

+55-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ where
1616
}
1717
Some(Self { sector_size, data })
1818
}
19+
20+
pub fn data(&self) -> &T {
21+
&self.data
22+
}
1923
}
2024

2125
impl<T> BlockDevice for MemoryBlockDevice<T>
@@ -53,9 +57,10 @@ where
5357

5458
#[cfg(test)]
5559
mod tests {
60+
use alloc::vec;
61+
5662
use crate::block::mem::MemoryBlockDevice;
5763
use crate::BlockDevice;
58-
use alloc::vec;
5964

6065
#[test]
6166
fn test_read_at_short() {
@@ -111,4 +116,53 @@ mod tests {
111116
let expected = [1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
112117
assert_eq!(expected, buf);
113118
}
119+
120+
#[test]
121+
fn test_write_at() {
122+
let data = vec![0xFF_u8; 16];
123+
let mut device = MemoryBlockDevice::try_new(4, data).unwrap();
124+
125+
device.write_at(0, &[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
126+
assert_eq!(&[1, 2, 3, 4, 5, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
127+
}
128+
129+
#[test]
130+
fn test_write_at_unaligned() {
131+
let data = vec![0xFF_u8; 16];
132+
let mut device = MemoryBlockDevice::try_new(4, data).unwrap();
133+
134+
device.write_at(1, &[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
135+
assert_eq!(&[0xFF, 1, 2, 3, 4, 5, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
136+
}
137+
138+
#[test]
139+
fn test_write_at_aligned_short() {
140+
let data = vec![0xFF_u8; 16];
141+
let mut device = MemoryBlockDevice::try_new(4, data).unwrap();
142+
143+
device.write_at(0, &[1, 2]).unwrap();
144+
assert_eq!(&[1, 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
145+
device.write_at(0, &[1, 2, 3]).unwrap();
146+
assert_eq!(&[1, 2, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
147+
}
148+
149+
#[test]
150+
fn test_write_at_unaligned_short() {
151+
let data = vec![0xFF_u8; 16];
152+
let mut device = MemoryBlockDevice::try_new(4, data).unwrap();
153+
154+
device.write_at(1, &[1, 2]).unwrap();
155+
assert_eq!(&[0xFF, 1, 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
156+
device.write_at(1, &[1, 2, 3]).unwrap();
157+
assert_eq!(&[0xFF, 1, 2, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
158+
}
159+
160+
#[test]
161+
fn test_write_at_aligned_one_sector() {
162+
let data = vec![0xFF_u8; 16];
163+
let mut device = MemoryBlockDevice::try_new(4, data).unwrap();
164+
165+
device.write_at(0, &[1, 2, 3, 4]).unwrap();
166+
assert_eq!(&[1, 2, 3, 4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], device.data().as_slice());
167+
}
114168
}

filesystem/src/block/mod.rs

+77-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use alloc::vec;
22

3-
mod mem;
4-
53
pub use mem::*;
64

5+
mod mem;
6+
77
pub trait BlockDevice {
88
type Error;
99

@@ -31,7 +31,7 @@ pub trait BlockDevice {
3131
/// an appropriate error.
3232
fn write_sector(&mut self, sector_index: usize, buf: &[u8]) -> Result<usize, Self::Error>;
3333

34-
/// Reads `buf.len()` bytes starting at at the given **byte** offset
34+
/// Reads `buf.len()` bytes starting at the given **byte** offset
3535
/// into the given buffer. Returns an error if the read would exceed
3636
/// the length of this block device.
3737
///
@@ -57,11 +57,11 @@ pub trait BlockDevice {
5757
};
5858
let sector_count = end_sector - start_sector
5959
+ if relative_offset == 0 && buf.len() % sector_size == 0 && start_sector != end_sector
60-
{
61-
0
62-
} else {
63-
1
64-
};
60+
{
61+
0
62+
} else {
63+
1
64+
};
6565

6666
// read sectors
6767
let mut data = vec![0_u8; sector_count * sector_size];
@@ -76,4 +76,73 @@ pub trait BlockDevice {
7676

7777
Ok(buf.len())
7878
}
79+
80+
/// Writes `buf.len()` bytes starting at the given **byte** offset
81+
/// onto the block device. Returns an error if the write would exceed
82+
/// the length of this block device.
83+
///
84+
/// Zero-sized writes are allowed.
85+
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Result<usize, Self::Error> {
86+
if buf.is_empty() {
87+
return Ok(0);
88+
}
89+
90+
let sector_size = self.sector_size();
91+
92+
if offset % buf.len() == 0 && buf.len() == sector_size {
93+
// if we write exactly one sector, and that write is aligned, delegate to the device impl
94+
return self.write_sector(offset / sector_size, buf);
95+
}
96+
97+
let start_sector = offset / sector_size;
98+
let relative_start_offset = offset % sector_size;
99+
let end_sector = if relative_start_offset + buf.len() <= sector_size {
100+
start_sector
101+
} else {
102+
(offset + buf.len()) / sector_size
103+
};
104+
let relative_end_offset = (relative_start_offset + buf.len()) % sector_size;
105+
106+
// The write is not aligned, so we have to read the first and last sector, merge
107+
// the data with the given buffer, and write the merged data back to the device.
108+
// For all other sectors in between, we can write the data directly to the device.
109+
110+
if start_sector == end_sector {
111+
// If we have a read that is shorter than a single sector, read that sector, merge the data
112+
// and write it back.
113+
let mut first_sector = vec![0_u8; sector_size];
114+
self.read_sector(start_sector, &mut first_sector)?;
115+
// if we have a 1 sector write and a relative_end_offset of 0, that means we need to write until the end of the sector
116+
let actual_end_offset = if relative_end_offset == 0 { sector_size } else { relative_end_offset };
117+
first_sector.as_mut_slice()[relative_start_offset..actual_end_offset].copy_from_slice(&buf);
118+
return self.write_sector(start_sector, &first_sector);
119+
}
120+
121+
let (mut first_sector, mut last_sector) = {
122+
let mut first = vec![0_u8; sector_size];
123+
self.read_sector(start_sector, &mut first)?;
124+
let mut last = vec![0_u8; sector_size];
125+
self.read_sector(end_sector, &mut last)?;
126+
(first, last)
127+
};
128+
129+
// merge the write data into first[relative_offset..]
130+
first_sector.as_mut_slice()[relative_start_offset..].copy_from_slice(&buf[..sector_size - relative_start_offset]);
131+
// merge the write data into last[..relative_end_offset]
132+
last_sector.as_mut_slice()[..relative_end_offset].copy_from_slice(&buf[buf.len() - relative_end_offset..]);
133+
let in_between_data = &buf[sector_size - relative_start_offset..buf.len() - relative_end_offset];
134+
135+
// write the first sector
136+
self.write_sector(start_sector, &first_sector)?;
137+
138+
// write the in-between sectors
139+
in_between_data.chunks_exact(sector_size).enumerate().try_for_each(|(i, chunk)| {
140+
self.write_sector(start_sector + i + 1, chunk).map(|_| ())
141+
})?;
142+
143+
// write the last sector
144+
self.write_sector(end_sector, &last_sector)?;
145+
146+
Ok(buf.len())
147+
}
79148
}

0 commit comments

Comments
 (0)