Skip to content

Commit

Permalink
io: add pread/pwrite
Browse files Browse the repository at this point in the history
this also probably fixed a race bug I introduced in thdat105 while
trying to fix the other race bug
  • Loading branch information
DankRank committed Oct 2, 2023
1 parent 1f6fc07 commit 4e31979
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 37 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ check_symbol_exists("chdir" "unistd.h" HAVE_CHDIR)
if(NOT HAVE_CHDIR)
check_symbol_exists("_chdir" "direct.h" HAVE__CHDIR)
endif()
check_symbol_exists("pread" "unistd.h" HAVE_PREAD)

check_symbol_exists("getc_unlocked" "stdio.h" HAVE_GETC_UNLOCKED)
if(HAVE_GETC_UNLOCKED)
Expand Down
1 change: 1 addition & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef SSIZE_T ssize_t;
#cmakedefine HAVE_FILENO
#cmakedefine HAVE_CHDIR
#cmakedefine HAVE__CHDIR
#cmakedefine HAVE_PREAD

#cmakedefine HAVE_GETC_UNLOCKED
#cmakedefine HAVE_FREAD_UNLOCKED
Expand Down
214 changes: 196 additions & 18 deletions thtk/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
#include <string.h>
#include <stddef.h>
#include <thtk/io.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif

