Implemented UMDiff read/write

This commit is contained in:
TheSola10 2025-04-05 19:19:42 +02:00
parent 78e8bcc861
commit 557f11ff93
Signed by: thesola10
GPG Key ID: 89245619BEBB95BA
8 changed files with 228 additions and 10 deletions

View File

@ -1,5 +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
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

33
stdio_glue.c Normal file
View File

@ -0,0 +1,33 @@
/**
* @file stdio_glue.c
* @author Karim Vergnes <me@thesola.io>
* @copyright GPLv2
* @brief Glue code between POSIX stdio and PSP kernel
*
* This module allows me to reuse code from the UMDiff utility, by redirecting
* POSIX standard I/O functions to their PSP kernel counterparts.
* Probably won't work for more complex programs.
*/
#include <unistd.h>
#include <pspkernel.h>
off_t
lseek(int fd, off_t offset, int whence)
{
return sceIoLseek(fd, offset, whence);
}
int
read(int fd, void *buf, size_t count)
{
return sceIoRead(fd, buf, count);
}
int
write(int fd, const void *buf, size_t count)
{
return sceIoWrite(fd, buf, count);
}
// vim: ft=c.doxygen

85
umdiff/file.c Normal file
View File

@ -0,0 +1,85 @@
/**
* @file file.c
* @author Karim Vergnes <me@thesola.io>
* @copyright GPLv2
* @brief Functions to read and write UMDiff files
*
* The functions defined here control reading and writing UMDiff files from
* in-memory structure @ref umdiff_File.
*/
#include "umdiff.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
typedef union {
char data[sizeof(umdiff_Header)];
umdiff_Header hdr;
} _impl_umdiff_RawHeader;
#define _impl_umdiff_alignSector$(x) \
( x + ISO_SECTOR_SIZE - (x % ISO_SECTOR_SIZE) )
void
_impl_umdiff_Header_rectify(umdiff_Header *hdr)
{
long len_preamble = sizeof(umdiff_Header)
+ (sizeof(umdiff_Command) * hdr->cmd_count);
strncpy(hdr->magic, umdiff_File_$MAGIC, 7);
hdr->version = umdiff_File_$VERSION;
hdr->data_start = _impl_umdiff_alignSector$(len_preamble);
}
int
umdiff_File_load(umdiff_File *file, int fd, umdiff_FileFlags flags)
{
_impl_umdiff_RawHeader rheader;
int ret;
if (!file) return 1;
ret = read(fd, &rheader.data, sizeof(umdiff_Header));
file->hdr = rheader.hdr;
if (strncmp(file->hdr.magic, umdiff_File_$MAGIC, 7))
return 1;
if (file->hdr.version != umdiff_File_$VERSION)
return 1;
if (flags >= umdiff_FileFlags_HEADER_AND_COMMANDS) {
ret = read(fd, file->commands, sizeof(umdiff_Command) * file->hdr.cmd_count);
}
if (flags == umdiff_FileFlags_LOAD_FULL) {
file->data_len = lseek(fd, 0, SEEK_END) - file->hdr.data_start;
ret = lseek(fd, file->hdr.data_start, SEEK_SET);
ret = read(fd, file->data, file->data_len);
}
return 0;
}
int
umdiff_File_write(umdiff_File *file, int outfd)
{
_impl_umdiff_RawHeader rheader;
int ret;
if (!file || file->mode != umdiff_FileFlags_LOAD_FULL
|| !file->commands || !file->data
|| !file->hdr.cmd_count || !file->hdr.index[0])
return 1;
rheader.hdr = file->hdr;
_impl_umdiff_Header_rectify(&rheader.hdr);
ret = write(outfd, rheader.data, sizeof(umdiff_Header));
ret = write(outfd, file->commands, sizeof(umdiff_Command) * rheader.hdr.cmd_count);
ret = lseek(outfd, rheader.hdr.data_start, SEEK_SET);
ret = write(outfd, file->data, file->data_len);
return 0;
}

View File

@ -9,11 +9,25 @@
* in the umd_livepatch module. * in the umd_livepatch module.
*/ */
#include <fcntl.h>
#include "usage.rl.h" #include "usage.rl.h"
#include "rdiff.h"
int int
umdiff_delta(char *source, char *target, char *output) umdiff_delta(char *source, char *target, char *output)
{ {
int source_fd, target_fd, output_fd;
umdiff_File *result;
source_fd = open(source, O_RDONLY);
target_fd = open(target, O_RDONLY);
result = umdiff_File_fromCompare(source_fd, target_fd);
output_fd = open(output, O_WRONLY|O_CREAT|O_TRUNC);
umdiff_File_write(result, output_fd);
return 1; return 1;
} }

0
umdiff/patch.c Normal file
View File

View File

