Serenity Operating System
at master 134 lines 4.3 kB view raw
1/* 2 * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Types.h> 8#include <Kernel/FileSystem/ISO9660FS/Definitions.h> 9#include <Kernel/FileSystem/ISO9660FS/DirectoryIterator.h> 10#include <Kernel/KBuffer.h> 11 12namespace Kernel { 13 14ISO9660DirectoryIterator::ISO9660DirectoryIterator(ISO9660FS& fs, ISO::DirectoryRecordHeader const& header) 15 : m_fs(fs) 16 , m_current_header(&header) 17{ 18 // FIXME: Panic or alternative method? 19 (void)read_directory_contents(); 20 get_header(); 21} 22 23ErrorOr<bool> ISO9660DirectoryIterator::next() 24{ 25 if (done()) 26 return false; 27 dbgln_if(ISO9660_VERY_DEBUG, "next(): Called"); 28 29 if (has_flag(m_current_header->file_flags, ISO::FileFlags::Directory)) { 30 dbgln_if(ISO9660_VERY_DEBUG, "next(): Recursing"); 31 { 32 TRY(m_directory_stack.try_append(move(m_current_directory))); 33 } 34 35 dbgln_if(ISO9660_VERY_DEBUG, "next(): Pushed into directory stack"); 36 37 TRY(read_directory_contents()); 38 39 dbgln_if(ISO9660_VERY_DEBUG, "next(): Read directory contents"); 40 41 m_current_directory.offset = 0; 42 get_header(); 43 if (m_current_header->length == 0) { 44 // We have found an empty directory, let's continue with the 45 // next one. 46 if (!go_up()) 47 return false; 48 } else { 49 // We cannot skip here, as this is the first record in this 50 // extent. 51 return true; 52 } 53 } 54 55 return skip(); 56} 57 58bool ISO9660DirectoryIterator::skip() 59{ 60 VERIFY(m_current_directory.entry); 61 62 if (m_current_directory.offset >= m_current_directory.entry->length) { 63 dbgln_if(ISO9660_VERY_DEBUG, "skip(): Was at last item already"); 64 return false; 65 } 66 67 m_current_directory.offset += m_current_header->length; 68 get_header(); 69 if (m_current_header->length == 0) { 70 // According to ECMA 119, if a logical block contains directory 71 // records, then the leftover bytes in the logical block are 72 // all zeros. So if our directory header has a length of 0, 73 // we're probably looking at padding. 74 // 75 // Of course, this doesn't mean we're done; it only means that there 76 // are no more directory entries in *this* logical block. If we 77 // have at least one more logical block of data length to go, we 78 // need to snap to the next logical block, because directory records 79 // cannot span multiple logical blocks. 80 u32 remaining_bytes = m_current_directory.entry->length - m_current_directory.offset; 81 if (remaining_bytes > m_fs.logical_block_size()) { 82 m_current_directory.offset += remaining_bytes % m_fs.logical_block_size(); 83 get_header(); 84 85 dbgln_if(ISO9660_VERY_DEBUG, "skip(): Snapped to next logical block (succeeded)"); 86 return true; 87 } 88 89 dbgln_if(ISO9660_VERY_DEBUG, "skip(): Was at the last logical block, at padding now (offset {}, data length {})", m_current_directory.entry->length, m_current_directory.offset); 90 return false; 91 } 92 93 dbgln_if(ISO9660_VERY_DEBUG, "skip(): Skipped to next item"); 94 return true; 95} 96 97bool ISO9660DirectoryIterator::go_up() 98{ 99 if (m_directory_stack.is_empty()) { 100 dbgln_if(ISO9660_VERY_DEBUG, "go_up(): Empty directory stack"); 101 return false; 102 } 103 104 m_current_directory = m_directory_stack.take_last(); 105 get_header(); 106 107 dbgln_if(ISO9660_VERY_DEBUG, "go_up(): Went up a directory"); 108 return true; 109} 110 111bool ISO9660DirectoryIterator::done() const 112{ 113 VERIFY(m_current_directory.entry); 114 auto result = m_directory_stack.is_empty() && m_current_directory.offset >= m_current_directory.entry->length; 115 dbgln_if(ISO9660_VERY_DEBUG, "done(): {}", result); 116 return result; 117} 118 119ErrorOr<void> ISO9660DirectoryIterator::read_directory_contents() 120{ 121 m_current_directory.entry = TRY(m_fs.directory_entry_for_record({}, m_current_header)); 122 return {}; 123} 124 125void ISO9660DirectoryIterator::get_header() 126{ 127 VERIFY(m_current_directory.entry); 128 if (!m_current_directory.entry->blocks) 129 return; 130 131 m_current_header = reinterpret_cast<ISO::DirectoryRecordHeader const*>(m_current_directory.entry->blocks->data() + m_current_directory.offset); 132} 133 134}