struct thtk_io_vtable {
ssize_t (*read)(thtk_io_t *io, void *buf, size_t count, thtk_error_t **error);
Expand All @@ -41,6 +47,8 @@ struct thtk_io_vtable {
unsigned char *(*map)(thtk_io_t *io, off_t offset, size_t count, thtk_error_t **error);
void (*unmap)(thtk_io_t *io, unsigned char *map);
int (*close)(thtk_io_t *io);
ssize_t (*pread)(thtk_io_t *io, void *buf, size_t count, off_t offset, thtk_error_t **error);
ssize_t (*pwrite)(thtk_io_t *io, const void *buf, size_t count, off_t offset, thtk_error_t **error);
};

struct thtk_io_t {
Expand All @@ -60,6 +68,8 @@ thtk_io_read(
return -1;
}
ret = io->v->read(io, buf, count, error);
if (ret == -1)
return -1;
if (ret != (ssize_t)count) {
thtk_error_new(error, "short read");
return -1;
Expand All @@ -80,6 +90,8 @@ thtk_io_write(
return -1;
}
ret = io->v->write(io, buf, count, error);
if (ret == -1)
return -1;
if (ret != (ssize_t)count) {
thtk_error_new(error, "short write");
return -1;
Expand Down Expand Up @@ -139,6 +151,80 @@ thtk_io_close(
return ret;
}

ssize_t
thtk_io_pread(
thtk_io_t *io,
void *buf,
size_t count,
off_t offset,
thtk_error_t **error)
{
ssize_t ret;
if (!io || !buf || !count) {
thtk_error_new(error, "invalid parameter passed");
return -1;
}
if (io->v->pread) {
ret = io->v->pread(io, buf, count, offset, error);
} else {
#pragma omp critical
{
off_t old;
ret = -1;
if ((old = thtk_io_seek(io, 0, SEEK_CUR, error)) != -1)
if (thtk_io_seek(io, offset, SEEK_SET, error) != -1) {
ret = thtk_io_read(io, buf, count, error);
if (thtk_io_seek(io, old, SEEK_SET, error) == -1)
ret = -1;
}
}
}
if (ret == -1)
return -1;
if (ret != (ssize_t)count) {
thtk_error_new(error, "short read");
return -1;
}
return ret;
}

ssize_t
thtk_io_pwrite(
thtk_io_t *io,
const void *buf,
size_t count,
off_t offset,
thtk_error_t **error)
{
ssize_t ret;
if (!io || !buf || !count) {
thtk_error_new(error, "invalid parameter passed");
return -1;
}
if (io->v->pwrite) {
ret = io->v->pwrite(io, buf, count, offset, error);
} else {
#pragma omp critical
{
off_t old;
ret = -1;
if ((old = thtk_io_seek(io, 0, SEEK_CUR, error)) != -1)
if (thtk_io_seek(io, offset, SEEK_SET, error) != -1) {
ret = thtk_io_write(io, buf, count, error);
if (thtk_io_seek(io, old, SEEK_SET, error) == -1)
ret = -1;
}
}
}
if (ret == -1)
return -1;
if (ret != (ssize_t)count) {
thtk_error_new(error, "short write");
return -1;
}
return ret;
}

struct thtk_io_file {
thtk_io_t io;
FILE *stream;
Expand Down Expand Up @@ -227,14 +313,106 @@ thtk_io_file_close(
return fclose(private->stream) == 0;
}

#if defined(HAVE_PREAD)
static ssize_t
thtk_io_file_pread(
thtk_io_t *io,
void *buf,
size_t count,
off_t offset,
thtk_error_t **error)
{
struct thtk_io_file *private = (void *)io;
ssize_t ret = pread(fileno(private->stream), buf, count, offset);
if (ret == -1) {
thtk_error_new(error, "error while reading: %s", strerror(errno));
return -1;
}
return ret;
}

static ssize_t
thtk_io_file_pwrite(
thtk_io_t *io,
const void *buf,
size_t count,
off_t offset,
thtk_error_t **error)
{
struct thtk_io_file *private = (void *)io;
ssize_t ret = pwrite(fileno(private->stream), buf, count, offset);
if (ret == -1) {
thtk_error_new(error, "error while writing: %s", strerror(errno));
return -1;
}
return ret;
}
#elif defined(_WIN32)
static ssize_t
thtk_io_file_pread(
thtk_io_t *io,
void *buf,
size_t count,
off_t offset,
thtk_error_t **error)
{
struct thtk_io_file *private = (void *)io;
OVERLAPPED ovl;
memset(&ovl, 0, sizeof(ovl));
ovl.Offset = offset; /* TODO: OffsetHigh */
DWORD nread;
BOOL ret = ReadFile((HANDLE)_get_osfhandle(fileno(private->stream)), buf, count, &nread, &ovl);
if (!ret) {
char *buf;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
thtk_error_new(error, "error while reading: %s", buf ? buf : "(null)");
LocalFree(buf);
return -1;
}
return nread;
}

static ssize_t
thtk_io_file_pwrite(
thtk_io_t *io,
const void *buf,
size_t count,
off_t offset,
thtk_error_t **error)
{
struct thtk_io_file *private = (void *)io;
OVERLAPPED ovl;
memset(&ovl, 0, sizeof(ovl));
ovl.Offset = offset; /* TODO: OffsetHigh */
DWORD nwritten;
BOOL ret = WriteFile((HANDLE)_get_osfhandle(fileno(private->stream)), buf, count, &nwritten, &ovl);
if (!ret) {
char *buf;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
thtk_error_new(error, "error while writing: %s", buf ? buf : "(null)");
LocalFree(buf);
return -1;
}
return nwritten;
}
#endif

static const struct thtk_io_vtable
thtk_io_file_vtable = {
thtk_io_file_read,
thtk_io_file_write,
thtk_io_file_seek,
thtk_io_file_map,
thtk_io_file_unmap,
thtk_io_file_close,
.read = thtk_io_file_read,
.write = thtk_io_file_write,
.seek = thtk_io_file_seek,
.map = thtk_io_file_map,
.unmap = thtk_io_file_unmap,
.close = thtk_io_file_close,
#if defined(HAVE_PREAD) || defined(_WIN32)
.pread = thtk_io_file_pread,
.pwrite = thtk_io_file_pwrite,
#endif
};

thtk_io_t*
Expand Down Expand Up @@ -390,12 +568,12 @@ thtk_io_memory_close(

static const struct thtk_io_vtable
thtk_io_memory_vtable = {
thtk_io_memory_read,
thtk_io_memory_write,
thtk_io_memory_seek,
thtk_io_memory_map,
thtk_io_noop_unmap,
thtk_io_memory_close,
.read = thtk_io_memory_read,
.write = thtk_io_memory_write,
.seek = thtk_io_memory_seek,
.map = thtk_io_memory_map,
.unmap = thtk_io_noop_unmap,
.close = thtk_io_memory_close,
};

thtk_io_t*
Expand Down Expand Up @@ -530,12 +708,12 @@ thtk_io_growing_memory_close(

static const struct thtk_io_vtable
thtk_io_growing_memory_vtable = {
thtk_io_growing_memory_read,
thtk_io_growing_memory_write,
thtk_io_growing_memory_seek,
thtk_io_growing_memory_map,
thtk_io_noop_unmap,
thtk_io_growing_memory_close,
.read = thtk_io_growing_memory_read,
.write = thtk_io_growing_memory_write,
.seek = thtk_io_growing_memory_seek,
.map = thtk_io_growing_memory_map,
.unmap = thtk_io_noop_unmap,
.close = thtk_io_growing_memory_close,
};

thtk_io_t*
Expand Down
6 changes: 6 additions & 0 deletions thtk/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ THTK_EXPORT unsigned char* thtk_io_map(thtk_io_t* io, off_t offset, size_t count
THTK_EXPORT void thtk_io_unmap(thtk_io_t* io, unsigned char* map);
/* Closes and frees the IO object. Returns 0 on error, otherwise 1. */
THTK_EXPORT int thtk_io_close(thtk_io_t* io);
/* See the documentation for pread(2). Returns the number of bytes read, or -1
* on error. */
THTK_EXPORT ssize_t thtk_io_pread(thtk_io_t* io, void* buf, size_t count, off_t offset, thtk_error_t** error);
/* See the documentation for pwrite(2). Returns the number of bytes written, or
* -1 on error. */
THTK_EXPORT ssize_t thtk_io_pwrite(thtk_io_t* io, const void* buf, size_t count, off_t offset, thtk_error_t** error);

/* Opens a file in the mode specified, the mode works as it does for fopen. */
THTK_EXPORT thtk_io_t* thtk_io_open_file(const char* path, const char* mode, thtk_error_t** error);
Expand Down
34 changes: 15 additions & 19 deletions thtk/thdat105.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,17 @@ th105_read(
thdat_entry_t *entry = &thdat->entries[entry_index];
uint8_t *data = malloc(entry->size);

int failed = 0;
#pragma omp critical
{
failed = (thtk_io_seek(thdat->stream, entry->offset, SEEK_SET, error) == -1) ||
(thtk_io_read(thdat->stream, data, entry->size, error) != entry->size);
}

if (failed)
if (thtk_io_pread(thdat->stream, data, entry->size, entry->offset, error) == -1) {
free(data);
return -1;
}

th105_data_crypt(thdat, entry, data);

if (thtk_io_write(output, data, entry->size, error) == -1)
if (thtk_io_write(output, data, entry->size, error) == -1) {
free(data);
return -1;
}

free(data);
return 1;
Expand Down Expand Up @@ -237,11 +234,15 @@ th105_write(
entry->size = input_length;
uint8_t *data = malloc(entry->size);

if (thtk_io_seek(input, 0, SEEK_SET, error) == -1)
if (thtk_io_seek(input, 0, SEEK_SET, error) == -1) {
free(data);
return -1;
}
int ret = thtk_io_read(input, data, entry->size, error);
if (ret != entry->size)
if (ret != entry->size) {
free(data);
return -1;
}

#pragma omp critical
{
Expand All @@ -251,17 +252,12 @@ th105_write(

th105_data_crypt(thdat, entry, data);

int failed = 0;
#pragma omp critical
{
failed = (thtk_io_write(thdat->stream, data, entry->size, error) != entry->size);
if (thtk_io_pwrite(thdat->stream, data, entry->size, entry->offset, error) == -1) {
free(data);
return -1;
}

free(data);

if (failed)
return -1;

return entry->size;
}

Expand Down

0 comments on commit 4e31979

Please sign in to comment.