@ -8,12 +8,10 @@
* and convert it in-memory into the UMDiff format. * and convert it in-memory into the UMDiff format.
*/ */
#include "umdiff.h" #include "rdiff.h"
#include <librsync.h> #include <librsync.h>
#define ISO_SECTOR_SIZE 2048
typedef union { typedef union {
int fd; int fd;
void *opaque; void *opaque;

29
umdiff/rdiff.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __RDIFF_H
#define __RDIFF_H
/**
* @file rdiff.h
* @author Karim Vergnes <me@thesola.io>
* @copyright GPLv2
* @brief rsync-based diff calculator functions
*
* Generator functions to create a @ref umdiff_File object from computing the
* difference between two files, using librsync algorithms.
*/
#include "umdiff.h"
/**
* @brief Generate a UMDiff file from a source and target file contents.
*
* This function invokes a signature and delta job from librsync under the hood.
* This is the optimum approach, as it includes our optimum parameters,
* ensuring computed blocks line up with ISO9660 sectors.
*/
umdiff_File *
umdiff_File_fromCompare(int source_fd, int target_fd);
#endif //__RDIFF_H
// vim: ft=c.doxygen

View File

@ -10,7 +10,15 @@
* This file contains all required types to read and parse a UMDiff file. * This file contains all required types to read and parse a UMDiff file.
*/ */
#define UMDIFF_VERSION 0x00 #ifndef ISO_SECTOR_SIZE
# define ISO_SECTOR_SIZE 2048
#endif
#define umdiff_File_$MAGIC "\x7fUMDiff"
#define umdiff_File_$VERSION 0x00
// Commands shall start immediately after the full header
#define umdiff_File_$COMMANDS_START (sizeof lp_UMDiffHeader)
/** /**
* @brief Index of commands at 1024 sector interval. * @brief Index of commands at 1024 sector interval.
@ -42,7 +50,7 @@ typedef struct
__attribute__((packed)) { __attribute__((packed)) {
char magic[7]; /* = 0x7f 'UMDiff' */ char magic[7]; /* = 0x7f 'UMDiff' */
char version; char version;
long cmd_len; long cmd_count;
long data_start; long data_start;
umdiff_CmdIndex index; umdiff_CmdIndex index;
} umdiff_Header; } umdiff_Header;
@ -58,7 +66,7 @@ __attribute__((packed)) {
* - <tt>sector_count</tt>: How many sectors on the original disc the patch * - <tt>sector_count</tt>: How many sectors on the original disc the patch
* command spans. * command spans.
* - <tt>patch_start</tt>: Where in the patch source the substitute data is * - <tt>patch_start</tt>: Where in the patch source the substitute data is
* found, in sectors. * found, in sectors (past @ref data_start for in-file patches).
* - <tt>patch_sector_count</tt>: How many sectors on the patch source the * - <tt>patch_sector_count</tt>: How many sectors on the patch source the
* substitute data occupies. If smaller than <tt>sector_count</tt>, then * substitute data occupies. If smaller than <tt>sector_count</tt>, then
* the substitute is a repeating pattern of that length. * the substitute is a repeating pattern of that length.
@ -75,14 +83,64 @@ typedef struct {
long data_source; /* 0 = patchfile, 1 = source */ long data_source; /* 0 = patchfile, 1 = source */
} umdiff_Command; } umdiff_Command;
// Commands shall start immediately after the full header /**
#define UMDIFF_COMMANDS_START (sizeof lp_UMDiffHeader) * @brief Flags to control loading a UMDiff file.
*
* In order to adapt to memory-constrained environments, one can choose to
* not load certain parts of a UMDiff file, instead resorting to in-situ reads.
*/
typedef enum {
umdiff_FileFlags_HEADER_ONLY,
umdiff_FileFlags_HEADER_AND_COMMANDS,
umdiff_FileFlags_LOAD_FULL
} umdiff_FileFlags;
/**
* @brief In-memory structure for a UMDiff file.
*
* 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.
*
* @see umdiff_FileFlags for the possible cases.
*/
typedef struct { typedef struct {
umdiff_Header *hdr; umdiff_Header hdr;
umdiff_Command *commands; umdiff_Command *commands;
long data_len;
char *data;
umdiff_FileFlags mode;
} umdiff_File; } umdiff_File;
/**
* @brief Load a UMDiff file from an open file descriptor.
*
* This function takes a pre-allocated @ref umdiff_File structure, and populates
* it from an open file descriptor, according to the given mode flags.
*
* @param file The target @ref umdiff_File to load into.
* @param fd The open file descriptor to read from.
* @param flags Flags to control how much data to read in memory.
*
* @return 0 on success, any other value indicates an error.
*/
int
umdiff_File_load(umdiff_File *file, int fd, umdiff_FileFlags flags);
/**
* @brief Write a fully-populated UMDiff into a file descriptor.
*
* This function takes a fully populated @ref umdiff_File structure, and writes
* it down into an open file descriptor. The output header will be set with
* correct values, only cmd_len and index must both be set.
*
* @param file The @ref umdiff_File to write from. Must be fully populated.
* @param outfd The open file descriptor to write into.
*
* @return 0 on success, any other value indicates an error.
*/
int
umdiff_File_write(umdiff_File *file, int outfd);
#endif //__UMDIFF_H #endif //__UMDIFF_H
// vim: ft=c.doxygen // vim: ft=c.doxygen