mirror of
https://github.com/sarah-walker-pcem/pcem.git
synced 2025-07-23 11:43:03 +02:00
Add ramdisk preloaded from RAW/VHD image file (*.rdimg;*.rdvhd) (#275)
This commit is contained in:
@@ -4,6 +4,9 @@
|
||||
- Numerous bugfixes in this build
|
||||
- Changed some GUI elements.
|
||||
- Preliminary Plugin Extensions Created
|
||||
- Added RAM disk preloaded with RAW/VHD images (*.rdimg;*.rdvhd)
|
||||
- Load up to 2GB disks to temporary disk (doesn't modify the image file)
|
||||
- Mounts as read-only if memory allocation fails (mind the 32bit PCem memory limits)
|
||||
|
||||
## Added the following machines to v18
|
||||
- Hyundai SUPER-16T
|
||||
|
@@ -3,6 +3,7 @@
|
||||
typedef enum hdd_img_type {
|
||||
HDD_IMG_RAW,
|
||||
HDD_IMG_VHD,
|
||||
HDD_IMG_RAW_RAM,
|
||||
} hdd_img_type;
|
||||
|
||||
typedef struct hdd_file_t {
|
||||
|
95
includes/private/hdd/ramdisk/ramdisk.h
Normal file
95
includes/private/hdd/ramdisk/ramdisk.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef __HAVE_RAMDISK_H__
|
||||
#define __HAVE_RAMDISK_H__
|
||||
/*
|
||||
* Growable RAM disk memory stream for PCem by MMaster (2024)
|
||||
*
|
||||
* - Automatically grows memory buffer (disk size)
|
||||
* - Maintains expected size separate from allocated size
|
||||
* - Only writes and set_size calls grow memory
|
||||
* - Allows preload from raw image file
|
||||
* - Behaves similarly to fread, fwrite & fseek
|
||||
*
|
||||
* Note: Maximum size is 2GB - 1B
|
||||
*/
|
||||
|
||||
/* ramdisk context */
|
||||
typedef struct ramdisk ramdisk_t;
|
||||
|
||||
/**
|
||||
* Create new ramdisk.
|
||||
*/
|
||||
ramdisk_t *ramdisk_init();
|
||||
|
||||
/**
|
||||
* Release ramdisk memory.
|
||||
*
|
||||
* @param ramdisk Ramdisk context
|
||||
*/
|
||||
void ramdisk_free(ramdisk_t *ramdisk);
|
||||
|
||||
/**
|
||||
* Set required size of the disk.
|
||||
*
|
||||
* @note Disk is still growable with writes beyond end.
|
||||
* @param ramdisk Ramdisk context
|
||||
* @param size New size of the disk
|
||||
* @raturn 0 on success, -1 if unable to resize
|
||||
*/
|
||||
int ramdisk_set_size(ramdisk_t *ramdisk, size_t size);
|
||||
|
||||
/**
|
||||
* Write data to ramdisk at cursor.
|
||||
*
|
||||
* @note Data may be written beyond the current size of the disk.
|
||||
* @param ramdisk Ramdisk context
|
||||
* @param buf Buffer containing data to be written
|
||||
* @param size Size of the buffer
|
||||
* @return 0 on EOF, -1 on error (sets errno), >0 number of bytes written
|
||||
*/
|
||||
int ramdisk_write(ramdisk_t *ramdisk, const char *buf, size_t size);
|
||||
|
||||
/**
|
||||
* Read data from ramdisk at cursor.
|
||||
*
|
||||
* @param ramdisk Ramdisk context
|
||||
* @param buf Buffer for data to be read to
|
||||
* @param size Size of the buffer
|
||||
* @return 0 on EOF, -1 on error (sets errno), >0 number of bytes read
|
||||
*/
|
||||
int ramdisk_read(ramdisk_t *ramdisk, char *buf, size_t size);
|
||||
|
||||
/**
|
||||
* Seek within the ramdisk. Moves the cursor.
|
||||
*
|
||||
* @param ramdisk Ramdisk context
|
||||
* @param offset Offset from position specified by "whence" parameter.
|
||||
* @param whence SEEK_SET, SEEK_CUR or SEEK_END
|
||||
* @return >=0 disk cursor offset, -1 on error (sets errno)
|
||||
*/
|
||||
int ramdisk_seek(ramdisk_t *ramdisk, off_t offset, int whence);
|
||||
|
||||
/**
|
||||
* Get temporary pointer to buffer from current cursor in ramdisk.
|
||||
*
|
||||
* Warning: This pointer is volatile and may be invalidated by write and set size calls.
|
||||
* Do not try to free this buffer!
|
||||
*
|
||||
* @param ramdisk Ramdisk context
|
||||
* @param mem Pointer to memory pointer that will be set to ramdisk buffer.
|
||||
* @param size Pointer to size of the buffer
|
||||
* @return 0 on EOF, -1 on error (cursor outside of allocated memory)
|
||||
*/
|
||||
int ramdisk_get_cursor_mem(ramdisk_t *ramdisk, char **mem, size_t *size);
|
||||
|
||||
/**
|
||||
* Load data from file to ramdisk at cursor.
|
||||
*
|
||||
* @note Data may be written beyond the current size of the disk.
|
||||
* @param ramdisk Ramdisk context
|
||||
* @param fp raw image FILE pointer
|
||||
* @return 0 on EOF, -1 on error (sets errno), >0 number of bytes written
|
||||
*/
|
||||
int ramdisk_load_file(ramdisk_t *ramdisk, FILE *fp);
|
||||
|
||||
#endif /* !__HAVE_RAMDISK_H__ */
|
||||
|
@@ -2,6 +2,7 @@ set(PCEM_PRIVATE_API ${PCEM_PRIVATE_API}
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/hdd_esdi.h
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/hdd_file.h
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/hdd.h
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/ramdisk/ramdisk.h
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/minivhd/cwalk.h
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/minivhd/libxml2_encoding.h
|
||||
${CMAKE_SOURCE_DIR}/includes/private/hdd/minivhd/minivhd_create.h
|
||||
@@ -18,6 +19,11 @@ set(PCEM_SRC ${PCEM_SRC}
|
||||
hdd/hdd_file.c
|
||||
)
|
||||
|
||||
# RAMDisk
|
||||
set(PCEM_SRC ${PCEM_SRC}
|
||||
hdd/ramdisk/ramdisk.c
|
||||
)
|
||||
|
||||
# MiniVHD
|
||||
set(PCEM_SRC ${PCEM_SRC}
|
||||
hdd/minivhd/cwalk.c
|
||||
|
@@ -5,10 +5,30 @@
|
||||
|
||||
#include "ibm.h"
|
||||
#include "hdd_file.h"
|
||||
#include "ramdisk/ramdisk.h"
|
||||
#include "minivhd/minivhd.h"
|
||||
#include "minivhd/minivhd_util.h"
|
||||
|
||||
bool is_ramdisk_file(const char *fn) {
|
||||
const char *ext1 = ".rdimg";
|
||||
const char *ext2 = ".rdvhd";
|
||||
int ext_len = 6;
|
||||
int len = strlen(fn);
|
||||
|
||||
if (len < ext_len)
|
||||
return false;
|
||||
|
||||
const char *extp = fn + (len - ext_len);
|
||||
return (strncmp(extp, ext1, ext_len) == 0) ||
|
||||
(strncmp(extp, ext2, ext_len) == 0);
|
||||
}
|
||||
|
||||
void hdd_load_ext(hdd_file_t *hdd, const char *fn, int spt, int hpc, int tracks, int read_only) {
|
||||
int requested_read_only = read_only;
|
||||
bool is_ramdisk = is_ramdisk_file(fn);
|
||||
if (is_ramdisk)
|
||||
read_only = 1;
|
||||
|
||||
if (hdd->f == NULL) {
|
||||
/* Try to open existing hard disk image */
|
||||
if (read_only)
|
||||
@@ -17,6 +37,7 @@ void hdd_load_ext(hdd_file_t *hdd, const char *fn, int spt, int hpc, int tracks,
|
||||
hdd->f = (void *)fopen64(fn, "rb+");
|
||||
if (hdd->f != NULL) {
|
||||
hdd->img_type = HDD_IMG_RAW;
|
||||
|
||||
/* Check if the file we opened is a VHD */
|
||||
if (mvhd_file_is_vhd((FILE *)hdd->f)) {
|
||||
int err;
|
||||
@@ -72,6 +93,58 @@ void hdd_load_ext(hdd_file_t *hdd, const char *fn, int spt, int hpc, int tracks,
|
||||
}
|
||||
hdd->sectors = hdd->spt * hdd->hpc * hdd->tracks;
|
||||
hdd->read_only = read_only;
|
||||
|
||||
if (is_ramdisk) {
|
||||
ramdisk_t *ramdisk = ramdisk_init();
|
||||
if (ramdisk == NULL) {
|
||||
pclog("Cannot initialize ramdisk '%s' : %s", fn, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare ramdisk buffer to have enough space for whole raw image
|
||||
size_t size = hdd->sectors * 512 + 1;
|
||||
if (ramdisk_set_size(ramdisk, size) < 0) {
|
||||
ramdisk_free(ramdisk);
|
||||
pclog("Cannot set ramdisk '%s' size to %d: %s", fn, size, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdd->img_type == HDD_IMG_RAW) {
|
||||
if (ramdisk_load_file(ramdisk, (FILE *)hdd->f) < 0) {
|
||||
pclog("Cannot load ramdisk from file '%s' : %s", fn, strerror(errno));
|
||||
ramdisk_free(ramdisk);
|
||||
return;
|
||||
}
|
||||
fclose((FILE *)hdd->f);
|
||||
} else if (hdd->img_type == HDD_IMG_VHD) {
|
||||
char *rd_buf;
|
||||
size_t rd_buf_size;
|
||||
|
||||
// get temporary buffer from beginning of disk (cursor is at 0)
|
||||
if (ramdisk_get_cursor_mem(ramdisk, &rd_buf, &rd_buf_size) < 0) {
|
||||
pclog("Unable to get ramdisk cursor memory pointer '%s'", fn);
|
||||
ramdisk_free(ramdisk);
|
||||
return;
|
||||
}
|
||||
|
||||
// immediately read all sectors from VHD to our raw ramdisk memory
|
||||
if (mvhd_read_sectors((MVHDMeta *)hdd->f, 0, hdd->sectors, rd_buf) < 0) {
|
||||
pclog("Unable to read VHD image sectors to ramdisk '%s'", fn);
|
||||
ramdisk_free(ramdisk);
|
||||
return;
|
||||
}
|
||||
mvhd_close((MVHDMeta *)hdd->f);
|
||||
} else {
|
||||
pclog("Unsupported HDD image type for ramdisk '%s'", fn);
|
||||
ramdisk_free(ramdisk);
|
||||
return;
|
||||
}
|
||||
|
||||
hdd->f = (void *)ramdisk;
|
||||
hdd->img_type = HDD_IMG_RAW_RAM;
|
||||
hdd->read_only = requested_read_only;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void hdd_load(hdd_file_t *hdd, int d, const char *fn) { hdd_load_ext(hdd, fn, hdc[d].spt, hdc[d].hpc, hdc[d].tracks, 0); }
|
||||
@@ -82,6 +155,8 @@ void hdd_close(hdd_file_t *hdd) {
|
||||
mvhd_close((MVHDMeta *)hdd->f);
|
||||
else if (hdd->img_type == HDD_IMG_RAW)
|
||||
fclose((FILE *)hdd->f);
|
||||
else if (hdd->img_type == HDD_IMG_RAW_RAM)
|
||||
ramdisk_free((ramdisk_t *)hdd->f);
|
||||
}
|
||||
hdd->img_type = HDD_IMG_RAW;
|
||||
hdd->f = NULL;
|
||||
@@ -90,7 +165,8 @@ void hdd_close(hdd_file_t *hdd) {
|
||||
int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer) {
|
||||
if (hdd->img_type == HDD_IMG_VHD) {
|
||||
return mvhd_read_sectors((MVHDMeta *)hdd->f, offset, nr_sectors, buffer);
|
||||
} else if (hdd->img_type == HDD_IMG_RAW) {
|
||||
} else if (hdd->img_type == HDD_IMG_RAW ||
|
||||
hdd->img_type == HDD_IMG_RAW_RAM) {
|
||||
off64_t addr;
|
||||
int transfer_sectors = nr_sectors;
|
||||
|
||||
@@ -98,8 +174,15 @@ int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
|
||||
transfer_sectors = hdd->sectors - offset;
|
||||
addr = (uint64_t)offset * 512;
|
||||
|
||||
if (hdd->img_type == HDD_IMG_RAW) {
|
||||
fseeko64((FILE *)hdd->f, addr, SEEK_SET);
|
||||
fread(buffer, transfer_sectors * 512, 1, (FILE *)hdd->f);
|
||||
} else if (hdd->img_type == HDD_IMG_RAW_RAM) {
|
||||
ramdisk_t *ramdisk = (ramdisk_t *)hdd->f;
|
||||
ramdisk_seek(ramdisk, addr, SEEK_SET);
|
||||
ramdisk_read(ramdisk, buffer, transfer_sectors * 512);
|
||||
} else
|
||||
return 1;
|
||||
|
||||
if (nr_sectors != transfer_sectors)
|
||||
return 1;
|
||||
@@ -112,7 +195,8 @@ int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
|
||||
int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer) {
|
||||
if (hdd->img_type == HDD_IMG_VHD) {
|
||||
return mvhd_write_sectors((MVHDMeta *)hdd->f, offset, nr_sectors, buffer);
|
||||
} else if (hdd->img_type == HDD_IMG_RAW) {
|
||||
} else if (hdd->img_type == HDD_IMG_RAW ||
|
||||
hdd->img_type == HDD_IMG_RAW_RAM) {
|
||||
off64_t addr;
|
||||
int transfer_sectors = nr_sectors;
|
||||
|
||||
@@ -123,8 +207,15 @@ int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
|
||||
transfer_sectors = hdd->sectors - offset;
|
||||
addr = (uint64_t)offset * 512;
|
||||
|
||||
if (hdd->img_type == HDD_IMG_RAW) {
|
||||
fseeko64((FILE *)hdd->f, addr, SEEK_SET);
|
||||
fwrite(buffer, transfer_sectors * 512, 1, (FILE *)hdd->f);
|
||||
} else if (hdd->img_type == HDD_IMG_RAW_RAM) {
|
||||
ramdisk_t *ramdisk = (ramdisk_t *)hdd->f;
|
||||
ramdisk_seek(ramdisk, addr, SEEK_SET);
|
||||
ramdisk_write(ramdisk, buffer, transfer_sectors * 512);
|
||||
} else
|
||||
return 1;
|
||||
|
||||
if (nr_sectors != transfer_sectors)
|
||||
return 1;
|
||||
@@ -137,7 +228,8 @@ int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
|
||||
int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors) {
|
||||
if (hdd->img_type == HDD_IMG_VHD) {
|
||||
return mvhd_format_sectors((MVHDMeta *)hdd->f, offset, nr_sectors);
|
||||
} else if (hdd->img_type == HDD_IMG_RAW) {
|
||||
} else if (hdd->img_type == HDD_IMG_RAW ||
|
||||
hdd->img_type == HDD_IMG_RAW_RAM) {
|
||||
off64_t addr;
|
||||
int c;
|
||||
uint8_t zero_buffer[512];
|
||||
@@ -151,9 +243,18 @@ int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors) {
|
||||
if ((hdd->sectors - offset) < transfer_sectors)
|
||||
transfer_sectors = hdd->sectors - offset;
|
||||
addr = (uint64_t)offset * 512;
|
||||
|
||||
if (hdd->img_type == HDD_IMG_RAW) {
|
||||
fseeko64((FILE *)hdd->f, addr, SEEK_SET);
|
||||
for (c = 0; c < transfer_sectors; c++)
|
||||
fwrite(zero_buffer, 512, 1, (FILE *)hdd->f);
|
||||
} else if (hdd->img_type == HDD_IMG_RAW_RAM) {
|
||||
ramdisk_t *ramdisk = (ramdisk_t *)hdd->f;
|
||||
ramdisk_seek(ramdisk, addr, SEEK_SET);
|
||||
for (c = 0; c < transfer_sectors; c++)
|
||||
ramdisk_write(ramdisk, zero_buffer, 512);
|
||||
} else
|
||||
return 1;
|
||||
|
||||
if (nr_sectors != transfer_sectors)
|
||||
return 1;
|
||||
|
273
src/hdd/ramdisk/ramdisk.c
Normal file
273
src/hdd/ramdisk/ramdisk.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Growable RAM disk memory stream for PCem by MMaster (2024)
|
||||
* Inspired by fmem https://github.com/Snaipe/fmem
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define KB_SIZE * 1024
|
||||
#define MB_SIZE * (1024 KB_SIZE)
|
||||
#define GB_SIZE * (1024 MB_SIZE)
|
||||
|
||||
// Max: 2 GB - 1B regardless of 32 / 64 bit
|
||||
#define MAX_STREAM_SIZE (-1 + 1 GB_SIZE + 1 GB_SIZE)
|
||||
|
||||
/* Stream section */
|
||||
typedef struct ramdisk_stream {
|
||||
uint8_t *mem;
|
||||
size_t _size; // internal allocation size
|
||||
size_t size; // expected size
|
||||
size_t cursor;
|
||||
} ramdisk_stream_t;
|
||||
|
||||
ramdisk_stream_t *ramdisk_stream_init() {
|
||||
ramdisk_stream_t *stream = (ramdisk_stream_t *)malloc(sizeof(ramdisk_stream_t));
|
||||
if (stream == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
|
||||
stream->_size = 4 KB_SIZE;
|
||||
stream->mem = (uint8_t *)malloc(stream->_size);
|
||||
if (stream->mem == NULL) {
|
||||
free(stream);
|
||||
return NULL;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
void ramdisk_stream_free(ramdisk_stream_t *stream) {
|
||||
free(stream->mem);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
size_t golden_growth_ceil(size_t n)
|
||||
{
|
||||
/* This effectively is a return ceil(n * φ).
|
||||
φ is approximatively 207 / (2^7), so we shift our result by
|
||||
6, then perform our ceil by adding the remainder of the last division
|
||||
by 2 of the result to itself. */
|
||||
|
||||
n = (n * 207) >> 6;
|
||||
n = (n >> 1) + (n & 1);
|
||||
return n;
|
||||
}
|
||||
|
||||
int ramdisk_stream_grow(ramdisk_stream_t *stream, size_t required) {
|
||||
if (stream->cursor > MAX_STREAM_SIZE - required) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
required += stream->cursor;
|
||||
|
||||
size_t newsize = stream->_size;
|
||||
if (required <= newsize)
|
||||
return 0;
|
||||
|
||||
while (required > newsize) {
|
||||
newsize = golden_growth_ceil(newsize);
|
||||
}
|
||||
|
||||
if (newsize > MAX_STREAM_SIZE)
|
||||
newsize = MAX_STREAM_SIZE;
|
||||
|
||||
uint8_t *newmem = realloc(stream->mem, newsize);
|
||||
if (newmem == NULL && newsize > required)
|
||||
newmem = realloc(stream->mem, required);
|
||||
if (newmem == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream->mem = newmem;
|
||||
stream->_size = newsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ramdisk_stream_resize(ramdisk_stream_t *stream, size_t size) {
|
||||
if (size <= stream->_size)
|
||||
return 0;
|
||||
|
||||
if (size > MAX_STREAM_SIZE) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *newmem = realloc(stream->mem, size);
|
||||
if (newmem == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream->mem = newmem;
|
||||
stream->_size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get buffer for reading (not incl. allocated space outside of current size)
|
||||
int ramdisk_stream_cursor_buf_r(ramdisk_stream_t *stream, uint8_t **buf, size_t *buf_size) {
|
||||
if (stream->size < stream->cursor)
|
||||
return -1;
|
||||
*buf_size = stream->size - stream->cursor;
|
||||
*buf = stream->mem + stream->cursor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get buffer for writing (incl. allocated space outside of current size)
|
||||
int ramdisk_stream_cursor_buf_w(ramdisk_stream_t *stream, uint8_t **buf, size_t *buf_size) {
|
||||
if (stream->_size < stream->cursor)
|
||||
return -1;
|
||||
*buf_size = stream->_size - stream->cursor;
|
||||
*buf = stream->mem + stream->cursor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ramdisk_stream_copy_buf(uint8_t *dst, size_t dst_size, const uint8_t *src, size_t src_size) {
|
||||
size_t len = src_size < dst_size ? src_size : dst_size;
|
||||
memcpy(dst, src, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Disk section */
|
||||
|
||||
typedef struct ramdisk {
|
||||
ramdisk_stream_t *stream;
|
||||
} ramdisk_t;
|
||||
|
||||
ramdisk_t *ramdisk_init() {
|
||||
ramdisk_t *ramdisk = (ramdisk_t *)malloc(sizeof(ramdisk_t));
|
||||
if (ramdisk == NULL)
|
||||
return NULL;
|
||||
|
||||
ramdisk->stream = ramdisk_stream_init();
|
||||
if (ramdisk->stream == NULL) {
|
||||
free(ramdisk);
|
||||
return NULL;
|
||||
}
|
||||
return ramdisk;
|
||||
}
|
||||
|
||||
void ramdisk_free(ramdisk_t *ramdisk) {
|
||||
ramdisk_stream_free(ramdisk->stream);
|
||||
free(ramdisk);
|
||||
}
|
||||
|
||||
int ramdisk_set_size(ramdisk_t *ramdisk, size_t size) {
|
||||
if (size > ramdisk->stream->_size) {
|
||||
if (ramdisk_stream_resize(ramdisk->stream, size) < 0)
|
||||
return -1;
|
||||
}
|
||||
ramdisk->stream->size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ramdisk_write(ramdisk_t *ramdisk, const char *buf, size_t size) {
|
||||
if (ramdisk->stream->cursor > MAX_STREAM_SIZE - size)
|
||||
size = MAX_STREAM_SIZE - ramdisk->stream->cursor;
|
||||
|
||||
char *dst_buf;
|
||||
size_t dst_buf_size;
|
||||
if (ramdisk_stream_grow(ramdisk->stream, size) < 0)
|
||||
return -1;
|
||||
|
||||
if (ramdisk_stream_cursor_buf_w(ramdisk->stream, (uint8_t **)&dst_buf, &dst_buf_size) < 0)
|
||||
return 0;
|
||||
|
||||
size_t written = ramdisk_stream_copy_buf(dst_buf, dst_buf_size, buf, size);
|
||||
if (written > INT_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
ramdisk->stream->cursor += written;
|
||||
|
||||
// if it was written beyond current 'end of file' move the EOF
|
||||
if (ramdisk->stream->size < ramdisk->stream->cursor)
|
||||
ramdisk->stream->size = ramdisk->stream->cursor;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
int ramdisk_read(ramdisk_t *ramdisk, char *buf, size_t size) {
|
||||
if (ramdisk->stream->cursor > MAX_STREAM_SIZE - size)
|
||||
size = MAX_STREAM_SIZE - ramdisk->stream->cursor;
|
||||
|
||||
// end of file at MAX_STREAM_SIZE
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
char *src_buf;
|
||||
size_t src_buf_size;
|
||||
size_t written = 0;
|
||||
if (ramdisk_stream_cursor_buf_r(ramdisk->stream, (uint8_t **)&src_buf, &src_buf_size) == 0) {
|
||||
if (src_buf_size == 0)
|
||||
return 0; // eof
|
||||
|
||||
written = ramdisk_stream_copy_buf(buf, size, src_buf, src_buf_size);
|
||||
}
|
||||
|
||||
if (written > INT_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ramdisk->stream->cursor += written;
|
||||
return written;
|
||||
}
|
||||
|
||||
int ramdisk_seek(ramdisk_t *ramdisk, off_t offset, int whence) {
|
||||
size_t new_offset;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
new_offset = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
new_offset = ramdisk->stream->cursor + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
new_offset = ramdisk->stream->size + offset;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (new_offset < 0 || new_offset > MAX_STREAM_SIZE) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ramdisk->stream->cursor = new_offset;
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
int ramdisk_get_cursor_mem(ramdisk_t *ramdisk, char **mem, size_t *size) {
|
||||
return ramdisk_stream_cursor_buf_w(ramdisk->stream, (uint8_t **)mem, size);
|
||||
}
|
||||
|
||||
int ramdisk_load_file(ramdisk_t *ramdisk, FILE *fp) {
|
||||
// get file size
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if (ramdisk_stream_resize(ramdisk->stream, size) < 0)
|
||||
return -1;
|
||||
|
||||
ramdisk_seek(ramdisk, 0, SEEK_SET);
|
||||
|
||||
char *buf;
|
||||
size_t buf_size;
|
||||
if (ramdisk_stream_cursor_buf_w(ramdisk->stream, (uint8_t **)&buf, &buf_size) < 0)
|
||||
return -1;
|
||||
|
||||
size_t len = fread(buf, 1, buf_size, fp);
|
||||
if (len > 0)
|
||||
ramdisk->stream->size = ramdisk->stream->cursor + len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@@ -2036,7 +2036,7 @@ static int hd_new(void *hdlg, int drive) {
|
||||
}
|
||||
|
||||
static int hd_file(void *hdlg, int drive) {
|
||||
if (!getfile(hdlg, "Hard disc image (*.img;*.vhd)|*.img;*.vhd|All files (*.*)|*.*", "")) {
|
||||
if (!getfile(hdlg, "Hard disk image (*.img;*.vhd)|*.img;*.vhd|RAM disk image (*.rdimg;*.rdvhd)|*.rdimg;*.rdvhd|All files (*.*)|*.*", "")) {
|
||||
off_t sz;
|
||||
FILE *f = fopen64(openfilestring, "rb");
|
||||
if (!f) {
|
||||
|
Reference in New Issue
Block a user