| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- /**
- * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
- *
- * This file is licensed under the GPL version 3 or any later version.
- * It is derived from disk.c in SCSI2SD V6
- *
- * https://www.gnu.org/licenses/gpl-3.0.html
- * ----
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- **/
- #include "ImageBackingStore.h"
- #include <SdFat.h>
- #include <BlueSCSI_platform.h>
- #include "BlueSCSI_log.h"
- #include "BlueSCSI_config.h"
- #include <minIni.h>
- #include <strings.h>
- #include <string.h>
- #include <assert.h>
- ImageBackingStore::ImageBackingStore()
- {
- m_israw = false;
- m_isrom = false;
- m_isreadonly_attr = false;
- m_blockdev = nullptr;
- m_bgnsector = m_endsector = m_cursector = 0;
- }
- ImageBackingStore::ImageBackingStore(const char *filename, uint32_t scsi_block_size): ImageBackingStore()
- {
- if (strncasecmp(filename, "RAW:", 4) == 0)
- {
- char *endptr, *endptr2;
- m_bgnsector = strtoul(filename + 4, &endptr, 0);
- m_endsector = strtoul(endptr + 1, &endptr2, 0);
- if (*endptr != ':' || *endptr2 != '\0')
- {
- log("Invalid format for raw filename: ", filename);
- return;
- }
- if ((scsi_block_size % SD_SECTOR_SIZE) != 0)
- {
- log("SCSI block size ", (int)scsi_block_size, " is not supported for RAW partitions (must be divisible by 512 bytes)");
- return;
- }
- m_israw = true;
- m_blockdev = SD.card();
- uint32_t sectorCount = SD.card()->sectorCount();
- if (m_endsector >= sectorCount)
- {
- log("Limiting RAW image mapping to SD card sector count: ", (int)sectorCount);
- m_endsector = sectorCount - 1;
- }
- }
- else if (strncasecmp(filename, "ROM:", 4) == 0)
- {
- if (!romDriveCheckPresent(&m_romhdr))
- {
- m_romhdr.imagesize = 0;
- }
- else
- {
- m_isrom = true;
- }
- }
- else
- {
- m_isreadonly_attr = !!(FS_ATTRIB_READ_ONLY & SD.attrib(filename));
- if (m_isreadonly_attr)
- {
- m_fsfile = SD.open(filename, O_RDONLY);
- log("---- Image file is read-only, writes disabled");
- }
- else
- {
- m_fsfile = SD.open(filename, O_RDWR);
- }
- uint32_t sectorcount = m_fsfile.size() / SD_SECTOR_SIZE;
- uint32_t begin = 0, end = 0;
- if (m_fsfile.contiguousRange(&begin, &end) && end >= begin + sectorcount
- && (scsi_block_size % SD_SECTOR_SIZE) == 0)
- {
- // Convert to raw mapping, this avoids some unnecessary
- // access overhead in SdFat library.
- // If non-aligned offsets are later requested, it automatically falls
- // back to SdFat access mode.
- m_israw = true;
- m_blockdev = SD.card();
- m_bgnsector = begin;
- m_endsector = begin + sectorcount - 1;
- m_fsfile.flush(); // Note: m_fsfile is also kept open as a fallback.
- }
- }
- }
- bool ImageBackingStore::isOpen()
- {
- if (m_israw)
- return (m_blockdev != NULL);
- else if (m_isrom)
- return (m_romhdr.imagesize > 0);
- else
- return m_fsfile.isOpen();
- }
- bool ImageBackingStore::isWritable()
- {
- return !(m_isrom && m_isreadonly_attr);
- }
- bool ImageBackingStore::isRom()
- {
- return m_isrom;
- }
- bool ImageBackingStore::isRaw()
- {
- return m_israw;
- }
- bool ImageBackingStore::close()
- {
- if (m_israw)
- {
- m_blockdev = nullptr;
- return true;
- }
- else if (m_isrom)
- {
- m_romhdr.imagesize = 0;
- return true;
- }
- else
- {
- return m_fsfile.close();
- }
- }
- uint64_t ImageBackingStore::size()
- {
- if (m_israw && m_blockdev)
- {
- return (uint64_t)(m_endsector - m_bgnsector + 1) * SD_SECTOR_SIZE;
- }
- else if (m_isrom)
- {
- return m_romhdr.imagesize;
- }
- else
- {
- return m_fsfile.size();
- }
- }
- bool ImageBackingStore::contiguousRange(uint32_t* bgnSector, uint32_t* endSector)
- {
- if (m_israw && m_blockdev)
- {
- *bgnSector = m_bgnsector;
- *endSector = m_endsector;
- return true;
- }
- else if (m_isrom)
- {
- *bgnSector = 0;
- *endSector = 0;
- return true;
- }
- else
- {
- return m_fsfile.contiguousRange(bgnSector, endSector);
- }
- }
- bool ImageBackingStore::seek(uint64_t pos)
- {
- uint32_t sectornum = pos / SD_SECTOR_SIZE;
- if (m_israw && (uint64_t)sectornum * SD_SECTOR_SIZE != pos)
- {
- debuglog("---- Unaligned access to image, falling back to SdFat access mode");
- m_israw = false;
- }
- if (m_israw)
- {
- m_cursector = m_bgnsector + sectornum;
- return (m_cursector <= m_endsector);
- }
- else if (m_isrom)
- {
- uint32_t sectornum = pos / SD_SECTOR_SIZE;
- assert((uint64_t)sectornum * SD_SECTOR_SIZE == pos);
- m_cursector = sectornum;
- return m_cursector * SD_SECTOR_SIZE < m_romhdr.imagesize;
- }
- else
- {
- return m_fsfile.seek(pos);
- }
- }
- ssize_t ImageBackingStore::read(void* buf, size_t count)
- {
- uint32_t sectorcount = count / SD_SECTOR_SIZE;
- if (m_israw && (uint64_t)sectorcount * SD_SECTOR_SIZE != count)
- {
- debuglog("---- Unaligned access to image, falling back to SdFat access mode");
- m_israw = false;
- }
- if (m_israw && m_blockdev)
- {
- if (m_blockdev->readSectors(m_cursector, (uint8_t*)buf, sectorcount))
- {
- m_cursector += sectorcount;
- return count;
- }
- else
- {
- return -1;
- }
- }
- else if (m_isrom)
- {
- assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
- uint32_t start = m_cursector * SD_SECTOR_SIZE;
- if (romDriveRead((uint8_t*)buf, start, count))
- {
- m_cursector += sectorcount;
- return count;
- }
- else
- {
- return -1;
- }
- }
- else
- {
- return m_fsfile.read(buf, count);
- }
- }
- ssize_t ImageBackingStore::write(const void* buf, size_t count)
- {
- uint32_t sectorcount = count / SD_SECTOR_SIZE;
- if (m_israw && (uint64_t)sectorcount * SD_SECTOR_SIZE != count)
- {
- debuglog("---- Unaligned access to image, falling back to SdFat access mode");
- m_israw = false;
- }
- if (m_israw && m_blockdev)
- {
- if (m_blockdev->writeSectors(m_cursector, (const uint8_t*)buf, sectorcount))
- {
- m_cursector += sectorcount;
- return count;
- }
- else
- {
- return 0;
- }
- }
- else if (m_isrom)
- {
- log("ERROR: attempted to write to ROM drive");
- return 0;
- }
- else if (m_isreadonly_attr)
- {
- log("ERROR: attempted to write to a read only image");
- return 0;
- }
- else
- {
- return m_fsfile.write(buf, count);
- }
- }
- void ImageBackingStore::flush()
- {
- if (!m_israw && !m_isrom && !m_isreadonly_attr)
- {
- m_fsfile.flush();
- }
- }
- void ImageBackingStore::getName(char * name, size_t len)
- {
- if(m_isrom)
- name = (char*)"ROM:";
- else if(m_israw)
- name = (char*)"RAW:";
- else
- m_fsfile.getName(name, len);
- }
- uint64_t ImageBackingStore::position()
- {
- if (!m_israw && !m_isrom)
- {
- return m_fsfile.curPosition();
- }
- else
- {
- return 0;
- }
- }
|