diff --git a/data/drive.img b/data/drive.img new file mode 100644 index 0000000..c97c12f Binary files /dev/null and b/data/drive.img differ diff --git a/src/components/drive.c b/src/components/drive.c index 3af2046..2a4ea23 100644 --- a/src/components/drive.c +++ b/src/components/drive.c @@ -51,6 +51,11 @@ void nn_drive_readSector(nn_drive *drive, void *_, nn_component *component, nn_c nn_value sectorValue = nn_getArgument(computer, 0); int sector = nn_toInt(sectorValue); size_t sector_size = drive->getSectorSize(component, drive->userdata); + // we leave the +1 intentionally to compare the end of the real sector + if (sector < 1 || (sector * sector_size > drive->getCapacity(component, drive->userdata))) { + nn_setCError(computer, "bad argument #1 (sector out of range)"); + return; + } char buf[sector_size]; drive->readSector(component, drive->userdata, sector, buf); nn_return_string(computer, buf, sector_size); @@ -60,16 +65,31 @@ void nn_drive_writeSector(nn_drive *drive, void *_, nn_component *component, nn_ int sector = nn_toInt(sectorValue); size_t sector_size = drive->getSectorSize(component, drive->userdata); nn_value bufValue = nn_getArgument(computer, 1); - const char *buf = nn_toString(bufValue, §or_size); + + size_t buf_size = 0; + const char *buf = nn_toString(bufValue, &buf_size); + if (buf_size != sector_size) { + nn_setCError(computer, "bad argument #2 (expected buffer of length `sectorSize`)"); + return; + } + // we leave the +1 intentionally to compare the end of the real sector + if (sector < 1 || (sector * sector_size > drive->getCapacity(component, drive->userdata))) { + nn_setCError(computer, "bad argument #1 (sector out of range)"); + return; + } drive->writeSector(component, drive->userdata, sector, buf); } void nn_drive_readByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_value offsetValue = nn_getArgument(computer, 0); - size_t disk_offset = nn_toInt(offsetValue); + size_t disk_offset = nn_toInt(offsetValue) - 1; size_t sector_size = drive->getSectorSize(component, drive->userdata); - int sector = disk_offset / sector_size; + int sector = (disk_offset / sector_size) + 1; size_t sector_offset = disk_offset % sector_size; + if (disk_offset >= drive->getCapacity(component, drive->userdata)) { + nn_setCError(computer, "bad argument #1 (index out of range)"); + return; + } char buf[sector_size]; drive->readSector(component, drive->userdata, sector, buf); @@ -78,12 +98,20 @@ void nn_drive_readByte(nn_drive *drive, void *_, nn_component *component, nn_com void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_value offsetValue = nn_getArgument(computer, 0); nn_value writeValue = nn_getArgument(computer, 1); - size_t disk_offset = nn_toInt(offsetValue); - char write = nn_toInt(writeValue); + size_t disk_offset = nn_toInt(offsetValue) - 1; + intptr_t write = nn_toInt(writeValue); size_t sector_size = drive->getSectorSize(component, drive->userdata); - int sector = disk_offset / sector_size; + int sector = (disk_offset / sector_size) + 1; size_t sector_offset = disk_offset % sector_size; + if (write < -128 || write > 255) { + nn_setCError(computer, "bad argument #2 (byte out of range)"); + return; + } + if (disk_offset >= drive->getCapacity(component, drive->userdata)) { + nn_setCError(computer, "bad argument #1 (index out of range)"); + return; + } char buf[sector_size]; drive->readSector(component, drive->userdata, sector, buf); diff --git a/src/emulator.c b/src/emulator.c index 141ac9b..abe2f7b 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -238,6 +238,47 @@ bool ne_fs_exists(nn_component *component, ne_fs *fs, const char *path) { return FileExists(p) || DirectoryExists(p); } +typedef struct ne_drive { + FILE *file; +} ne_drive; + +void ne_drive_close(nn_component *component, ne_drive *drive) { + fclose(drive->file); +} +nn_driveControl ne_drive_getControl(nn_component *component, ne_drive *_) { + return (nn_driveControl){}; +} +size_t ne_drive_getPlatterCount(nn_component *component, ne_drive *_) { + return 1; +} +size_t ne_drive_getSectorSize(nn_component *component, ne_drive *_) { + return 512; +} +size_t ne_drive_getCapacity(nn_component *component, ne_drive *drive) { + fseek(drive->file, 0, SEEK_END); + return ftell(drive->file); +} +void ne_drive_readSector(nn_component *component, ne_drive *drive, int shifted_sector, char *buf) { + int sector = shifted_sector - 1; + size_t sectorSize = ne_drive_getSectorSize(component, drive); + + size_t offset = sector * sectorSize; + fseek(drive->file, offset, SEEK_SET); + fread(buf, sizeof(char), sectorSize, drive->file); +} +void ne_drive_writeSector(nn_component *component, ne_drive *drive, int shifted_sector, const char *buf) { + int sector = shifted_sector - 1; + size_t sectorSize = ne_drive_getSectorSize(component, drive); + + size_t offset = sector * sectorSize; + fseek(drive->file, offset, SEEK_SET); + fwrite(buf, sizeof(char), sectorSize, drive->file); + + // this is probably not needed but i believe someone isn't running the deinit + fflush(drive->file); +} + + int keycode_to_oc(int keycode) { switch (keycode) { case KEY_NULL: @@ -533,6 +574,27 @@ int main() { }; nn_addFileSystem(computer, "OpenOS", 1, &genericFS); + ne_drive drive = { + .file = fopen("data/drive.img", "r+") + }; + assert(drive.file != NULL); + + nn_drive genericDrive = { + .refc = 0, + .userdata = &drive, + .deinit = (void *)ne_drive_close, + .control = (void *)ne_drive_getControl, + .getLabel = ne_eeprom_getLabel, + .setLabel = ne_eeprom_setLabel, + .getPlatterCount = (void *)ne_drive_getPlatterCount, + .getSectorSize = (void *)ne_drive_getSectorSize, + .getCapacity = (void *)ne_drive_getCapacity, + .readSector = (void *)ne_drive_readSector, + .writeSector = (void *)ne_drive_writeSector, + }; + + nn_addDrive(computer, "drive.img", 4, &genericDrive); + nn_screen *s = nn_newScreen(&alloc, 80, 32, 16, 16, 256); nn_addKeyboard(s, "shitty keyboard"); nn_mountKeyboard(computer, "shitty keyboard", 2);