mirror of
https://github.com/Thesola10/umd-livepatch.git
synced 2025-04-19 22:13:22 +00:00
110 lines
3.2 KiB
C
110 lines
3.2 KiB
C
/**
|
|
* @file patch.c
|
|
* @author Karim Vergnes <me@thesola.io>
|
|
* @copyright GPLv2
|
|
* @brief UMDiff patch algorithms
|
|
*
|
|
* Functions to redirect read requests and reconstruct the result file given
|
|
* a set of UMDiff commands.
|
|
*
|
|
* @warning This file is reused by umd_livepatch. Do not allocate on the heap!
|
|
*/
|
|
|
|
#include "umdiff.h"
|
|
|
|
#include <string.h>
|
|
|
|
static umdiff_File *current_file;
|
|
|
|
static int
|
|
_impl_umdiff_Command_read(umdiff_Command cmd, void *dest, long count, long offset,
|
|
umdiff_ReadCallback read_source,
|
|
umdiff_ReadCallback read_patchFile)
|
|
{
|
|
long rel_offset = offset - (cmd.sector_start * ISO_SECTOR_SIZE);
|
|
|
|
//TODO: implement read system
|
|
// 1. perform first truncated read
|
|
// 2. if repeat-length remains, perform second full read
|
|
// 3. if repeat-length still remains, memcpy second read range onwards
|
|
// -> saved a bunch of i/o calls at the guest ptr's expense!
|
|
}
|
|
|
|
static umdiff_Command *
|
|
_impl_umdiff_File_readIndexCmds(umdiff_File *file, long offset_sector,
|
|
umdiff_ReadCallback read_patchFile)
|
|
{
|
|
int res;
|
|
int index = offset_sector / 1024;
|
|
|
|
// stateful optimization: don't re-read the same commands
|
|
if (index == file->last_index)
|
|
return 0;
|
|
|
|
if (file->mode == umdiff_FileFlags_HEADER_ONLY) {
|
|
res = read_patchFile(file->commands, sizeof(umdiff_Command) * 1024,
|
|
file->hdr.index[index]);
|
|
return file->commands;
|
|
} else {
|
|
return file->commands + file->hdr.index[index] - umdiff_File_$COMMANDS_START;
|
|
}
|
|
|
|
file->last_index = index;
|
|
}
|
|
|
|
/**
|
|
* Virtual read callback for @ref umdiff_File with @ref umdiff_FileFlags_LOAD_FULL.
|
|
*
|
|
* Automatically set by @ref umdiff_File_readPatched as needed.
|
|
*/
|
|
int
|
|
_impl_umdiff_ReadCallback_fullFile(void *dest, long count, long offset)
|
|
{
|
|
// Undo relative-to-absolute translation from _impl_umdiff_Command_read
|
|
long ds = current_file->hdr.data_start;
|
|
long real_offset = offset - ds;
|
|
|
|
memcpy(dest, current_file->data + real_offset, count);
|
|
|
|
return count;
|
|
}
|
|
|
|
int
|
|
umdiff_File_readPatched(umdiff_File *file, void *dest, long count, long offset,
|
|
umdiff_ReadCallback read_source,
|
|
umdiff_ReadCallback read_patchFile)
|
|
{
|
|
int res;
|
|
umdiff_Command *commands;
|
|
umdiff_Command *curCommand;
|
|
|
|
#define $offset_sectors (offset / ISO_SECTOR_SIZE)
|
|
|
|
current_file = file;
|
|
|
|
if (file->mode == umdiff_FileFlags_LOAD_FULL) {
|
|
read_patchFile = _impl_umdiff_ReadCallback_fullFile;
|
|
}
|
|
|
|
while (count > 0) {
|
|
commands = _impl_umdiff_File_readIndexCmds(file, $offset_sectors,
|
|
read_patchFile);
|
|
curCommand = 0;
|
|
|
|
for (int i = 0; i < 1024; i++) {
|
|
if (commands[i].sector_start <= $offset_sectors) {
|
|
curCommand = &commands[i];
|
|
break;
|
|
}
|
|
}
|
|
res = _impl_umdiff_Command_read(*curCommand, dest, count, offset,
|
|
read_source, read_patchFile);
|
|
dest += res;
|
|
count -= res;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// vim: ft=c.doxygen
|