srfs_core/
fs_sync.rs

1// Filesystem. The API is biased for convenience, which in practical terms
2// means that there is a single mutable object representing the filesystem,
3// and the rest are immutable clone-able and copy-able that do not borrow.
4// This makes dealing with the borrow checker trivial.
5
6use core::ptr::copy_nonoverlapping;
7
8use alloc::boxed::Box;
9use alloc::string::String;
10use alloc::borrow::ToOwned;
11
12use crate::block_cache::BlockCache;
13
14use super::*;
15
16pub(crate) fn format(block_device: &mut dyn SyncBlockDevice) -> Result<(), FsError> {
17    let num_blocks = block_device.num_blocks();
18    if num_blocks < 2 {
19        return Err(FsError::InvalidArgument);
20    }
21
22    // We use u64::MAX as a marker for None.
23    let num_blocks = num_blocks.min(u64::MAX - 1);
24
25    // Write the first block.
26    let mut block = Block::new_zeroed();
27    unsafe {
28        let fbh = block.get_mut::<SuperblockHeader>();
29        fbh.magic = MAGIC;
30        fbh.version = 1;
31        fbh.num_blocks = num_blocks;
32        fbh.free_blocks = num_blocks - 2;
33        fbh.generation = 1;
34        fbh.empty_area_start = 2; // 0 => this; 1 => root dir.
35        fbh.set_crc32();
36        fbh.validate()?;
37    }
38    block_device.write_block(0, block.as_bytes())?;
39
40    // Write the root directory.
41    unsafe {
42        let root_dir = block.get_mut::<EntryMetadata>();
43        *root_dir = EntryMetadata::new(ROOT_DIR_ID, ROOT_DIR_ID);
44        root_dir.set_crc32();
45    }
46    block_device.write_block(1, block.as_bytes())?;
47
48    Ok(())
49}
50
51#[derive(Debug)]
52enum BlockType {
53    Metadata,
54    Data,
55    Links,
56    ListOfLinks,
57}
58
59pub struct SyncFileSystem {
60    superblock: Superblock,
61    blockcache: BlockCache,
62    num_blocks: u64,
63    error: Result<(), FsError>, // If set, the FS is corrupted and cannot be used.
64}
65
66impl SyncFileSystem {
67    pub const fn root_dir_id() -> EntryId {
68        ROOT_DIR_ID
69    }
70
71    pub fn num_blocks(&self) -> u64 {
72        self.num_blocks
73    }
74
75    pub fn empty_blocks(&self) -> u64 {
76        self.superblock.header().free_blocks
77    }
78
79    pub fn open_fs(mut block_device: Box<dyn SyncBlockDevice>) -> Result<Self, FsError> {
80        let mut block = Box::new(Block::new_uninit());
81        block_device.read_block(0, block.as_bytes_mut())?;
82        let superblock = Superblock::from(block)?;
83
84        let num_blocks = superblock.header().num_blocks;
85        if num_blocks < 3 || num_blocks == u64::MAX || num_blocks > block_device.num_blocks() {
86            return Err(FsError::InvalidArgument);
87        }
88
89        let fbh = superblock.header();
90        if fbh.txn_meta_block != 0
91            || fbh.txn_data_block != 0
92            || fbh.txn_link_block != 0
93            || fbh.txn_list_of_links_block != 0
94        {
95            todo!("roll back or commit the TXN")
96        }
97
98        Ok(Self {
99            num_blocks,
100            superblock,
101            blockcache: BlockCache::new(block_device),
102            error: Ok(()),
103        })
104    }
105
106    /// Create a new file.
107    pub fn add_file(&mut self, parent_id: EntryId, name: &str) -> Result<EntryId, FsError> {
108        self.add_directory_entry(parent_id, name, true)
109    }
110
111    /// Create a new directory.
112    pub fn add_directory(&mut self, parent_id: EntryId, name: &str) -> Result<EntryId, FsError> {
113        self.add_directory_entry(parent_id, name, false)
114    }
115
116    // Returns parent size.
117    fn validate_new_entry(&mut self, parent_id: EntryId, name: &str) -> Result<(), FsError> {
118        self.error?;
119        validate_filename(name)?;
120        if parent_id.block_no >= self.num_blocks || parent_id.block_no < 1 {
121            return Err(FsError::InvalidArgument);
122        }
123        if self.find_entry_by_name(parent_id, name).is_ok() {
124            return Err(FsError::AlreadyExists);
125        }
126
127        let parent_block = self.blockcache.read(parent_id.block_no)?;
128        let meta = unsafe { parent_block.block().get::<EntryMetadata>() };
129        meta.validate_dir(parent_id)?;
130        if meta.size == MAX_DIR_ENTRIES {
131            return Err(FsError::TooLarge);
132        }
133
134        Ok(())
135    }
136
137    // Must be inside a transaction. Inner => no need to poison self.
138    fn add_directory_entry_inner(
139        &mut self,
140        parent_id: EntryId,
141        child_id: EntryId,
142        child_name: &str,
143    ) -> Result<(), FsError> {
144        let sbh = self.superblock.header();
145        assert_ne!(TXN_TYPE_NONE, sbh.txn_type);
146        let parent_block = self.blockcache.get(parent_id.block_no);
147        let meta = unsafe { parent_block.block().get::<EntryMetadata>() };
148        let prev_size = meta.size;
149
150        // Update the parent dir.
151        if prev_size < MAX_ENTRIES_IN_META_BLOCK as u64 {
152            // Stick the new block entry into the meta block.
153            let parent_block = self.blockcache.get_mut(parent_id.block_no);
154            let meta = unsafe { parent_block.block_mut().get_mut::<EntryMetadata>() };
155            meta.size += 1;
156            meta.set_crc32();
157            parent_block
158                .block_mut()
159                .set_dir_entry((prev_size + 1) as usize, child_id, child_name);
160            self.blockcache.write(parent_id.block_no)?;
161        } else if prev_size < MAX_ENTRIES_ONLY_DATA_BLOCKS {
162            let need_new_block = prev_size == MAX_ENTRIES_IN_META_BLOCK
163                || (prev_size % MAX_ENTRIES_IN_DATA_BLOCK == 0);
164            if need_new_block {
165                // Allocate a new data block.
166                let data_block_no = self.allocate_txn_block(BlockType::Data)?;
167
168                // Write the new data block.
169                if prev_size == MAX_ENTRIES_IN_META_BLOCK {
170                    let source_block_addr =
171                        self.blockcache.get(parent_id.block_no).block() as *const Block as usize;
172                    let data_block = self.blockcache.get_block_uninit(data_block_no);
173                    for idx in 0..(MAX_ENTRIES_IN_META_BLOCK as usize) {
174                        let source_block =
175                            unsafe { (source_block_addr as *const Block).as_ref().unwrap() };
176
177                        *data_block.block_mut().get_dir_entry_mut(idx) =
178                            *source_block.get_dir_entry(idx + 1);
179                    }
180
181                    data_block.block_mut().set_dir_entry(
182                        MAX_ENTRIES_IN_META_BLOCK as usize,
183                        child_id,
184                        child_name,
185                    );
186                } else {
187                    let data_block = self.blockcache.get_block_uninit(data_block_no);
188                    data_block
189                        .block_mut()
190                        .set_dir_entry(0, child_id, child_name);
191                }
192                self.blockcache.write(data_block_no)?;
193
194                // Update the parent.
195                let parent_block = self.blockcache.get_mut(parent_id.block_no);
196                let meta = unsafe { parent_block.block_mut().get_mut::<EntryMetadata>() };
197                meta.size += 1;
198                meta.set_crc32();
199                parent_block
200                    .block_mut()
201                    .set_datablock_no_in_meta(prev_size / MAX_ENTRIES_IN_DATA_BLOCK, data_block_no);
202                self.blockcache.write(parent_id.block_no)?;
203            } else {
204                // Update an existing data block.
205                let data_block_idx = prev_size / MAX_ENTRIES_IN_DATA_BLOCK;
206                let parent_block = self.blockcache.get(parent_id.block_no);
207                let data_block_no = parent_block
208                    .block()
209                    .get_datablock_no_in_meta(data_block_idx);
210                let data_block = self.blockcache.read_mut(data_block_no)?;
211                data_block.block_mut().set_dir_entry(
212                    (prev_size % MAX_ENTRIES_IN_DATA_BLOCK) as usize,
213                    child_id,
214                    child_name,
215                );
216                self.blockcache.write(data_block_no)?;
217                self.plus_one(parent_id.block_no)?;
218            }
219        } else {
220            let need_new_data_block = prev_size % MAX_ENTRIES_IN_DATA_BLOCK == 0;
221            let need_new_list_block = prev_size == MAX_ENTRIES_ONLY_DATA_BLOCKS
222                || (prev_size % MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST == 0);
223
224            if need_new_data_block {
225                // Allocate a new data block.
226                let data_block_no = self.allocate_txn_block(BlockType::Data)?;
227                let data_block = self.blockcache.get_block_uninit(data_block_no);
228                data_block
229                    .block_mut()
230                    .set_dir_entry(0, child_id, child_name);
231                self.blockcache.write(data_block_no)?;
232
233                if need_new_list_block {
234                    let link_block_no = self.allocate_txn_block(BlockType::Links)?;
235                    if prev_size == MAX_ENTRIES_ONLY_DATA_BLOCKS {
236                        let source_block_addr = self.blockcache.get(parent_id.block_no).block()
237                            as *const Block
238                            as usize;
239                        let link_block = self.blockcache.get_block_uninit(link_block_no);
240                        for idx in 0..MAX_LINKS_IN_META_BLOCK {
241                            let source_block =
242                                unsafe { (source_block_addr as *const Block).as_ref().unwrap() };
243
244                            link_block.block_mut().set_datablock_no_in_link(
245                                idx,
246                                source_block.get_datablock_no_in_meta(idx),
247                            );
248                        }
249
250                        link_block
251                            .block_mut()
252                            .set_datablock_no_in_link(MAX_LINKS_IN_META_BLOCK, data_block_no);
253                    } else {
254                        let link_block = self.blockcache.get_block_uninit(link_block_no);
255                        link_block
256                            .block_mut()
257                            .set_datablock_no_in_link(0, data_block_no);
258                    }
259                    self.blockcache.write(link_block_no)?;
260                    // Update the parent.
261                    let parent_block = self.blockcache.get_mut(parent_id.block_no);
262                    let meta = unsafe { parent_block.block_mut().get_mut::<EntryMetadata>() };
263                    meta.size += 1;
264                    meta.set_crc32();
265                    parent_block.block_mut().set_datablock_no_in_meta(
266                        prev_size / MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST,
267                        link_block_no,
268                    );
269                    self.blockcache.write(parent_id.block_no)?;
270                } else {
271                    // Update the link block.
272                    let link_block_idx = prev_size / MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST;
273                    let parent_block = self.blockcache.get(parent_id.block_no);
274                    let link_block_no = parent_block
275                        .block()
276                        .get_datablock_no_in_meta(link_block_idx);
277                    let link_block = self.blockcache.read_mut(link_block_no)?;
278                    let data_block_idx = (prev_size % MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST)
279                        / MAX_ENTRIES_IN_DATA_BLOCK;
280                    link_block
281                        .block_mut()
282                        .set_datablock_no_in_link(data_block_idx, data_block_no);
283                    self.blockcache.write(link_block_no)?;
284                    self.plus_one(parent_id.block_no)?;
285                }
286            } else {
287                // Update an existing data block.
288                let link_block_idx = prev_size / MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST;
289                let parent_block = self.blockcache.get(parent_id.block_no);
290                let link_block_no = parent_block
291                    .block()
292                    .get_datablock_no_in_meta(link_block_idx);
293                let link_block = self.blockcache.read(link_block_no)?;
294                let data_block_idx = (prev_size % MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST)
295                    / MAX_ENTRIES_IN_DATA_BLOCK;
296                let data_block_no = link_block.block().get_datablock_no_in_link(data_block_idx);
297
298                let data_block = self.blockcache.read_mut(data_block_no)?;
299                data_block.block_mut().set_dir_entry(
300                    (prev_size % MAX_ENTRIES_IN_DATA_BLOCK) as usize,
301                    child_id,
302                    child_name,
303                );
304                self.blockcache.write(data_block_no)?;
305                self.plus_one(parent_id.block_no)?;
306            }
307        }
308
309        Ok(())
310    }
311
312    fn add_directory_entry(
313        &mut self,
314        parent_id: EntryId,
315        name: &str,
316        is_file: bool,
317    ) -> Result<EntryId, FsError> {
318        self.error?;
319        self.validate_new_entry(parent_id, name)?;
320
321        // Steps:
322        // - get a free block
323        // - write the new EntryMetadata into it; (crash here: whatever)
324        // - mark the block as busy in the parent dir; (crash here: check the parent dir upon bootup)
325        // - add the block to the parent dir; (crash here: check the parent dir upon bootup)
326        // - commit: clear the busy block.
327
328        // Get a new generation (no save).
329        let mut generation = self.superblock.header().generation + 1;
330        if is_file && ((generation & 1) == 1) {
331            generation += 1; // Files must have EVEN generations.
332        }
333        if (!is_file) && ((generation & 1) == 0) {
334            generation += 1; // Directories must have ODD generations.
335        }
336
337        let sbh = self.superblock.header_mut();
338        sbh.generation = generation;
339        self.start_txn(TXN_TYPE_ADD_NODE, parent_id)?;
340
341        // Get a new block.
342        let block_no = self.allocate_txn_block(BlockType::Metadata)?;
343
344        // Write the new block.
345        let new_id = EntryId::new(block_no, generation);
346        let meta_block = self.blockcache.get_block_uninit(block_no);
347        let meta = unsafe { meta_block.block_mut().get_mut::<EntryMetadata>() };
348        *meta = EntryMetadata::new(new_id, parent_id);
349        meta.size = 0;
350        meta.set_crc32();
351        self.blockcache.write(block_no)?;
352
353        self.add_directory_entry_inner(parent_id, new_id, name)
354            .map_err(|e| {
355                let _ = self.make_error();
356                e
357            })?;
358
359        // Commit.
360        self.commit_txn()?;
361        Ok(new_id)
362    }
363
364    /// Get a specific directory entry (child).
365    pub fn get_directory_entry(
366        &mut self,
367        parent: EntryId,
368        pos: u64,
369    ) -> Result<DirEntry, FsError> {
370        self.error?;
371        let parent_block = self.blockcache.read(parent.block_no)?;
372        let meta = unsafe { parent_block.block().get::<EntryMetadata>() };
373        meta.validate_dir(parent)?;
374        let num_entries = meta.size;
375
376        if pos as u64 >= meta.size {
377            return Err(FsError::NotFound);
378        }
379
380        if num_entries <= MAX_ENTRIES_IN_META_BLOCK {
381            return parent_block
382                .block()
383                .get_dir_entry((pos + 1) as usize)
384                .to_owned();
385        }
386
387        if num_entries <= MAX_ENTRIES_ONLY_DATA_BLOCKS {
388            let data_block_idx = pos / MAX_ENTRIES_IN_DATA_BLOCK;
389            let data_block_no = parent_block
390                .block()
391                .get_datablock_no_in_meta(data_block_idx);
392            return self
393                .blockcache
394                .read(data_block_no)?
395                .block()
396                .get_dir_entry((pos % MAX_ENTRIES_IN_DATA_BLOCK) as usize)
397                .to_owned();
398        }
399
400        let link_block_idx = pos / MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST;
401        let link_block_no = parent_block
402            .block()
403            .get_datablock_no_in_meta(link_block_idx);
404
405        let link_block = self.blockcache.read(link_block_no)?;
406        let data_block_idx =
407            (pos % MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST) / MAX_ENTRIES_IN_DATA_BLOCK;
408        let data_block_no = link_block.block().get_datablock_no_in_link(data_block_idx);
409
410        return self
411            .blockcache
412            .read(data_block_no)?
413            .block()
414            .get_dir_entry((pos % MAX_ENTRIES_IN_DATA_BLOCK) as usize)
415            .to_owned();
416    }
417
418    pub fn get_directory_entry_by_name(
419        &mut self,
420        parent: EntryId,
421        name: &str,
422    ) -> Result<DirEntry, FsError> {
423        self.error?;
424        let (block_no, entry_pos) = self.find_entry_by_name(parent, name)?;
425        let block = self.blockcache.read(block_no).unwrap();
426        Ok(block.block().get_dir_entry(entry_pos).to_owned()?)
427    }
428
429    /// Get the number of directory entries (children).
430    pub fn get_num_entries(&mut self, dir: EntryId) -> Result<u64, FsError> {
431        self.error?;
432        let block = self.blockcache.read(dir.block_no)?;
433        let meta = unsafe { block.block().get::<EntryMetadata>() };
434        meta.validate_dir(dir)?;
435
436        Ok(meta.size as u64)
437    }
438
439    /// Get file size.
440    pub fn get_file_size(&mut self, file: EntryId) -> Result<u64, FsError> {
441        self.error?;
442        let block = self.blockcache.read(file.block_no)?;
443        let meta = unsafe { block.block().get::<EntryMetadata>() };
444        meta.validate_file(file)?;
445
446        Ok(meta.size)
447    }
448
449    pub fn stat(&mut self, entry: EntryId) -> Result<Attr, FsError> {
450        self.error?;
451        let block = self.blockcache.read(entry.block_no)?;
452        let meta = unsafe { block.block().get::<EntryMetadata>() };
453        meta.validate(entry)?;
454
455        Ok(meta.into())
456    }
457
458    pub fn set_file_size(&mut self, file_id: EntryId, new_size: u64) -> Result<(), FsError> {
459        self.error?;
460
461        // Go block by block, from the end.
462        loop {
463            let metadata_block = self.blockcache.read(file_id.block_no)?;
464            let meta = unsafe { metadata_block.block().get::<EntryMetadata>() };
465            meta.validate_file(file_id)?;
466            let prev_size = meta.size;
467            if new_size > prev_size {
468                return Err(FsError::InvalidArgument);
469            }
470            if new_size == prev_size {
471                return Ok(());
472            }
473
474            let mid_size = (prev_size - 1) & !(BLOCK_SIZE - 1);
475            debug_assert!(mid_size < prev_size);
476            debug_assert!((prev_size - mid_size) <= BLOCK_SIZE);
477            debug_assert_eq!(0, mid_size & (BLOCK_SIZE - 1));
478
479            // A special case.
480            let mid_size = if prev_size > MAX_BYTES_IN_META_BLOCK
481                && prev_size <= BLOCK_SIZE
482                && new_size <= MAX_BYTES_IN_META_BLOCK
483            {
484                new_size
485            } else {
486                mid_size
487            };
488
489            if (new_size > mid_size && new_size > MAX_BYTES_IN_META_BLOCK)
490                || prev_size <= MAX_BYTES_IN_META_BLOCK
491            {
492                // No block/layout changes.
493                let metadata_block = self.blockcache.get_mut(file_id.block_no);
494                let meta = unsafe { metadata_block.block_mut().get_mut::<EntryMetadata>() };
495                meta.size = new_size;
496                meta.set_crc32();
497                self.blockcache.write(file_id.block_no)?;
498                return Ok(());
499            }
500
501            // Need to remove the last data block and, potentially, link blocks.
502            if prev_size <= MAX_BYTES_ONLY_DATA_BLOCKS {
503                // Files smaller than ~2M.
504                let block_idx = mid_size >> BLOCK_SIZE.ilog2();
505
506                let meta_block = self.blockcache.get(file_id.block_no);
507                let data_block_no = meta_block.block().get_datablock_no_in_meta(block_idx);
508
509                // TODO: we probably don't need a TXN here: will save a couple of block writes?
510                self.start_txn(TXN_TYPE_REMOVE_BYTES, file_id)?;
511                self.superblock.header_mut().txn_data_block = data_block_no;
512                self.save_superblock()?;
513
514                let metadata_block = self.blockcache.get_mut(file_id.block_no);
515                let meta = unsafe { metadata_block.block_mut().get_mut::<EntryMetadata>() };
516                meta.size = mid_size;
517                meta.set_crc32();
518                self.blockcache.write(file_id.block_no)?;
519
520                if (mid_size <= MAX_BYTES_IN_META_BLOCK) && (mid_size > 0) {
521                    let data = *self.blockcache.read(data_block_no)?.block();
522                    unsafe {
523                        let metadata_block = self.blockcache.get_mut(file_id.block_no);
524                        copy_nonoverlapping(
525                            data.as_bytes().as_ptr(),
526                            metadata_block
527                                .block_mut()
528                                .as_data_bytes_in_meta_mut()
529                                .as_mut_ptr(),
530                            MAX_BYTES_IN_META_BLOCK as usize,
531                        );
532                    }
533                    self.blockcache.write(file_id.block_no)?;
534                }
535
536                self.free_txn_block(BlockType::Data)?;
537                self.commit_txn()?;
538                continue;
539            }
540
541            if prev_size <= MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS {
542                // Files smaller than ~1G.
543                let link_block_idx = mid_size >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
544                let meta_block = self.blockcache.get(file_id.block_no);
545                let link_block_no = meta_block.block().get_datablock_no_in_meta(link_block_idx);
546
547                let link_block = self.blockcache.read(link_block_no)?;
548                let data_block_idx =
549                    (mid_size & (BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1)) >> BLOCK_SIZE.ilog2();
550                let data_block_no = link_block.block().get_datablock_no_in_link(data_block_idx);
551
552                let need_to_free_link_block =
553                    (data_block_idx == 0) || (mid_size == MAX_BYTES_ONLY_DATA_BLOCKS);
554
555                self.start_txn(TXN_TYPE_REMOVE_BYTES, file_id)?;
556                self.superblock.header_mut().txn_data_block = data_block_no;
557                if need_to_free_link_block {
558                    self.superblock.header_mut().txn_link_block = link_block_no;
559                }
560                self.save_superblock()?;
561
562                let metadata_block = self.blockcache.get_mut(file_id.block_no);
563                let meta = unsafe { metadata_block.block_mut().get_mut::<EntryMetadata>() };
564                meta.size = mid_size;
565                meta.set_crc32();
566                self.blockcache.write(file_id.block_no)?;
567
568                if mid_size == MAX_BYTES_ONLY_DATA_BLOCKS {
569                    let links = *self.blockcache.get(link_block_no).block();
570                    let metadata_block = self.blockcache.get_mut(file_id.block_no);
571                    for idx in 0..MAX_LINKS_IN_META_BLOCK {
572                        metadata_block
573                            .block_mut()
574                            .set_datablock_no_in_meta(idx, links.get_datablock_no_in_link(idx));
575                    }
576                    self.blockcache.write(file_id.block_no)?;
577                }
578
579                self.free_txn_block(BlockType::Data)?;
580                if need_to_free_link_block {
581                    self.free_txn_block(BlockType::Links)?;
582                }
583                self.commit_txn()?;
584                continue;
585            }
586
587            // Large files.
588            let list_of_links_block_idx =
589                mid_size >> BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST.ilog2();
590            let meta_block = self.blockcache.get(file_id.block_no);
591            let list_of_links_block_no = meta_block
592                .block()
593                .get_datablock_no_in_meta(list_of_links_block_idx);
594
595            let link_block_idx = (mid_size & (BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST - 1))
596                >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
597            let list_of_links_block = self.blockcache.read(list_of_links_block_no)?;
598            let link_block_no = list_of_links_block
599                .block()
600                .get_datablock_no_in_link(link_block_idx);
601
602            let link_block = self.blockcache.read(link_block_no)?;
603            let data_block_idx =
604                (mid_size & (BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1)) >> BLOCK_SIZE.ilog2();
605            let data_block_no = link_block.block().get_datablock_no_in_link(data_block_idx);
606
607            let need_to_free_link_block = data_block_idx == 0;
608            let need_to_free_list_of_links_block = need_to_free_link_block
609                && ((link_block_idx == 0) || (mid_size == MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS));
610
611            self.start_txn(TXN_TYPE_REMOVE_BYTES, file_id)?;
612            self.superblock.header_mut().txn_data_block = data_block_no;
613            if need_to_free_link_block {
614                self.superblock.header_mut().txn_link_block = link_block_no;
615            }
616            if need_to_free_list_of_links_block {
617                self.superblock.header_mut().txn_list_of_links_block = list_of_links_block_no;
618            }
619            self.save_superblock()?;
620
621            let metadata_block = self.blockcache.get_mut(file_id.block_no);
622            let meta = unsafe { metadata_block.block_mut().get_mut::<EntryMetadata>() };
623            meta.size = mid_size;
624            meta.set_crc32();
625            self.blockcache.write(file_id.block_no)?;
626
627            if mid_size == MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS {
628                let list_of_links = *self.blockcache.get(list_of_links_block_no).block();
629                let metadata_block = self.blockcache.get_mut(file_id.block_no);
630                for idx in 0..MAX_LINKS_IN_META_BLOCK {
631                    metadata_block
632                        .block_mut()
633                        .set_datablock_no_in_meta(idx, list_of_links.get_datablock_no_in_link(idx));
634                }
635                self.blockcache.write(file_id.block_no)?;
636            }
637
638            self.free_txn_block(BlockType::Data)?;
639            if need_to_free_link_block {
640                self.free_txn_block(BlockType::Links)?;
641            }
642            if need_to_free_list_of_links_block {
643                self.free_txn_block(BlockType::ListOfLinks)?;
644            }
645            self.commit_txn()?;
646            continue;
647        }
648    }
649
650    pub fn get_parent(&mut self, entry_id: EntryId) -> Result<Option<EntryId>, FsError> {
651        if entry_id == ROOT_DIR_ID {
652            return Ok(None);
653        }
654
655        let block = self.blockcache.read(entry_id.block_no)?;
656        let meta = unsafe { block.block().get::<EntryMetadata>() };
657        meta.validate(entry_id)?;
658
659        Ok(Some(meta.parent_id))
660    }
661
662    pub fn get_name(&mut self, entry_id: EntryId) -> Result<String, FsError> {
663        if entry_id == ROOT_DIR_ID {
664            return Ok("/".to_owned());
665        }
666
667        let block = self.blockcache.read(entry_id.block_no)?;
668        let meta = unsafe { block.block().get::<EntryMetadata>() };
669
670        meta.validate(entry_id)?;
671
672        let parent_id = meta.parent_id;
673        let (block_no, entry_pos) = self.find_entry_by_id(parent_id, entry_id)?;
674        let block = self.blockcache.get(block_no);
675        let dir_entry = block.block().get_dir_entry(entry_pos);
676        Ok(dir_entry.to_owned()?.name)
677    }
678
679    pub fn move_rename(
680        &mut self,
681        entry_id: EntryId,
682        new_parent: EntryId,
683        new_name: &str,
684    ) -> Result<(), FsError> {
685        self.error?;
686        #[cfg(debug_assertions)]
687        {
688            let block = self.blockcache.read(entry_id.block_no)?;
689            let meta = unsafe { block.block().get::<EntryMetadata>() };
690            meta.validate(entry_id).unwrap();
691            let block = self.blockcache.read(new_parent.block_no)?;
692            let meta = unsafe { block.block().get::<EntryMetadata>() };
693            meta.validate(new_parent).unwrap();
694        }
695        self.validate_new_entry(new_parent, new_name)?;
696        if entry_id.block_no == ROOT_DIR_ID.block_no {
697            return Err(FsError::InvalidArgument);
698        }
699        let block = self.blockcache.read(entry_id.block_no)?;
700        let meta = unsafe { block.block().get::<EntryMetadata>() };
701        meta.validate(entry_id)?;
702        let old_parent = meta.parent_id;
703
704        if old_parent == new_parent {
705            let (block_no, entry_pos) = self.find_entry_by_id(old_parent, entry_id)?;
706            let block = self.blockcache.get_mut(block_no);
707            block
708                .block_mut()
709                .get_dir_entry_mut(entry_pos)
710                .set_name(new_name);
711            self.blockcache.write(block_no)?;
712            return Ok(());
713        }
714
715        self.start_txn(TXN_TYPE_MOVE, old_parent)?;
716        self.superblock.header_mut().txn_meta_block = entry_id.block_no;
717        self.save_superblock()?;
718
719        let block = self.blockcache.get_mut(entry_id.block_no);
720        let meta = unsafe { block.block_mut().get_mut::<EntryMetadata>() };
721        meta.parent_id = new_parent;
722        meta.set_crc32();
723        self.blockcache.write(entry_id.block_no)?;
724
725        #[cfg(debug_assertions)]
726        {
727            let block = self.blockcache.read(entry_id.block_no)?;
728            let meta = unsafe { block.block().get::<EntryMetadata>() };
729            meta.validate(entry_id).unwrap();
730        }
731
732        // Move to the new parent.
733        self.add_directory_entry_inner(new_parent, entry_id, new_name)
734            .map_err(|e| {
735                let _ = self.make_error();
736                e
737            })?;
738
739        #[cfg(debug_assertions)]
740        {
741            let block = self.blockcache.read(entry_id.block_no)?;
742            let meta = unsafe { block.block().get::<EntryMetadata>() };
743            meta.validate(entry_id).unwrap();
744            let block = self.blockcache.read(old_parent.block_no)?;
745            let meta = unsafe { block.block().get::<EntryMetadata>() };
746            meta.validate(old_parent).unwrap();
747            let block = self.blockcache.read(new_parent.block_no)?;
748            let meta = unsafe { block.block().get::<EntryMetadata>() };
749            meta.validate(new_parent).unwrap();
750        }
751
752        // Clear newly added blocks, if any (can find them from the meta block).
753        let sbh = self.superblock.header_mut();
754        sbh.txn_data_block = 0;
755        sbh.txn_link_block = 0;
756        sbh.txn_list_of_links_block = 0;
757
758        #[cfg(debug_assertions)]
759        {
760            let block = self.blockcache.read(entry_id.block_no)?;
761            let meta = unsafe { block.block().get::<EntryMetadata>() };
762            meta.validate(entry_id).unwrap();
763        }
764
765        self.remove_directory_entry_inner(old_parent, entry_id)
766            .map_err(|e| {
767                let _ = self.make_error();
768                e
769            })?;
770        if self.superblock.header().txn_link_block != 0 {
771            self.free_txn_block(BlockType::Links)?;
772        }
773        if self.superblock.header().txn_data_block != 0 {
774            self.free_txn_block(BlockType::Data)?;
775        }
776
777        #[cfg(debug_assertions)]
778        {
779            let block = self.blockcache.read(entry_id.block_no)?;
780            let meta = unsafe { block.block().get::<EntryMetadata>() };
781            meta.validate(entry_id).unwrap();
782            let block = self.blockcache.read(old_parent.block_no)?;
783            let meta = unsafe { block.block().get::<EntryMetadata>() };
784            meta.validate(old_parent).unwrap();
785            let block = self.blockcache.read(new_parent.block_no)?;
786            let meta = unsafe { block.block().get::<EntryMetadata>() };
787            meta.validate(new_parent).unwrap();
788        }
789
790        self.commit_txn()?;
791        #[cfg(debug_assertions)]
792        {
793            let block = self.blockcache.read(entry_id.block_no)?;
794            let meta = unsafe { block.block().get::<EntryMetadata>() };
795            meta.validate(entry_id).unwrap();
796        }
797
798        Ok(())
799    }
800
801    pub fn remove(&mut self, entry_id: EntryId) -> Result<(), FsError> {
802        self.error?;
803        if entry_id.block_no == ROOT_DIR_ID.block_no {
804            return Err(FsError::InvalidArgument);
805        }
806        let block = self.blockcache.read(entry_id.block_no)?;
807        let meta = unsafe { block.block().get::<EntryMetadata>() };
808        meta.validate(entry_id)?;
809        if meta.size > 0 {
810            // Cannot delete a non-empty directory or a file with data.
811            // First clean the directory or truncate the file.
812            #[cfg(debug_assertions)]
813            log::debug!("srfs-core: remove failed: non-empty entry");
814            return Err(FsError::TooLarge);
815        }
816        let parent_id = meta.parent_id;
817
818        // Pre-commit: mark the block we are removing as dirty.
819        self.start_txn(TXN_TYPE_REMOVE_NODE, parent_id)?;
820        let fbh = self.superblock.header_mut();
821        assert_eq!(0, fbh.txn_meta_block);
822        fbh.txn_meta_block = entry_id.block_no;
823
824        self.remove_directory_entry_inner(parent_id, entry_id)
825            .map_err(|e| {
826                let _ = self.make_error();
827                e
828            })?;
829
830        // Commit.
831        if self.superblock.header().txn_link_block != 0 {
832            self.free_txn_block(BlockType::Links)?;
833        }
834        if self.superblock.header().txn_data_block != 0 {
835            self.free_txn_block(BlockType::Data)?;
836        }
837        self.free_txn_block(BlockType::Metadata)?;
838        self.commit_txn()
839    }
840
841    // Must be inside a transaction. Inner => no need to poison self.
842    fn remove_directory_entry_inner(
843        &mut self,
844        parent_id: EntryId,
845        child: EntryId,
846    ) -> Result<(), FsError> {
847        let sbh = self.superblock.header();
848        assert_ne!(TXN_TYPE_NONE, sbh.txn_type);
849
850        // Need to put the last entry into the place occupied by this entry.
851        let (entry_block_no, entry_pos) = self.find_entry_by_id(parent_id, child)?;
852
853        // Need to read instead of get because the find above may flush the cache.
854        let parent_block = self.blockcache.read(parent_id.block_no)?;
855        let parent_meta = unsafe { parent_block.block().get::<EntryMetadata>() };
856        parent_meta.validate_dir(parent_id)?;
857        let num_entries = parent_meta.size;
858        if num_entries <= MAX_ENTRIES_IN_META_BLOCK {
859            assert_eq!(entry_block_no, parent_id.block_no);
860            // Only the parent_block needs changing.
861            if (entry_pos as u64) < num_entries {
862                let parent_block = self.blockcache.get_mut(parent_id.block_no);
863                let last_entry = *parent_block.block().get_dir_entry(num_entries as usize);
864                *parent_block.block_mut().get_dir_entry_mut(entry_pos) = last_entry;
865            }
866        } else if num_entries <= MAX_ENTRIES_ONLY_DATA_BLOCKS {
867            let last_entry_block_idx = (num_entries - 1) / MAX_ENTRIES_IN_DATA_BLOCK;
868            let last_entry_block_no = parent_block
869                .block()
870                .get_datablock_no_in_meta(last_entry_block_idx);
871            let last_entry_idx = ((num_entries - 1) % MAX_ENTRIES_IN_DATA_BLOCK) as usize;
872
873            if (entry_block_no, entry_pos) != (last_entry_block_no, last_entry_idx) {
874                let last_entry_block = self.blockcache.read(last_entry_block_no)?;
875                let last_entry = *last_entry_block.block().get_dir_entry(last_entry_idx);
876                let entry_block = self.blockcache.read_mut(entry_block_no)?;
877                *entry_block.block_mut().get_dir_entry_mut(entry_pos) = last_entry;
878                self.blockcache.write(entry_block_no)?;
879            }
880
881            if last_entry_idx == 0 {
882                // We need to free last_entry_block.
883                let fbh = self.superblock.header_mut();
884                assert_eq!(0, fbh.txn_data_block);
885                fbh.txn_data_block = last_entry_block_no;
886                self.save_superblock()?; // TODO: do we need this?
887            }
888
889            if num_entries == (MAX_ENTRIES_IN_META_BLOCK + 1) {
890                // Move all entries into the parent meta block.
891                let entry_block = *self.blockcache.get(entry_block_no).block();
892                let parent_block = self.blockcache.get_mut(parent_id.block_no);
893                for idx in 0..(MAX_ENTRIES_IN_META_BLOCK as usize) {
894                    *parent_block.block_mut().get_dir_entry_mut(idx + 1) =
895                        *entry_block.get_dir_entry(idx);
896                }
897                // Note: parent_block is not saved here, will be saved below.
898
899                // Free the last block.
900                let fbh = self.superblock.header_mut();
901                assert_eq!(0, fbh.txn_data_block);
902                fbh.txn_data_block = last_entry_block_no;
903                self.save_superblock()?; // TODO: do we need this?
904            }
905        } else {
906            let last_link_block_no = parent_block.block().get_datablock_no_in_meta(
907                (num_entries - 1) / MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST,
908            );
909
910            let last_link_block = self.blockcache.read(last_link_block_no)?;
911            let last_entry_block_idx = ((num_entries - 1)
912                % MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST)
913                / MAX_ENTRIES_IN_DATA_BLOCK;
914            let last_entry_block_no = last_link_block
915                .block()
916                .get_datablock_no_in_link(last_entry_block_idx);
917            let last_entry_idx = ((num_entries - 1) % MAX_ENTRIES_IN_DATA_BLOCK) as usize;
918
919            if (entry_block_no, entry_pos) != (last_entry_block_no, last_entry_idx) {
920                let last_entry_block = self.blockcache.read(last_entry_block_no)?;
921                let last_entry = *last_entry_block.block().get_dir_entry(last_entry_idx);
922                let entry_block = self.blockcache.read_mut(entry_block_no)?;
923                *entry_block.block_mut().get_dir_entry_mut(entry_pos) = last_entry;
924                self.blockcache.write(entry_block_no)?;
925            }
926
927            if last_entry_idx == 0 {
928                // We need to free last_entry_block.
929                let fbh = self.superblock.header_mut();
930                assert_eq!(0, fbh.txn_data_block);
931                fbh.txn_data_block = last_entry_block_no;
932                self.save_superblock()?; // TODO: do we need this?
933            }
934
935            if num_entries == (MAX_ENTRIES_ONLY_DATA_BLOCKS + 1) {
936                // Move all links into the parent meta block.
937                let link_block = self.blockcache.get(last_link_block_no);
938                let links: Block = *link_block.block();
939                let parent_block = self.blockcache.get_mut(parent_id.block_no);
940                for idx in 0..MAX_LINKS_IN_META_BLOCK {
941                    parent_block
942                        .block_mut()
943                        .set_datablock_no_in_meta(idx, links.get_datablock_no_in_link(idx));
944                }
945                // Note: parent_block is not saved here, will be saved below.
946
947                // Free the link block.
948                let fbh = self.superblock.header_mut();
949                assert_eq!(0, fbh.txn_link_block);
950                fbh.txn_link_block = last_link_block_no;
951                self.save_superblock()?; // TODO: do we need this?
952            }
953
954            if (num_entries % MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST) == 1 {
955                // Free the link block.
956                let fbh = self.superblock.header_mut();
957                assert_eq!(0, fbh.txn_link_block);
958                fbh.txn_link_block = last_link_block_no;
959                self.save_superblock()?; // TODO: do we need this?
960            }
961        }
962
963        let parent_block = self.blockcache.get_mut(parent_id.block_no);
964        let parent_meta = unsafe { parent_block.block_mut().get_mut::<EntryMetadata>() };
965        parent_meta.size -= 1;
966        parent_meta.set_crc32();
967        self.blockcache.write(parent_id.block_no)?;
968
969        Ok(())
970    }
971
972    /// Write buf to file at offset. At most 4096 bytes will be written.
973    ///
974    /// A write may succeed with the resulting usize less than buf.len; this usually
975    /// happens when the write would otherwise cross a block boundary. Just do another
976    /// write for the remaining bytes then.
977    pub fn write(&mut self, file_id: EntryId, offset: u64, buf: &[u8]) -> Result<usize, FsError> {
978        self.error?;
979        if file_id.kind() != EntryKind::File {
980            return Err(FsError::InvalidArgument);
981        }
982        let meta_block = self.blockcache.read(file_id.block_no)?;
983        let meta = unsafe { meta_block.block().get::<EntryMetadata>() };
984        meta.validate_file(file_id)?;
985        let prev_size = meta.size;
986        if offset > prev_size {
987            return Err(FsError::InvalidArgument);
988        }
989        let new_end = if offset == prev_size {
990            offset + (buf.len() as u64)
991        } else {
992            prev_size.min(offset + (buf.len() as u64))
993        };
994        let new_size = prev_size.max(new_end);
995        if new_size <= MAX_BYTES_IN_META_BLOCK {
996            // Only the main/metadata block.
997            let meta_block = self.blockcache.get_mut(file_id.block_no);
998            let meta = unsafe { meta_block.block_mut().get_mut::<EntryMetadata>() };
999
1000            meta.size = new_size;
1001            meta.set_crc32();
1002            unsafe {
1003                copy_nonoverlapping(
1004                    buf.as_ptr(),
1005                    (meta_block
1006                        .block_mut()
1007                        .as_data_bytes_in_meta_mut()
1008                        .as_mut_ptr() as usize
1009                        + (offset as usize)) as *mut u8,
1010                    (new_end - offset) as usize,
1011                );
1012            }
1013            self.blockcache.write(file_id.block_no).map_err(|e| {
1014                let _ = self.make_error();
1015                e
1016            })?;
1017            return Ok((new_end - offset) as usize);
1018        }
1019
1020        if new_size == prev_size {
1021            return self.update_file(file_id, offset, buf);
1022        } else {
1023            return self.append(file_id, offset, buf);
1024        }
1025    }
1026
1027    pub fn read(
1028        &mut self,
1029        file_id: EntryId,
1030        offset: u64,
1031        buf: &mut [u8],
1032    ) -> Result<usize, FsError> {
1033        self.error?;
1034        if file_id.kind() != EntryKind::File {
1035            return Err(FsError::InvalidArgument);
1036        }
1037        let meta_block = self.blockcache.read(file_id.block_no)?;
1038        let meta = unsafe { meta_block.block().get::<EntryMetadata>() };
1039        meta.validate_file(file_id)?;
1040        let file_size = meta.size;
1041        if offset >= file_size {
1042            return Ok(0);
1043        }
1044        let end = file_size.min(offset + (buf.len() as u64));
1045        if file_size <= (MAX_BYTES_IN_META_BLOCK as u64) {
1046            // We are still in the main block.
1047            unsafe {
1048                copy_nonoverlapping(
1049                    (meta_block.block().as_data_bytes_in_meta().as_ptr() as usize
1050                        + (offset as usize)) as *const u8,
1051                    buf.as_mut_ptr(),
1052                    (end - offset) as usize,
1053                );
1054            }
1055            return Ok((end - offset) as usize);
1056        }
1057
1058        let data_block_no = self.find_data_block(file_id, offset)?;
1059        let block_end = align_up(offset + 1, BLOCK_SIZE);
1060        let new_end = (offset + (buf.len() as u64)).min(block_end);
1061        let data_block = self.blockcache.read(data_block_no)?;
1062        unsafe {
1063            copy_nonoverlapping(
1064                (data_block.block().as_bytes().as_ptr() as usize
1065                    + ((offset & (BLOCK_SIZE - 1)) as usize)) as *const u8,
1066                buf.as_mut_ptr(),
1067                (new_end - offset) as usize,
1068            );
1069        }
1070        return Ok((new_end - offset) as usize);
1071    }
1072
1073    fn append(&mut self, file_id: EntryId, offset: u64, buf: &[u8]) -> Result<usize, FsError> {
1074        self.error?;
1075        // We may potentially need to allocate three new blocks:
1076        // - a new data block
1077        // - a new 1st level (leaf) blocklist block
1078        // - a new 2nd level blocklist block
1079        let meta_block = self.blockcache.get(file_id.block_no);
1080        let meta = unsafe { meta_block.block().get::<EntryMetadata>() };
1081        let prev_size = meta.size;
1082        assert_eq!(prev_size, offset);
1083        let new_size = if align_up(prev_size + 1, BLOCK_SIZE) >= prev_size + (buf.len() as u64) {
1084            prev_size + (buf.len() as u64)
1085        } else {
1086            align_up(prev_size + 1, BLOCK_SIZE)
1087        };
1088
1089        // Special case 1: going from data in meta block to a separate data block.
1090        if prev_size <= MAX_BYTES_IN_META_BLOCK {
1091            assert!(new_size > MAX_BYTES_IN_META_BLOCK); // The caller handles in-meta writes.
1092
1093            // Cache the address of the bytes, to fool the borrow checker.
1094            let prev_bytes_start = meta_block.block().as_data_bytes_in_meta().as_ptr() as usize;
1095
1096            // Start the txn.
1097            self.start_txn(TXN_TYPE_ADD_BYTES, file_id)?;
1098            let data_block_no = self.allocate_txn_block(BlockType::Data)?;
1099
1100            // Copy bytes.
1101            let data_block = self.blockcache.get_block_uninit(data_block_no);
1102            unsafe {
1103                // Copy existing bytes.
1104                copy_nonoverlapping(
1105                    prev_bytes_start as *const u8,
1106                    data_block.block_mut().as_bytes_mut().as_mut_ptr(),
1107                    prev_size as usize,
1108                );
1109                // Copy new bytes.
1110                copy_nonoverlapping(
1111                    buf.as_ptr(),
1112                    (data_block.block_mut().as_bytes_mut().as_ptr() as usize + (prev_size as usize))
1113                        as *mut u8,
1114                    (new_size - prev_size) as usize,
1115                );
1116            }
1117            self.blockcache.write(data_block_no).map_err(|e| {
1118                let _ = self.make_error();
1119                e
1120            })?;
1121
1122            // Update the meta.
1123            let meta_block = self.blockcache.get_mut(file_id.block_no);
1124            meta_block
1125                .block_mut()
1126                .set_datablock_no_in_meta(0, data_block_no);
1127            let meta = unsafe { meta_block.block_mut().get_mut::<EntryMetadata>() };
1128            meta.size = new_size;
1129            meta.set_crc32();
1130            self.blockcache.write(file_id.block_no).map_err(|e| {
1131                let _ = self.make_error();
1132                e
1133            })?;
1134
1135            // Commit the txn.
1136            self.commit_txn()?;
1137            return Ok((new_size - prev_size) as usize);
1138        }
1139
1140        if align_up(prev_size, BLOCK_SIZE) >= new_size {
1141            // The write goes to an existing data block - no TXN is necessary.
1142            let data_block_no = self.find_data_block(file_id, prev_size - 1)?;
1143
1144            // Copy bytes.
1145            let data_block = self.blockcache.read_mut(data_block_no)?;
1146            unsafe {
1147                copy_nonoverlapping(
1148                    buf.as_ptr(),
1149                    (data_block.block_mut().as_bytes_mut().as_mut_ptr() as usize
1150                        + (offset & (BLOCK_SIZE - 1)) as usize) as *mut u8,
1151                    (new_size - prev_size) as usize,
1152                );
1153            }
1154            self.blockcache.write(data_block_no)?;
1155
1156            // Update meta.
1157            let meta_block = self.blockcache.get_mut(file_id.block_no);
1158            let meta = unsafe { meta_block.block_mut().get_mut::<EntryMetadata>() };
1159            meta.size = new_size;
1160            meta.set_crc32();
1161            self.blockcache.write(file_id.block_no)?;
1162
1163            return Ok((new_size - prev_size) as usize);
1164        }
1165
1166        // Append a new block.
1167        self.start_txn(TXN_TYPE_ADD_BYTES, file_id)?;
1168        let data_block_no = self.allocate_txn_block(BlockType::Data)?;
1169
1170        // Copy bytes.
1171        let data_block = self.blockcache.get_block_uninit(data_block_no);
1172        debug_assert_eq!(0, offset & (BLOCK_SIZE - 1));
1173        unsafe {
1174            copy_nonoverlapping(
1175                buf.as_ptr(),
1176                data_block.block_mut().as_bytes_mut().as_mut_ptr(),
1177                (new_size - prev_size) as usize,
1178            );
1179        }
1180        self.blockcache.write(data_block_no).map_err(|e| {
1181            let _ = self.make_error();
1182            e
1183        })?;
1184
1185        if new_size <= MAX_BYTES_ONLY_DATA_BLOCKS {
1186            // Update the meta.
1187            let meta_block = self.blockcache.get_mut(file_id.block_no);
1188            meta_block
1189                .block_mut()
1190                .set_datablock_no_in_meta(prev_size >> BLOCK_SIZE.ilog2(), data_block_no);
1191        } else if new_size <= MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS {
1192            // Files of size between ~2M and ~1G.
1193            let need_new_link_block = (prev_size % BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST == 0)
1194                || (prev_size == MAX_BYTES_ONLY_DATA_BLOCKS);
1195
1196            if need_new_link_block {
1197                let link_block_no = self.allocate_txn_block(BlockType::Links).map_err(|e| {
1198                    let _ = self.make_error();
1199                    e
1200                })?;
1201
1202                let (link_block, data_block_idx) = if prev_size == MAX_BYTES_ONLY_DATA_BLOCKS {
1203                    let meta_block = *self.blockcache.get(file_id.block_no).block();
1204                    let bytes = meta_block.as_data_bytes_in_meta();
1205                    let link_block = self.blockcache.get_block_uninit(link_block_no);
1206
1207                    unsafe {
1208                        copy_nonoverlapping(
1209                            bytes.as_ptr(),
1210                            link_block.block_mut().as_bytes_mut().as_mut_ptr(),
1211                            bytes.len(),
1212                        );
1213                    }
1214
1215                    (link_block, MAX_LINKS_IN_META_BLOCK)
1216                } else {
1217                    (self.blockcache.get_block_uninit(link_block_no), 0)
1218                };
1219
1220                link_block
1221                    .block_mut()
1222                    .set_datablock_no_in_link(data_block_idx, data_block_no);
1223                self.blockcache.write(link_block_no).map_err(|e| {
1224                    let _ = self.make_error();
1225                    e
1226                })?;
1227
1228                let link_block_idx = prev_size >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
1229                let meta_block = self.blockcache.get_mut(file_id.block_no);
1230                meta_block
1231                    .block_mut()
1232                    .set_datablock_no_in_meta(link_block_idx, link_block_no);
1233            } else {
1234                let link_block_idx = prev_size >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
1235                let link_block_no = self
1236                    .blockcache
1237                    .get(file_id.block_no)
1238                    .block()
1239                    .get_datablock_no_in_meta(link_block_idx);
1240                let link_block = self.blockcache.read_mut(link_block_no);
1241                if let Err(err) = link_block {
1242                    let _ = self.make_error();
1243                    return Err(err);
1244                }
1245                let data_block_idx = (prev_size & (BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1))
1246                    >> BLOCK_SIZE.ilog2();
1247                link_block
1248                    .unwrap()
1249                    .block_mut()
1250                    .set_datablock_no_in_link(data_block_idx, data_block_no);
1251                self.blockcache.write(link_block_no).map_err(|e| {
1252                    let _ = self.make_error();
1253                    e
1254                })?;
1255            }
1256        } else {
1257            // ~1G+ files here.
1258            let need_new_list_of_links_block =
1259                (prev_size % BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST == 0)
1260                    || (prev_size == MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS);
1261
1262            if need_new_list_of_links_block {
1263                // Always a new link block here.
1264                let link_block_no = self.allocate_txn_block(BlockType::Links).map_err(|e| {
1265                    let _ = self.make_error();
1266                    e
1267                })?;
1268                let link_block = self.blockcache.get_block_uninit(link_block_no);
1269
1270                link_block
1271                    .block_mut()
1272                    .set_datablock_no_in_link(0, data_block_no);
1273                self.blockcache.write(link_block_no).map_err(|e| {
1274                    let _ = self.make_error();
1275                    e
1276                })?;
1277
1278                let list_of_links_block_no = self
1279                    .allocate_txn_block(BlockType::ListOfLinks)
1280                    .map_err(|e| {
1281                        let _ = self.make_error();
1282                        e
1283                    })?;
1284                let (list_of_links_block, link_block_idx) =
1285                    if prev_size == MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS {
1286                        let meta_block = *self.blockcache.get(file_id.block_no).block();
1287                        let bytes = meta_block.as_data_bytes_in_meta();
1288                        let list_of_links_block =
1289                            self.blockcache.get_block_uninit(list_of_links_block_no);
1290
1291                        unsafe {
1292                            copy_nonoverlapping(
1293                                bytes.as_ptr(),
1294                                list_of_links_block.block_mut().as_bytes_mut().as_mut_ptr(),
1295                                bytes.len(),
1296                            );
1297                        }
1298
1299                        (list_of_links_block, MAX_LINKS_IN_META_BLOCK)
1300                    } else {
1301                        (self.blockcache.get_block_uninit(list_of_links_block_no), 0)
1302                    };
1303
1304                list_of_links_block
1305                    .block_mut()
1306                    .set_datablock_no_in_link(link_block_idx, link_block_no);
1307                self.blockcache.write(list_of_links_block_no).map_err(|e| {
1308                    let _ = self.make_error();
1309                    e
1310                })?;
1311
1312                let list_of_links_block_idx =
1313                    prev_size >> BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST.ilog2();
1314                let meta_block = self.blockcache.get_mut(file_id.block_no);
1315                meta_block
1316                    .block_mut()
1317                    .set_datablock_no_in_meta(list_of_links_block_idx, list_of_links_block_no);
1318            } else {
1319                let list_of_links_block_idx =
1320                    prev_size >> BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST.ilog2();
1321                let list_of_links_block_no = self
1322                    .blockcache
1323                    .get(file_id.block_no)
1324                    .block()
1325                    .get_datablock_no_in_meta(list_of_links_block_idx);
1326                // Cache the block.
1327                if let Err(err) = self.blockcache.read(list_of_links_block_no) {
1328                    let _ = self.make_error();
1329                    return Err(err);
1330                }
1331
1332                let need_new_link_block = prev_size % BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST == 0;
1333                let link_block_idx = (prev_size & (BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST - 1))
1334                    >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
1335
1336                if need_new_link_block {
1337                    let link_block_no = self.allocate_txn_block(BlockType::Links).map_err(|e| {
1338                        let _ = self.make_error();
1339                        e
1340                    })?;
1341                    let link_block = self.blockcache.get_block_uninit(link_block_no);
1342
1343                    link_block
1344                        .block_mut()
1345                        .set_datablock_no_in_link(0, data_block_no);
1346                    self.blockcache.write(link_block_no).map_err(|e| {
1347                        let _ = self.make_error();
1348                        e
1349                    })?;
1350
1351                    let list_of_links_block = self.blockcache.get_mut(list_of_links_block_no);
1352                    list_of_links_block
1353                        .block_mut()
1354                        .set_datablock_no_in_link(link_block_idx, link_block_no);
1355                    self.blockcache.write(list_of_links_block_no).map_err(|e| {
1356                        let _ = self.make_error();
1357                        e
1358                    })?;
1359                } else {
1360                    let link_block_no = self
1361                        .blockcache
1362                        .get(list_of_links_block_no)
1363                        .block()
1364                        .get_datablock_no_in_link(link_block_idx);
1365                    let link_block = self.blockcache.read_mut(link_block_no);
1366                    if let Err(err) = link_block {
1367                        let _ = self.make_error();
1368                        return Err(err);
1369                    }
1370                    let data_block_idx = (prev_size & (BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1))
1371                        >> BLOCK_SIZE.ilog2();
1372                    link_block
1373                        .unwrap()
1374                        .block_mut()
1375                        .set_datablock_no_in_link(data_block_idx, data_block_no);
1376                    self.blockcache.write(link_block_no).map_err(|e| {
1377                        let _ = self.make_error();
1378                        e
1379                    })?;
1380                }
1381            }
1382        }
1383
1384        // Commit the txn.
1385        let meta_block = self.blockcache.get_mut(file_id.block_no);
1386        let meta = unsafe { meta_block.block_mut().get_mut::<EntryMetadata>() };
1387        meta.size = new_size;
1388        meta.set_crc32();
1389        self.blockcache.write(file_id.block_no).map_err(|e| {
1390            let _ = self.make_error();
1391            e
1392        })?;
1393
1394        self.commit_txn()?;
1395        return Ok((new_size - prev_size) as usize);
1396    }
1397
1398    fn update_file(&mut self, file_id: EntryId, offset: u64, buf: &[u8]) -> Result<usize, FsError> {
1399        let data_block_no = self.find_data_block(file_id, offset)?;
1400        let block_end = align_up(offset + 1, BLOCK_SIZE);
1401        let new_end = (offset + (buf.len() as u64)).min(block_end);
1402        let data_block = self.blockcache.read_mut(data_block_no)?;
1403        unsafe {
1404            copy_nonoverlapping(
1405                buf.as_ptr(),
1406                (data_block.block_mut().as_bytes_mut().as_ptr() as usize
1407                    + ((offset & (BLOCK_SIZE - 1)) as usize)) as *mut u8,
1408                (new_end - offset) as usize,
1409            );
1410        }
1411        self.blockcache.write(data_block_no)?;
1412        return Ok((new_end - offset) as usize);
1413    }
1414
1415    fn find_data_block(&mut self, file_id: EntryId, offset: u64) -> Result<u64, FsError> {
1416        let meta_block = self.blockcache.get(file_id.block_no);
1417        let meta = unsafe { meta_block.block().get::<EntryMetadata>() };
1418        let file_size = meta.size;
1419        debug_assert!(file_size > MAX_BYTES_IN_META_BLOCK);
1420        debug_assert!(offset < file_size);
1421
1422        if file_size <= MAX_BYTES_ONLY_DATA_BLOCKS {
1423            // Files smaller than ~2M.
1424            let block_idx = offset >> BLOCK_SIZE.ilog2();
1425
1426            let meta_block = self.blockcache.get(file_id.block_no);
1427            return Ok(meta_block.block().get_datablock_no_in_meta(block_idx));
1428        }
1429
1430        if file_size <= MAX_BYTES_SINGLE_LEVEL_LIST_BLOCKS {
1431            // Files smaller than ~1G.
1432            let link_block_idx = offset >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
1433            let meta_block = self.blockcache.get(file_id.block_no);
1434            let link_block_no = meta_block.block().get_datablock_no_in_meta(link_block_idx);
1435
1436            let link_block = self.blockcache.read(link_block_no)?;
1437            let data_block_idx =
1438                (offset & (BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1)) >> BLOCK_SIZE.ilog2();
1439            return Ok(link_block.block().get_datablock_no_in_link(data_block_idx));
1440        }
1441
1442        // Files larger than ~1G.
1443        let list_of_links_block_idx = offset >> BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST.ilog2();
1444        let meta_block = self.blockcache.get(file_id.block_no);
1445        let list_of_links_block_no = meta_block
1446            .block()
1447            .get_datablock_no_in_meta(list_of_links_block_idx);
1448
1449        let list_of_links_block = self.blockcache.read(list_of_links_block_no)?;
1450        let link_block_idx = (offset & (BYTES_COVERED_BY_SECOND_LEVEL_BLOCKLIST - 1))
1451            >> BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST.ilog2();
1452        let link_block_no = list_of_links_block
1453            .block()
1454            .get_datablock_no_in_link(link_block_idx);
1455
1456        let link_block = self.blockcache.read(link_block_no)?;
1457        let data_block_idx =
1458            (offset & (BYTES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1)) >> BLOCK_SIZE.ilog2();
1459        return Ok(link_block.block().get_datablock_no_in_link(data_block_idx));
1460    }
1461
1462    fn find_entry_by_id(
1463        &mut self,
1464        parent_id: EntryId,
1465        entry_id: EntryId,
1466    ) -> Result<(u64 /* block_no */, usize /* entry_pos */), FsError> {
1467        self.find_entry(parent_id, |e| e.id == entry_id)
1468    }
1469
1470    fn find_entry_by_name(
1471        &mut self,
1472        parent_id: EntryId,
1473        name: &str,
1474    ) -> Result<(u64 /* block_no */, usize /* entry_pos */), FsError> {
1475        self.find_entry(parent_id, |e| {
1476            if let Ok(s) = core::str::from_utf8(&e.name[0..(e.name_len as usize)]) {
1477                s == name
1478            } else {
1479                false
1480            }
1481        })
1482    }
1483
1484    fn find_entry<F>(
1485        &mut self,
1486        parent_id: EntryId,
1487        pred: F,
1488    ) -> Result<(u64 /* block_no */, usize /* entry_pos */), FsError>
1489    where
1490        F: Fn(&DirEntryInternal) -> bool,
1491    {
1492        self.error?;
1493        let parent_block = self.blockcache.read(parent_id.block_no)?;
1494        let meta = unsafe { parent_block.block().get::<EntryMetadata>() };
1495        let valid = meta.validate_dir(parent_id);
1496        if valid.is_err() {
1497            let _ = self.make_error();
1498            return Err(valid.err().unwrap());
1499        }
1500
1501        let num_entries = meta.size;
1502        if num_entries <= MAX_ENTRIES_IN_META_BLOCK {
1503            for pos in 0..num_entries {
1504                let entry = parent_block.block().get_dir_entry((pos + 1) as usize);
1505                if pred(entry) {
1506                    return Ok((parent_id.block_no, (pos + 1) as usize));
1507                }
1508            }
1509            return Err(FsError::NotFound);
1510        }
1511
1512        if num_entries <= MAX_ENTRIES_ONLY_DATA_BLOCKS {
1513            let num_blocks =
1514                (num_entries + MAX_ENTRIES_IN_DATA_BLOCK - 1) / MAX_ENTRIES_IN_DATA_BLOCK;
1515            assert!(num_blocks <= MAX_LINKS_IN_META_BLOCK);
1516
1517            // Copy links out so that we don't have to juggle cached blocks.
1518            let block_nos = *parent_block.block();
1519
1520            let mut curr_entry_idx = 0;
1521            for block_idx in 0..num_blocks {
1522                let block_no = block_nos.get_datablock_no_in_meta(block_idx);
1523                let block = self.blockcache.read(block_no)?;
1524
1525                for pos in 0..MAX_ENTRIES_IN_DATA_BLOCK {
1526                    let entry = block.block().get_dir_entry(pos as usize);
1527                    if pred(entry) {
1528                        return Ok((block_no, pos as usize));
1529                    }
1530                    curr_entry_idx += 1;
1531                    if curr_entry_idx >= num_entries {
1532                        break;
1533                    }
1534                }
1535            }
1536            return Err(FsError::NotFound);
1537        }
1538
1539        let num_link_blocks = (num_entries + MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST - 1)
1540            / MAX_ENTRIES_COVERED_BY_FIRST_LEVEL_BLOCKLIST;
1541        assert!(num_link_blocks <= MAX_LINKS_IN_META_BLOCK);
1542        let num_blocks = (num_entries + MAX_ENTRIES_IN_DATA_BLOCK - 1) / MAX_ENTRIES_IN_DATA_BLOCK;
1543
1544        // Copy links out so that we don't have to juggle cached blocks.
1545        let link_block_nos = *parent_block.block();
1546
1547        let mut curr_entry_idx = 0;
1548        let mut curr_block_idx = 0;
1549        for link_block_idx in 0..num_link_blocks {
1550            let link_block_no = link_block_nos.get_datablock_no_in_meta(link_block_idx);
1551            let link_block = self.blockcache.read(link_block_no)?;
1552            let data_block_nos = *link_block.block();
1553            for pos_block in 0..512 {
1554                let data_block_no = data_block_nos.get_datablock_no_in_link(pos_block);
1555                let block = self.blockcache.read(data_block_no)?;
1556                for pos in 0..MAX_ENTRIES_IN_DATA_BLOCK {
1557                    let entry = block.block().get_dir_entry(pos as usize);
1558                    if pred(entry) {
1559                        return Ok((data_block_no, pos as usize));
1560                    }
1561                    curr_entry_idx += 1;
1562                    if curr_entry_idx >= num_entries {
1563                        break;
1564                    }
1565                }
1566                curr_block_idx += 1;
1567                if curr_block_idx >= num_blocks {
1568                    break;
1569                }
1570            }
1571        }
1572        return Err(FsError::NotFound);
1573    }
1574
1575    fn make_error(&mut self) -> Result<(), FsError> {
1576        assert!(self.error.is_ok());
1577        self.error = Err(FsError::ValidationFailed);
1578        return self.error;
1579    }
1580
1581    fn save_superblock(&mut self) -> Result<(), FsError> {
1582        assert!(self.error.is_ok());
1583        self.superblock.header_mut().set_crc32();
1584        self.blockcache
1585            .write_uncached_block(0, self.superblock.block())
1586            .map_err(|e| {
1587                let _ = self.make_error();
1588                e
1589            })
1590    }
1591
1592    fn plus_one(&mut self, block_no: u64) -> Result<(), FsError> {
1593        let block = self.blockcache.get_mut(block_no);
1594        let meta = unsafe { block.block_mut().get_mut::<EntryMetadata>() };
1595        meta.size += 1;
1596        meta.set_crc32();
1597        self.blockcache.write(block_no).map_err(|e| {
1598            let _ = self.make_error(); // We cannot recover from this.
1599            e
1600        })
1601    }
1602
1603    // Get a free block to use.
1604    fn allocate_txn_block(&mut self, block_type: BlockType) -> Result<u64, FsError> {
1605        let fbh = self.superblock.header_mut();
1606        assert_ne!(0, fbh.txn_blocks_owner);
1607        if fbh.free_blocks == 0 {
1608            return Err(FsError::FsFull);
1609        }
1610
1611        #[cfg(debug_assertions)]
1612        match block_type {
1613            BlockType::Metadata => debug_assert_eq!(0, fbh.txn_meta_block),
1614            BlockType::Data => debug_assert_eq!(0, fbh.txn_data_block),
1615            BlockType::Links => debug_assert_eq!(0, fbh.txn_link_block),
1616            BlockType::ListOfLinks => debug_assert_eq!(0, fbh.txn_list_of_links_block),
1617        }
1618
1619        let new_block_no = if fbh.freelist_head == 0 {
1620            // The freelist is empty: get the block from the empty area.
1621            let new_block_no = fbh.empty_area_start;
1622            fbh.empty_area_start += 1;
1623            new_block_no
1624        } else {
1625            // Get the block from the freelist.
1626            let new_block_no = fbh.freelist_head;
1627            let block = self.blockcache.read(new_block_no)?;
1628            fbh.freelist_head = *unsafe { block.block().get::<u64>() };
1629            if fbh.freelist_head >= fbh.num_blocks {
1630                log::error!("FS corrupted: bad freelist (1)");
1631                self.make_error()?;
1632                unreachable!()
1633            }
1634            new_block_no
1635        };
1636
1637        assert_ne!(new_block_no, 0);
1638        if new_block_no >= fbh.num_blocks {
1639            log::error!("FS corrupted: bad freelist (2)");
1640            self.make_error()?;
1641            unreachable!()
1642        }
1643        fbh.free_blocks -= 1;
1644        match block_type {
1645            BlockType::Metadata => fbh.txn_meta_block = new_block_no,
1646            BlockType::Data => fbh.txn_data_block = new_block_no,
1647            BlockType::Links => fbh.txn_link_block = new_block_no,
1648            BlockType::ListOfLinks => fbh.txn_list_of_links_block = new_block_no,
1649        }
1650        self.save_superblock()?;
1651
1652        Ok(new_block_no)
1653    }
1654
1655    fn free_txn_block(&mut self, block_type: BlockType) -> Result<(), FsError> {
1656        let sbh = self.superblock.header_mut();
1657        let block_no = match block_type {
1658            BlockType::Metadata => sbh.txn_meta_block,
1659            BlockType::Data => sbh.txn_data_block,
1660            BlockType::Links => sbh.txn_link_block,
1661            BlockType::ListOfLinks => sbh.txn_list_of_links_block,
1662        };
1663        assert_ne!(0, block_no);
1664        if sbh.empty_area_start == (block_no + 1) {
1665            sbh.empty_area_start -= 1;
1666        } else {
1667            let prev_head = sbh.freelist_head;
1668            let block = self.blockcache.get_block_uninit(block_no);
1669            unsafe { *block.block_mut().get_mut::<u64>() = prev_head };
1670            self.blockcache.write(block_no)?;
1671        }
1672
1673        match block_type {
1674            BlockType::Metadata => sbh.txn_meta_block = 0,
1675            BlockType::Data => sbh.txn_data_block = 0,
1676            BlockType::Links => sbh.txn_link_block = 0,
1677            BlockType::ListOfLinks => sbh.txn_list_of_links_block = 0,
1678        }
1679        sbh.free_blocks += 1;
1680        self.save_superblock()
1681    }
1682
1683    fn start_txn(&mut self, txn_type: u32, owner: EntryId) -> Result<(), FsError> {
1684        let sbh = self.superblock.header_mut();
1685        assert_eq!(TXN_TYPE_NONE, sbh.txn_type);
1686        assert_eq!(0, sbh.txn_blocks_owner);
1687        assert_eq!(0, sbh.txn_meta_block);
1688        assert_eq!(0, sbh.txn_data_block);
1689        assert_eq!(0, sbh.txn_link_block);
1690        assert_eq!(0, sbh.txn_list_of_links_block);
1691        sbh.txn_blocks_owner = owner.block_no;
1692        sbh.txn_type = txn_type;
1693
1694        self.save_superblock()
1695    }
1696
1697    fn commit_txn(&mut self) -> Result<(), FsError> {
1698        let sbh = self.superblock.header_mut();
1699        sbh.txn_meta_block = 0;
1700        sbh.txn_data_block = 0;
1701        sbh.txn_link_block = 0;
1702        sbh.txn_list_of_links_block = 0;
1703        sbh.txn_blocks_owner = 0;
1704        sbh.txn_type = TXN_TYPE_NONE;
1705        self.save_superblock()
1706    }
1707}