Implementing patch algorithm

This commit is contained in:
TheSola10 2025-04-05 23:13:24 +02:00
parent d4fa58acfe
commit 8f3dd9c61b
Signed by: thesola10
GPG Key ID: 89245619BEBB95BA
6 changed files with 148 additions and 6 deletions

View File

@ -1,6 +1,6 @@
TARGET = umd_livepatch TARGET = umd_livepatch
C_OBJS = patch.o io_funcs.o main.o \ C_OBJS = patch.o io_funcs.o main.o \
stdio_glue.o umdiff/file.o stdio_glue.o umdiff/file.o umdiff/patch.o
OBJS = $(C_OBJS) imports.o OBJS = $(C_OBJS) imports.o
all: $(TARGET).prx all: $(TARGET).prx
INCDIR = $(ARKROOT)/common/include $(ARKROOT)/core/systemctrl/include $(LIBRSYNC)/src INCDIR = $(ARKROOT)/common/include $(ARKROOT)/core/systemctrl/include $(LIBRSYNC)/src

View File

@ -1,5 +1,5 @@
TARGET = umdiff TARGET = umdiff
C_OBJS = main.c.o compare.c.o file.c.o patch.c.o C_OBJS = main.c.o rdiff.c.o compare.c.o file.c.o patch.c.o
OBJS = $(C_OBJS) OBJS = $(C_OBJS)
CMAKE := cmake CMAKE := cmake

View File

@ -6,6 +6,8 @@
* *
* The functions defined here control reading and writing UMDiff files from * The functions defined here control reading and writing UMDiff files from
* in-memory structure @ref umdiff_File. * in-memory structure @ref umdiff_File.
*
* @warning This file is reused by umd_livepatch. Do not allocate on the heap!
*/ */
#include "umdiff.h" #include "umdiff.h"
@ -28,7 +30,7 @@ _impl_umdiff_Header_rectify(umdiff_Header *hdr)
long len_preamble = sizeof(umdiff_Header) long len_preamble = sizeof(umdiff_Header)
+ (sizeof(umdiff_Command) * hdr->cmd_count); + (sizeof(umdiff_Command) * hdr->cmd_count);
strncpy(hdr->magic, umdiff_File_$MAGIC, 7); memcpy(hdr->magic, umdiff_File_$MAGIC, 7);
hdr->version = umdiff_File_$VERSION; hdr->version = umdiff_File_$VERSION;
hdr->data_start = _impl_umdiff_alignSector$(len_preamble); hdr->data_start = _impl_umdiff_alignSector$(len_preamble);
} }

View File

@ -0,0 +1,82 @@
/**
* @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"
static long
_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;
}
int
umdiff_File_readPatched(umdiff_File *file, void *dest, long count, long offset,
umdiff_ReadCallback read_source,
umdiff_ReadCallback read_patchFile)
{
long res;
umdiff_Command *commands;
umdiff_Command *curCommand;
#define $offset_sectors (offset / ISO_SECTOR_SIZE)
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

15
umdiff/rdiff.c Normal file
View File

@ -0,0 +1,15 @@
/**
* @file rdiff.c
* @author Karim Vergnes <me@thesola.io>
* @copyright GPLv2
* @brief rsync diff parser
*
* This file parses and converts rdiff commands into equivalent UMDiff commands
* and manages the corresponding data bucket.
*/
#include <prototab.h>
// vim: ft=c.doxygen

View File

@ -18,7 +18,7 @@
#define umdiff_File_$VERSION 0x00 #define umdiff_File_$VERSION 0x00
// Commands shall start immediately after the full header // Commands shall start immediately after the full header
#define umdiff_File_$COMMANDS_START (sizeof lp_UMDiffHeader) #define umdiff_File_$COMMANDS_START (sizeof(umdiff_Header))
/** /**
* @brief Index of commands at 1024 sector interval. * @brief Index of commands at 1024 sector interval.
@ -101,16 +101,40 @@ typedef enum {
* This struct represents the contents of a UMDiff file, loaded in memory. * This struct represents the contents of a UMDiff file, loaded in memory.
* If read from a file, only the header is guaranteed to be populated. * If read from a file, only the header is guaranteed to be populated.
* *
* If <tt>commands</tt> is set to point to a 1024-command buffer, and <tt>mode</tt>
* is set to @ref umdiff_FileFlags_HEADER_ONLY, it will be used as a holding
* buffer when reading commands from file.
*
* @see umdiff_FileFlags for the possible cases. * @see umdiff_FileFlags for the possible cases.
*/ */
typedef struct { typedef struct {
umdiff_Header hdr; umdiff_Header hdr;
/**
* @brief List of loaded commands from file
*
* If <tt>mode</tt> is set to @ref umdiff_FileFlags_HEADER_ONLY, this is
* expected to be a pre-allocated buffer holding 1024 commands.
* Otherwise, it contains all commands in the file.
*/
umdiff_Command *commands; umdiff_Command *commands;
long data_len;
char *data; char *data;
long data_len;
/** Keeps track of the last command batch pulled from index. */
int last_index;
/** Which loading mode was used when this file was opened. */
umdiff_FileFlags mode; umdiff_FileFlags mode;
} umdiff_File; } umdiff_File;
/**
* @brief Callback function to read from a source.
*
* This is used by @ref umdiff_File_readPatched to perform an actual read from
* a data source, be it the patch file or original media.
*/
typedef int (*umdiff_ReadCallback)(void *dest, long count, long offset);
/** /**
* @brief Load a UMDiff file from an open file descriptor. * @brief Load a UMDiff file from an open file descriptor.
* *
@ -141,6 +165,25 @@ umdiff_File_load(umdiff_File *file, int fd, umdiff_FileFlags flags);
int int
umdiff_File_write(umdiff_File *file, int outfd); umdiff_File_write(umdiff_File *file, int outfd);
/**
* @brief Perform a read at a given offset and size with patches applied.
*
* This function maps a given read request into the patched data, using the
* provided callback functions to carry out the actual read commands needed.
*
* @param file The @ref umdiff_File to perform the patch with.
* @param dest Like pread(2), the buffer to write the data into.
* @param count Like pread(2), the amount of data to read.
* @param offset Like pread(2), the offset at which to start reading.
*
* @param read_source The function to read the source media.
* @param read_patchFile The function to read the patch file from storage.
*/
int
umdiff_File_readPatched(umdiff_File *file, void *dest, long count, long offset,
umdiff_ReadCallback read_source,
umdiff_ReadCallback read_patchFile);
#endif //__UMDIFF_H #endif //__UMDIFF_H
// vim: ft=c.doxygen // vim: ft=c.doxygen