1use std::{
5 collections::{BTreeMap, BTreeSet},
6 path::{Path, PathBuf},
7 sync::Arc,
8};
9
10use crate::{
11 io::fs::{
12 Create, Filesystem, FsError, Len, Mkdir, Open, OpenMut, Pread, Pwrite, ReadDir, Rename, Result,
13 SyncData, SyncDir, Truncate, Unlink,
14 },
15 sync::mutex::Mutex,
16};
17
18pub const SECTOR_BYTES: usize = 512;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum SectorState {
22 Unwritten,
23 Dirty,
24 Durable,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct SectorMask(Vec<bool>);
29
30impl SectorMask {
31 pub fn full(sectors: usize) -> Self {
32 Self(vec![true; sectors])
33 }
34
35 pub fn empty(sectors: usize) -> Self {
36 Self(vec![false; sectors])
37 }
38
39 pub fn set(&mut self, sector: usize) {
40 if sector < self.0.len() {
41 self.0[sector] = true;
42 }
43 }
44
45 pub fn clear(&mut self, sector: usize) {
46 if sector < self.0.len() {
47 self.0[sector] = false;
48 }
49 }
50
51 pub fn is_set(&self, sector: usize) -> bool {
52 self.0.get(sector).copied().unwrap_or(false)
53 }
54
55 pub fn sectors(&self) -> usize {
56 self.0.len()
57 }
58}
59
60pub(crate) fn sector_span(offset: u64, len: usize, sector_bytes: usize) -> usize {
61 if len == 0 {
62 return 0;
63 }
64 let first = offset as usize / sector_bytes;
65 let last = (offset as usize + len - 1) / sector_bytes;
66 last - first + 1
67}
68
69struct FileData {
70 bytes: Vec<u8>,
71 sectors: Vec<SectorState>,
72 shadow: BTreeMap<usize, (SectorState, Vec<u8>)>,
73}
74
75impl FileData {
76 fn new(len: usize, sector_bytes: usize) -> Self {
77 Self {
78 bytes: vec![0u8; len],
79 sectors: vec![SectorState::Unwritten; len.div_ceil(sector_bytes)],
80 shadow: BTreeMap::new(),
81 }
82 }
83
84 fn resize(&mut self, len: usize, sector_bytes: usize) {
85 self.bytes.resize(len, 0);
86 self.sectors.resize(len.div_ceil(sector_bytes), SectorState::Unwritten);
87 let sectors = self.sectors.len();
88 self.shadow.retain(|sector, _| *sector < sectors);
89 }
90
91 fn dirty(&mut self, sector: usize, sector_bytes: usize) {
92 if !self.shadow.contains_key(§or) {
93 let lo = sector * sector_bytes;
94 let hi = (lo + sector_bytes).min(self.bytes.len());
95 self.shadow.insert(sector, (self.sectors[sector], self.bytes[lo..hi].to_vec()));
96 }
97 self.sectors[sector] = SectorState::Dirty;
98 }
99
100 fn sync(&mut self) {
101 for state in self.sectors.iter_mut() {
102 if *state == SectorState::Dirty {
103 *state = SectorState::Durable;
104 }
105 }
106 self.shadow.clear();
107 }
108
109 #[cfg(any(test, feature = "testing"))]
110 fn revert(&mut self, sector_bytes: usize) {
111 while let Some((sector, (state, bytes))) = self.shadow.pop_first() {
112 let lo = sector * sector_bytes;
113 if lo >= self.bytes.len() {
114 continue;
115 }
116 let hi = (lo + bytes.len()).min(self.bytes.len());
117 self.bytes[lo..hi].copy_from_slice(&bytes[..hi - lo]);
118 if sector < self.sectors.len() {
119 self.sectors[sector] = state;
120 }
121 }
122 }
123}
124
125pub(crate) struct MemoryFileState {
126 sector_bytes: usize,
127 data: Mutex<FileData>,
128}
129
130impl MemoryFileState {
131 fn new(len: usize, sector_bytes: usize) -> Self {
132 Self {
133 sector_bytes,
134 data: Mutex::new(FileData::new(len, sector_bytes)),
135 }
136 }
137
138 fn pread(&self, offset: u64, buf: &mut [u8]) -> Result<usize> {
139 let data = self.data.lock();
140 let offset = offset as usize;
141 if offset >= data.bytes.len() {
142 return Ok(0);
143 }
144 let read = buf.len().min(data.bytes.len() - offset);
145 buf[..read].copy_from_slice(&data.bytes[offset..offset + read]);
146 Ok(read)
147 }
148
149 fn write_masked(&self, offset: u64, buf: &[u8], mask: &SectorMask) -> Result<usize> {
150 if buf.is_empty() {
151 return Ok(0);
152 }
153 let sector_bytes = self.sector_bytes;
154 let offset = offset as usize;
155 let end = offset + buf.len();
156 let mut data = self.data.lock();
157 if end > data.bytes.len() {
158 data.resize(end, sector_bytes);
159 }
160 let first = offset / sector_bytes;
161 let last = (end - 1) / sector_bytes;
162 for sector in first..=last {
163 if !mask.is_set(sector - first) {
164 continue;
165 }
166 let lo = (sector * sector_bytes).max(offset);
167 let hi = (sector * sector_bytes + sector_bytes).min(end);
168 data.dirty(sector, sector_bytes);
169 data.bytes[lo..hi].copy_from_slice(&buf[lo - offset..hi - offset]);
170 }
171 Ok(buf.len())
172 }
173
174 fn sync_data(&self) -> Result<()> {
175 self.data.lock().sync();
176 Ok(())
177 }
178
179 fn truncate(&self, len: u64) -> Result<()> {
180 self.data.lock().resize(len as usize, self.sector_bytes);
181 Ok(())
182 }
183
184 fn len(&self) -> Result<u64> {
185 Ok(self.data.lock().bytes.len() as u64)
186 }
187
188 #[cfg(any(test, feature = "testing"))]
189 fn revert(&self) {
190 self.data.lock().revert(self.sector_bytes);
191 }
192
193 #[cfg(any(test, feature = "testing"))]
194 fn sector_states(&self) -> Vec<SectorState> {
195 self.data.lock().sectors.clone()
196 }
197}
198
199struct State {
200 files: BTreeMap<PathBuf, Arc<MemoryFileState>>,
201 dirs: BTreeSet<PathBuf>,
202 sector_bytes: usize,
203}
204
205impl Default for State {
206 fn default() -> Self {
207 Self {
208 files: BTreeMap::new(),
209 dirs: BTreeSet::from([PathBuf::from("/")]),
210 sector_bytes: SECTOR_BYTES,
211 }
212 }
213}
214
215impl State {
216 fn exists(&self, path: &Path) -> bool {
217 self.files.contains_key(path) || self.dirs.contains(path)
218 }
219
220 fn parent_is_dir(&self, path: &Path) -> bool {
221 match path.parent() {
222 Some(parent) => self.dirs.contains(parent),
223 None => false,
224 }
225 }
226}
227
228#[derive(Default)]
229struct Inner {
230 state: Mutex<State>,
231}
232
233#[derive(Clone, Default)]
234pub struct MemoryFs(Arc<Inner>);
235
236impl MemoryFs {
237 pub fn new() -> Self {
238 Self::default()
239 }
240
241 pub fn with_sector_bytes(sector_bytes: usize) -> Self {
242 Self(Arc::new(Inner {
243 state: Mutex::new(State {
244 sector_bytes,
245 ..State::default()
246 }),
247 }))
248 }
249
250 #[cfg(any(test, feature = "testing"))]
251 pub fn crash(&self) {
252 let files: Vec<Arc<MemoryFileState>> = self.0.state.lock().files.values().cloned().collect();
253 for file in files {
254 file.revert();
255 }
256 }
257
258 #[cfg(feature = "testing")]
259 pub(crate) fn detach(&self, path: &Path) -> Result<Arc<MemoryFileState>> {
260 self.0.state.lock().files.remove(path).ok_or_else(|| FsError::NotFound(path.to_path_buf()))
261 }
262
263 #[cfg(feature = "testing")]
264 pub(crate) fn attach(&self, path: &Path, state: Arc<MemoryFileState>) {
265 self.0.state.lock().files.insert(path.to_path_buf(), state);
266 }
267}
268
269pub struct MemoryFile {
270 path: PathBuf,
271 state: Arc<MemoryFileState>,
272}
273
274pub struct MemoryFileMut {
275 path: PathBuf,
276 state: Arc<MemoryFileState>,
277}
278
279impl MemoryFileMut {
280 pub fn write_masked(&self, offset: u64, buf: &[u8], mask: &SectorMask) -> Result<usize> {
281 self.state.write_masked(offset, buf, mask)
282 }
283
284 pub fn path(&self) -> &Path {
285 &self.path
286 }
287
288 pub fn sector_bytes(&self) -> usize {
289 self.state.sector_bytes
290 }
291
292 #[cfg(any(test, feature = "testing"))]
293 pub fn sector_states(&self) -> Vec<SectorState> {
294 self.state.sector_states()
295 }
296}
297
298impl MemoryFile {
299 pub fn path(&self) -> &Path {
300 &self.path
301 }
302
303 pub fn sector_bytes(&self) -> usize {
304 self.state.sector_bytes
305 }
306
307 #[cfg(any(test, feature = "testing"))]
308 pub fn sector_states(&self) -> Vec<SectorState> {
309 self.state.sector_states()
310 }
311}
312
313impl Filesystem for MemoryFs {
314 type File = MemoryFile;
315 type FileMut = MemoryFileMut;
316}
317
318impl Mkdir for MemoryFs {
319 fn mkdir(&self, path: &Path) -> Result<()> {
320 let mut state = self.0.state.lock();
321 if !state.parent_is_dir(path) {
322 return Err(FsError::NotFound(path.to_path_buf()));
323 }
324 if state.exists(path) {
325 return Err(FsError::AlreadyExists(path.to_path_buf()));
326 }
327 state.dirs.insert(path.to_path_buf());
328 Ok(())
329 }
330}
331
332impl Create for MemoryFs {
333 fn create(&self, path: &Path, len: u64) -> Result<MemoryFileMut> {
334 let mut state = self.0.state.lock();
335 if !state.parent_is_dir(path) {
336 return Err(FsError::NotFound(path.to_path_buf()));
337 }
338 if state.exists(path) {
339 return Err(FsError::AlreadyExists(path.to_path_buf()));
340 }
341 let file = Arc::new(MemoryFileState::new(len as usize, state.sector_bytes));
342 state.files.insert(path.to_path_buf(), Arc::clone(&file));
343 Ok(MemoryFileMut {
344 path: path.to_path_buf(),
345 state: file,
346 })
347 }
348}
349
350impl Open for MemoryFs {
351 fn open(&self, path: &Path) -> Result<MemoryFile> {
352 let state = self.0.state.lock();
353 state.files
354 .get(path)
355 .map(|file| MemoryFile {
356 path: path.to_path_buf(),
357 state: Arc::clone(file),
358 })
359 .ok_or_else(|| FsError::NotFound(path.to_path_buf()))
360 }
361}
362
363impl OpenMut for MemoryFs {
364 fn open_mut(&self, path: &Path) -> Result<MemoryFileMut> {
365 let state = self.0.state.lock();
366 state.files
367 .get(path)
368 .map(|file| MemoryFileMut {
369 path: path.to_path_buf(),
370 state: Arc::clone(file),
371 })
372 .ok_or_else(|| FsError::NotFound(path.to_path_buf()))
373 }
374}
375
376impl ReadDir for MemoryFs {
377 fn read_dir(&self, path: &Path) -> Result<Vec<PathBuf>> {
378 let state = self.0.state.lock();
379 if !state.dirs.contains(path) {
380 if state.files.contains_key(path) {
381 return Err(FsError::NotADirectory(path.to_path_buf()));
382 }
383 return Err(FsError::NotFound(path.to_path_buf()));
384 }
385 let mut entries: Vec<PathBuf> = state
386 .files
387 .keys()
388 .chain(state.dirs.iter())
389 .filter(|entry| entry.parent() == Some(path))
390 .cloned()
391 .collect();
392 entries.sort();
393 Ok(entries)
394 }
395}
396
397impl Rename for MemoryFs {
398 fn rename(&self, from: &Path, to: &Path) -> Result<()> {
399 let mut state = self.0.state.lock();
400 let Some(file) = state.files.remove(from) else {
401 return Err(FsError::NotFound(from.to_path_buf()));
402 };
403 if !state.parent_is_dir(to) {
404 state.files.insert(from.to_path_buf(), file);
405 return Err(FsError::NotFound(to.to_path_buf()));
406 }
407 state.files.insert(to.to_path_buf(), file);
408 Ok(())
409 }
410}
411
412impl Unlink for MemoryFs {
413 fn unlink(&self, path: &Path) -> Result<()> {
414 let mut state = self.0.state.lock();
415 state.files.remove(path).map(|_| ()).ok_or_else(|| FsError::NotFound(path.to_path_buf()))
416 }
417}
418
419impl SyncDir for MemoryFs {
420 fn sync_dir(&self, path: &Path) -> Result<()> {
421 let state = self.0.state.lock();
422 if !state.dirs.contains(path) {
423 return Err(FsError::NotFound(path.to_path_buf()));
424 }
425 Ok(())
426 }
427}
428
429impl Pread for MemoryFile {
430 fn pread(&self, offset: u64, buf: &mut [u8]) -> Result<usize> {
431 self.state.pread(offset, buf)
432 }
433}
434
435impl Len for MemoryFile {
436 fn len(&self) -> Result<u64> {
437 self.state.len()
438 }
439}
440
441impl Pread for MemoryFileMut {
442 fn pread(&self, offset: u64, buf: &mut [u8]) -> Result<usize> {
443 self.state.pread(offset, buf)
444 }
445}
446
447impl Pwrite for MemoryFileMut {
448 fn pwrite(&self, offset: u64, buf: &[u8]) -> Result<usize> {
449 let mask = SectorMask::full(sector_span(offset, buf.len(), self.state.sector_bytes));
450 self.state.write_masked(offset, buf, &mask)
451 }
452}
453
454impl SyncData for MemoryFileMut {
455 fn sync_data(&self) -> Result<()> {
456 self.state.sync_data()
457 }
458}
459
460impl Truncate for MemoryFileMut {
461 fn truncate(&self, len: u64) -> Result<()> {
462 self.state.truncate(len)
463 }
464}
465
466impl Len for MemoryFileMut {
467 fn len(&self) -> Result<u64> {
468 self.state.len()
469 }
470}
471
472#[cfg(test)]
473mod tests {
474 use super::*;
475
476 fn read_all(file: &MemoryFileMut) -> Vec<u8> {
477 let len = file.len().unwrap() as usize;
478 let mut buf = vec![0u8; len];
479 assert_eq!(file.pread(0, &mut buf).unwrap(), len);
480 buf
481 }
482
483 #[test]
484 fn create_leaves_every_sector_unwritten_and_zeroed() {
485 let fs = MemoryFs::new();
487 let file = fs.create(Path::new("/a"), 1024).unwrap();
488 assert_eq!(file.sector_states(), vec![SectorState::Unwritten; 2]);
489 assert_eq!(read_all(&file), vec![0u8; 1024]);
490 }
491
492 #[test]
493 fn write_dirties_every_grazed_sector_whole() {
494 let fs = MemoryFs::new();
496 let file = fs.create(Path::new("/a"), 2048).unwrap();
497 assert_eq!(file.pwrite(500, &[7u8; 20]).unwrap(), 20);
498 assert_eq!(
499 file.sector_states(),
500 vec![SectorState::Dirty, SectorState::Dirty, SectorState::Unwritten, SectorState::Unwritten]
501 );
502 }
503
504 #[test]
505 fn sync_promotes_every_dirty_sector() {
506 let fs = MemoryFs::new();
508 let file = fs.create(Path::new("/a"), 2048).unwrap();
509 file.pwrite(0, &[1u8; 600]).unwrap();
510 file.sync_data().unwrap();
511 assert_eq!(
512 file.sector_states(),
513 vec![
514 SectorState::Durable,
515 SectorState::Durable,
516 SectorState::Unwritten,
517 SectorState::Unwritten
518 ]
519 );
520 }
521
522 #[test]
523 fn write_masked_skips_unmasked_sectors_but_reports_full_length() {
524 let fs = MemoryFs::new();
526 let file = fs.create(Path::new("/a"), 1536).unwrap();
527 let mut mask = SectorMask::empty(3);
528 mask.set(0);
529 mask.set(2);
530 assert_eq!(file.write_masked(0, &[0xABu8; 1536], &mask).unwrap(), 1536);
531 let bytes = read_all(&file);
532 assert!(bytes[0..512].iter().all(|byte| *byte == 0xAB));
533 assert!(bytes[512..1024].iter().all(|byte| *byte == 0));
534 assert!(bytes[1024..1536].iter().all(|byte| *byte == 0xAB));
535 assert_eq!(file.sector_states(), vec![SectorState::Dirty, SectorState::Unwritten, SectorState::Dirty]);
536 }
537
538 #[test]
539 fn mask_ignores_out_of_range_indices() {
540 let mut mask = SectorMask::empty(2);
542 mask.set(5);
543 assert_eq!(mask.sectors(), 2);
544 assert!(!mask.is_set(5));
545 let mut full = SectorMask::full(2);
546 full.clear(1);
547 assert!(full.is_set(0));
548 assert!(!full.is_set(1));
549 }
550
551 #[test]
552 fn pread_round_trips_clamps_and_stops_at_the_end() {
553 let fs = MemoryFs::new();
555 let file = fs.create(Path::new("/a"), 10).unwrap();
556 file.pwrite(0, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap();
557 let mut buf = [0u8; 4];
558 assert_eq!(file.pread(2, &mut buf).unwrap(), 4);
559 assert_eq!(buf, [3, 4, 5, 6]);
560 let mut tail = [0u8; 16];
561 assert_eq!(file.pread(5, &mut tail).unwrap(), 5);
562 assert_eq!(&tail[..5], &[6, 7, 8, 9, 10]);
563 assert_eq!(file.pread(10, &mut tail).unwrap(), 0);
564 assert_eq!(file.pread(9999, &mut tail).unwrap(), 0);
565 }
566
567 #[test]
568 fn write_past_the_end_grows_bytes_and_sectors_together() {
569 let fs = MemoryFs::new();
571 let file = fs.create(Path::new("/a"), 0).unwrap();
572 assert!(file.sector_states().is_empty());
573 assert_eq!(file.pwrite(1000, &[9u8; 10]).unwrap(), 10);
574 assert_eq!(file.len().unwrap(), 1010);
575 assert_eq!(file.sector_states(), vec![SectorState::Unwritten, SectorState::Dirty]);
576 assert_eq!(fs.open(Path::new("/a")).unwrap().sector_states().len(), 2);
577 }
578
579 #[test]
580 fn truncate_shortens_bytes_and_sector_states_together() {
581 let fs = MemoryFs::new();
583 let file = fs.create(Path::new("/a"), 2048).unwrap();
584 file.pwrite(0, &[3u8; 2048]).unwrap();
585 file.truncate(600).unwrap();
586 assert_eq!(file.len().unwrap(), 600);
587 assert_eq!(file.sector_states().len(), 2);
588 file.truncate(100).unwrap();
589 assert_eq!(file.sector_states().len(), 1);
590 assert_eq!(read_all(&file), vec![3u8; 100]);
591 file.truncate(1024).unwrap();
592 assert_eq!(file.sector_states(), vec![SectorState::Dirty, SectorState::Unwritten]);
593 }
594
595 #[test]
596 fn crash_reverts_dirty_sectors_to_their_prior_bytes_and_state() {
597 let fs = MemoryFs::new();
599 let file = fs.create(Path::new("/a"), 1024).unwrap();
600 file.pwrite(0, &[1u8; 512]).unwrap();
601 file.sync_data().unwrap();
602 file.pwrite(0, &[2u8; 512]).unwrap();
603 file.pwrite(512, &[2u8; 512]).unwrap();
604 fs.crash();
605 let bytes = read_all(&file);
606 assert!(bytes[0..512].iter().all(|byte| *byte == 1));
607 assert!(bytes[512..1024].iter().all(|byte| *byte == 0));
608 assert_eq!(file.sector_states(), vec![SectorState::Durable, SectorState::Unwritten]);
609 }
610
611 #[test]
612 fn crash_after_truncate_drops_shadow_beyond_the_new_end() {
613 let fs = MemoryFs::new();
615 let file = fs.create(Path::new("/a"), 2048).unwrap();
616 file.pwrite(1536, &[8u8; 512]).unwrap();
617 file.truncate(512).unwrap();
618 fs.crash();
619 assert_eq!(file.len().unwrap(), 512);
620 assert_eq!(file.sector_states(), vec![SectorState::Unwritten]);
621 }
622
623 #[test]
624 fn sync_clears_the_shadow_so_a_later_crash_keeps_the_data() {
625 let fs = MemoryFs::new();
627 let file = fs.create(Path::new("/a"), 512).unwrap();
628 file.pwrite(0, &[5u8; 512]).unwrap();
629 file.sync_data().unwrap();
630 fs.crash();
631 assert_eq!(read_all(&file), vec![5u8; 512]);
632 assert_eq!(file.sector_states(), vec![SectorState::Durable]);
633 }
634
635 #[test]
636 fn sector_size_is_configurable_and_consistent() {
637 let fs = MemoryFs::with_sector_bytes(64);
639 let file = fs.create(Path::new("/a"), 100).unwrap();
640 assert_eq!(file.sector_bytes(), 64);
641 assert_eq!(file.sector_states().len(), 2);
642 file.pwrite(0, &[1u8; 100]).unwrap();
643 assert_eq!(file.sector_states(), vec![SectorState::Dirty, SectorState::Dirty]);
644
645 let wide = MemoryFs::new();
646 let file = wide.create(Path::new("/a"), 100).unwrap();
647 assert_eq!(file.sector_bytes(), SECTOR_BYTES);
648 file.pwrite(0, &[1u8; 100]).unwrap();
649 assert_eq!(file.sector_states(), vec![SectorState::Dirty]);
650 }
651
652 #[test]
653 fn mkdir_needs_a_parent_directory_and_rejects_an_existing_path() {
654 let fs = MemoryFs::new();
656 assert_eq!(fs.mkdir(Path::new("/a/b")), Err(FsError::NotFound(PathBuf::from("/a/b"))));
657 fs.mkdir(Path::new("/a")).unwrap();
658 assert_eq!(fs.mkdir(Path::new("/a")), Err(FsError::AlreadyExists(PathBuf::from("/a"))));
659 fs.create(Path::new("/a/f"), 0).unwrap();
660 assert_eq!(fs.mkdir(Path::new("/a/f")), Err(FsError::AlreadyExists(PathBuf::from("/a/f"))));
661 }
662
663 #[test]
664 fn create_needs_a_parent_directory_and_rejects_an_existing_path() {
665 let fs = MemoryFs::new();
666 assert!(fs.create(Path::new("/a/f"), 0).is_err());
667 fs.mkdir(Path::new("/a")).unwrap();
668 fs.create(Path::new("/a/f"), 0).unwrap();
669 assert_eq!(fs.create(Path::new("/a/f"), 0).err(), Some(FsError::AlreadyExists(PathBuf::from("/a/f"))));
670 }
671
672 #[test]
673 fn open_and_open_mut_report_a_missing_file() {
674 let fs = MemoryFs::new();
675 assert_eq!(fs.open(Path::new("/a")).err(), Some(FsError::NotFound(PathBuf::from("/a"))));
676 assert_eq!(fs.open_mut(Path::new("/a")).err(), Some(FsError::NotFound(PathBuf::from("/a"))));
677 fs.create(Path::new("/a"), 8).unwrap();
678 let file = fs.open(Path::new("/a")).unwrap();
679 assert_eq!(file.path(), Path::new("/a"));
680 assert_eq!(file.len().unwrap(), 8);
681 assert_eq!(file.sector_bytes(), SECTOR_BYTES);
682 assert_eq!(file.sector_states(), vec![SectorState::Unwritten]);
683 }
684
685 #[test]
686 fn open_shares_the_state_with_the_creating_handle() {
687 let fs = MemoryFs::new();
689 let writer = fs.create(Path::new("/a"), 512).unwrap();
690 writer.pwrite(0, &[4u8; 8]).unwrap();
691 let reader = fs.open(Path::new("/a")).unwrap();
692 let mut buf = [0u8; 8];
693 assert_eq!(reader.pread(0, &mut buf).unwrap(), 8);
694 assert_eq!(buf, [4u8; 8]);
695 assert_eq!(reader.sector_states(), vec![SectorState::Dirty]);
696 }
697
698 #[test]
699 fn read_dir_lists_direct_children_in_ascending_order() {
700 let fs = MemoryFs::new();
702 fs.mkdir(Path::new("/d")).unwrap();
703 fs.mkdir(Path::new("/d/sub")).unwrap();
704 fs.create(Path::new("/d/c"), 0).unwrap();
705 fs.create(Path::new("/d/a"), 0).unwrap();
706 fs.create(Path::new("/d/sub/deep"), 0).unwrap();
707 assert_eq!(
708 fs.read_dir(Path::new("/d")).unwrap(),
709 vec![PathBuf::from("/d/a"), PathBuf::from("/d/c"), PathBuf::from("/d/sub")]
710 );
711 assert_eq!(fs.read_dir(Path::new("/nope")).err(), Some(FsError::NotFound(PathBuf::from("/nope"))));
712 assert_eq!(fs.read_dir(Path::new("/d/a")).err(), Some(FsError::NotADirectory(PathBuf::from("/d/a"))));
713 }
714
715 #[test]
716 fn rename_moves_the_entry_and_keeps_the_contents() {
717 let fs = MemoryFs::new();
718 let file = fs.create(Path::new("/a"), 512).unwrap();
719 file.pwrite(0, &[6u8; 4]).unwrap();
720 fs.rename(Path::new("/a"), Path::new("/b")).unwrap();
721 assert_eq!(fs.open(Path::new("/a")).err(), Some(FsError::NotFound(PathBuf::from("/a"))));
722 let moved = fs.open(Path::new("/b")).unwrap();
723 let mut buf = [0u8; 4];
724 assert_eq!(moved.pread(0, &mut buf).unwrap(), 4);
725 assert_eq!(buf, [6u8; 4]);
726 assert_eq!(
727 fs.rename(Path::new("/a"), Path::new("/c")).err(),
728 Some(FsError::NotFound(PathBuf::from("/a")))
729 );
730 }
731
732 #[test]
733 fn rename_into_a_missing_directory_leaves_the_source_in_place() {
734 let fs = MemoryFs::new();
736 fs.create(Path::new("/a"), 0).unwrap();
737 assert_eq!(
738 fs.rename(Path::new("/a"), Path::new("/d/b")).err(),
739 Some(FsError::NotFound(PathBuf::from("/d/b")))
740 );
741 assert!(fs.open(Path::new("/a")).is_ok());
742 }
743
744 #[test]
745 fn unlink_removes_the_entry_or_reports_it_missing() {
746 let fs = MemoryFs::new();
747 fs.create(Path::new("/a"), 0).unwrap();
748 fs.unlink(Path::new("/a")).unwrap();
749 assert_eq!(fs.unlink(Path::new("/a")).err(), Some(FsError::NotFound(PathBuf::from("/a"))));
750 }
751
752 #[test]
753 fn sync_dir_checks_the_directory_exists() {
754 let fs = MemoryFs::new();
755 fs.sync_dir(Path::new("/")).unwrap();
756 assert_eq!(fs.sync_dir(Path::new("/d")).err(), Some(FsError::NotFound(PathBuf::from("/d"))));
757 fs.mkdir(Path::new("/d")).unwrap();
758 fs.sync_dir(Path::new("/d")).unwrap();
759 }
760
761 #[test]
762 fn a_cloned_handle_shares_one_filesystem() {
763 let fs = MemoryFs::new();
765 let clone = fs.clone();
766 clone.mkdir(Path::new("/d")).unwrap();
767 assert_eq!(fs.read_dir(Path::new("/")).unwrap(), vec![PathBuf::from("/d")]);
768 }
769}