20#include "Iso9660Directory.h"
21#include "pedigree/kernel/utilities/BufferView.h"
24constexpr uint64_t IsoSectorSize = 2048;
27Iso9660Directory::~Iso9660Directory() =
default;
32 return LookupStatus::IoError;
37 const ReadStatus status = scanDirectory(cookie, resolveEntry, &context);
39 child = context.child;
40 return LookupStatus::Found;
42 if (status == ReadStatus::IoError) {
43 return LookupStatus::IoError;
45 return LookupStatus::NotFound;
52 return LookupStatus::IoError;
55 const uint64_t expectedCookie = cookie;
56 ResolveContext context = {
this, name,
nullptr, expectedCookie,
true};
57 scanDirectory(cookie, resolveEntry, &context);
59 child = context.child;
60 return LookupStatus::Found;
68 DirectoryEntryEmitter emitter,
71 return ReadStatus::IoError;
75 return scanDirectory(cookie, emitEntry, &readContext);
78Directory::ReadStatus Iso9660Directory::scanDirectory(uint64_t& cookie, ScannedEntryEmitter emitter,
80 if (!m_pFs || !emitter) {
81 return ReadStatus::IoError;
84 const uint64_t directorySize = LITTLE_TO_HOST32(m_Dir.DataLen_LE);
85 const uint64_t directoryLocation = LITTLE_TO_HOST32(m_Dir.ExtentLocation_LE);
86 const uint64_t sectorCount = (directorySize + IsoSectorSize - 1) / IsoSectorSize;
87 if (cookie > directorySize) {
88 return ReadStatus::IoError;
91 uint64_t scanCookie = cookie;
92 while (scanCookie < directorySize) {
93 const uint64_t sector = scanCookie / IsoSectorSize;
94 if (sector >= sectorCount) {
95 return ReadStatus::IoError;
98 const uint64_t sectorStart = sector * IsoSectorSize;
99 const size_t sectorLimit =
static_cast<size_t>(min(IsoSectorSize, directorySize - sectorStart));
100 size_t offset =
static_cast<size_t>(scanCookie - sectorStart);
103 const uint64_t diskLocation = (directoryLocation + sector) * IsoSectorSize;
104 if (!m_pFs->
readSector(diskLocation, sectorBytes)) {
105 return ReadStatus::IoError;
107 const BufferView buffer(sectorBytes,
sizeof(sectorBytes));
109 while (offset < sectorLimit) {
110 const uint64_t currentCookie = sectorStart + offset;
111 cookie = currentCookie;
114 if (!sectorBytes[offset]) {
115 scanCookie = min(sectorStart + IsoSectorSize, directorySize);
120 const size_t bytesRemaining = sectorLimit - offset;
122 return ReadStatus::IoError;
126 const size_t recordLength = record->RecLen;
127 if (recordLength <
sizeof(*record) || recordLength > bytesRemaining ||
128 !record->FileIdentLen || record->FileIdentLen > (recordLength -
sizeof(*record))) {
129 return ReadStatus::IoError;
132 const uint64_t nextCookie = currentCookie + recordLength;
133 uint8_t* fileIdentifier = buffer.as<uint8_t>(offset +
sizeof(*record));
134 offset += recordLength;
135 scanCookie = nextCookie;
138 const bool dotEntry =
139 record->FileIdentLen == 1 && (fileIdentifier[0] == 0 || fileIdentifier[0] == 1);
140 if (dotEntry || (record->FileFlags & (1 << 0))) {
145 String fileName = m_pFs->parseName(*record);
146 ScannedEntry entry = {&fileName, record, currentCookie, nextCookie};
147 if (!emitter(context, entry)) {
148 cookie = currentCookie;
149 return ReadStatus::Stopped;
155 cookie = directorySize;
156 return ReadStatus::Complete;
159bool Iso9660Directory::resolveEntry(
void* opaque,
const ScannedEntry& entry) {
160 ResolveContext* context =
reinterpret_cast<ResolveContext*
>(opaque);
161 if (context->checkCookie && entry.currentCookie != context->expectedCookie) {
164 if (!(*entry.name == context->name)) {
165 return !context->checkCookie;
168 const bool directory = (entry.record->FileFlags & (1 << 1)) != 0;
170 context->directory->m_pFs->fileFromDirRecord(*entry.record, 0, context->directory, directory);
174bool Iso9660Directory::emitEntry(
void* opaque,
const ScannedEntry& scanned) {
175 ReadContext* context =
reinterpret_cast<ReadContext*
>(opaque);
176 const EntryType type =
177 (scanned.record->FileFlags & (1 << 1)) ? EntryType::Directory : EntryType::Regular;
178 DirectoryEntryView entry = {scanned.name->view(), 0, type, scanned.currentCookie,
180 return context->emitter(context->context, entry);
LookupStatus resolveChild(const StringView &name, File *&child) override
LookupStatus resolveChildAt(uint64_t cookie, const StringView &name, File *&child) override
ReadStatus readDirectory(uint64_t &cookie, DirectoryEntryEmitter emitter, void *context) override
bool readSector(uint64_t location, void *destination)