summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats
diff options
context:
space:
mode:
author npwoods <npwoods@mess.org>2022-04-24 23:03:58 -0400
committer GitHub <noreply@github.com>2022-04-24 23:03:58 -0400
commit174c246037911759fbbdff64c1da909802efcf83 (patch)
tree0f179cd1e2f47a762f6b959cc0fbbf278952c816 /src/lib/formats
parentfd500d142ba516c0793882f125fa2c979d390a6e (diff)
Add logic to the CoCo RS-DOS FS module to catch cycles in file granule (block) lists (#9615)
Diffstat (limited to 'src/lib/formats')
-rw-r--r--src/lib/formats/fs_coco_rsdos.cpp18
1 files changed, 15 insertions, 3 deletions
diff --git a/src/lib/formats/fs_coco_rsdos.cpp b/src/lib/formats/fs_coco_rsdos.cpp
index aa201a7df92..c229257d624 100644
--- a/src/lib/formats/fs_coco_rsdos.cpp
+++ b/src/lib/formats/fs_coco_rsdos.cpp
@@ -13,6 +13,7 @@
#include "util/corestr.h"
#include "util/strformat.h"
+#include <bitset>
#include <optional>
#include <string_view>
@@ -70,6 +71,7 @@ public:
std::optional<u8> m_current_granule;
u8 m_maximum_granules;
u16 m_last_sector_bytes;
+ std::bitset<256> m_visited_granules;
};
class file : public ifile_t {
@@ -397,6 +399,8 @@ impl::granule_iterator::granule_iterator(impl &fs, const rsdos_dirent &dirent)
, m_maximum_granules(fs.maximum_granules())
, m_last_sector_bytes((u16(dirent.m_last_sector_bytes_msb) << 8) | dirent.m_last_sector_bytes_lsb)
{
+ // visit the first granule
+ m_visited_granules.set(dirent.m_first_granule);
}
@@ -412,6 +416,7 @@ bool impl::granule_iterator::next(u8 &granule, u16 &byte_count)
if (m_current_granule)
{
+ std::optional<u8> next_granule;
const u8 *granule_map_data = m_granule_map.rodata();
if (granule_map_data[*m_current_granule] < m_maximum_granules)
{
@@ -419,7 +424,13 @@ bool impl::granule_iterator::next(u8 &granule, u16 &byte_count)
success = true;
granule = *m_current_granule;
byte_count = 9 * 256;
- m_current_granule = granule_map_data[*m_current_granule];
+ next_granule = granule_map_data[*m_current_granule];
+
+ // check for cycles, which should only happen if the disk is corrupt (or not in RS-DOS format)
+ if (m_visited_granules[*next_granule])
+ next_granule = std::nullopt; // this is corrupt!
+ else
+ m_visited_granules.set(*next_granule);
}
else if (granule_map_data[*m_current_granule] >= 0xC0 && granule_map_data[*m_current_granule] <= 0xC9)
{
@@ -428,13 +439,14 @@ bool impl::granule_iterator::next(u8 &granule, u16 &byte_count)
granule = *m_current_granule;
u16 sector_count = std::max(granule_map_data[*m_current_granule], u8(0xC1)) - 0xC1;
byte_count = sector_count * 256 + m_last_sector_bytes;
- m_current_granule = std::nullopt;
+ next_granule = std::nullopt;
}
else
{
// should not happen; but we'll treat this as an EOF
- m_current_granule = std::nullopt;
+ next_granule = std::nullopt;
}
+ m_current_granule = next_granule;
}
return success;
}