From 6b5b44074fd6bdbbeb59f8d006fb88e0230cf1ef Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 5 Aug 2009 18:24:59 -0700 Subject: Cleaning up and sanityzing the ioctl subsystem. --- int-bios.h | 13 ------ mpq-bios.c | 144 ++++++++++++++++++++++++++++++++++++++++++++--------------- mpq-bios.h | 15 +++++-- mpq-errors.c | 2 + mpq-errors.h | 2 + mpq-file.c | 11 +++-- 6 files changed, 130 insertions(+), 57 deletions(-) delete mode 100644 int-bios.h diff --git a/int-bios.h b/int-bios.h deleted file mode 100644 index 2c1c4ee..0000000 --- a/int-bios.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __INT_BIOS_H__ -#define __INT_BIOS_H__ - -#include "mpq-bios.h" - -/* - * Internal BIOS functions. - */ - -int __mpqlib_seek(struct mpq_archive_t *, uint64_t); -int __mpqlib_read(struct mpq_archive_t *, void *, uint32_t); - -#endif diff --git a/mpq-bios.c b/mpq-bios.c index 35f657c..93c0623 100644 --- a/mpq-bios.c +++ b/mpq-bios.c @@ -21,12 +21,12 @@ #include #include #include +#include #include "mpq-crypto.h" #include "mpq-bios.h" #include "mpq-errors.h" #include "mpq-misc.h" -#include "int-bios.h" #include "errors.h" #ifndef MAX @@ -213,6 +213,12 @@ static int read_data(struct mpq_archive_t * mpq_a, void * buf, size_t l) { return 1; } +static int write_data(struct mpq_archive_t * mpq_a, const void * buf, size_t l) { + if (write(mpq_a->fd, buf, l) != l) + return 0; + return 1; +} + void mpqlib_init() { __mpqlib_init_cryptography(); } @@ -437,12 +443,12 @@ static hash_t * mpqlib_locate_hash_entry(struct mpq_archive_t * mpq_a, uint32_t return NULL; } -static hash_t * mpqlib_find_free_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) { +int mpqlib_add_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint16_t language, uint16_t platform, int entry) { uint32_t i; if (!mpq_a->for_write) { __mpqlib_errno = MPQLIB_ERROR_READONLY; - return NULL; + return -1; } /* The hash table is a true one, pre-built. We can access it as-it, speeding up the searches drastically. */ @@ -453,20 +459,26 @@ static hash_t * mpqlib_find_free_hash_entry_by_hash(struct mpq_archive_t * mpq_a (mpq_a->hashs[i].platform == platform)) { /* Full collision ?! */ __mpqlib_errno = MPQLIB_ERROR_UNKNOWN; - return NULL; + return -1; + } + if (mpq_a->hashs[i].file_block_index == 0xffffffff) { + mpq_a->hashs[i].file_path_hasha = hA; + mpq_a->hashs[i].file_path_hashb = hB; + mpq_a->hashs[i].language = language; + mpq_a->hashs[i].platform = platform; + mpq_a->hashs[i].file_block_index = entry; + return 0; } - if (mpq_a->hashs[i].file_block_index == 0xffffffff) - return mpq_a->hashs + i; } __mpqlib_errno = MPQLIB_ERROR_TOO_MANY_FILES; - return NULL; + return -1; } -static hash_t * mpqlib_find_free_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) { +int mpqlib_add_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint16_t language, uint16_t platform, int entry) { if (!mpq_a->for_write) { __mpqlib_errno = MPQLIB_ERROR_READONLY; - return NULL; + return -1; } uint32_t h, hA, hB; @@ -475,10 +487,10 @@ static hash_t * mpqlib_find_free_hash_entry_by_name(struct mpq_archive_t * mpq_a hA = mpqlib_hashA_filename(name); hB = mpqlib_hashB_filename(name); - return mpqlib_find_free_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform); + return mpqlib_add_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform, entry); } -int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) { +int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint16_t language, uint16_t platform) { uint32_t h, hA, hB; h = mpqlib_hash_filename(name); @@ -487,8 +499,8 @@ int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * na return mpqlib_find_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform); } - -int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) { + +int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint16_t language, uint16_t platform) { hash_t * hash = mpqlib_locate_hash_entry(mpq_a, h, hA, hB, language, platform); if (hash) { @@ -497,53 +509,115 @@ int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uin return -1; } -int __mpqlib_seek(struct mpq_archive_t * mpq_a, uint64_t off) { - if (lseek64(mpq_a->fd, off, SEEK_SET) != off) - return 0; - return 1; -} - -int __mpqlib_read(struct mpq_archive_t * mpq_a, void * buffer, uint32_t size) { - return read_data(mpq_a, buffer, size); -} - -uint64_t mpqlib_ioctl(struct mpq_archive_t * mpq_a, enum mpqlib_ioctl_t command, int entry) { +uint64_t mpqlib_ioctl(struct mpq_archive_t * mpq_a, enum mpqlib_ioctl_t command, ...) { __mpqlib_errno = MPQLIB_ERROR_NO_ERROR; + int r = 0; + uint32_t u32; + uint64_t u64; + int entry; + void * buffer; + va_list ap; + va_start(ap, command); switch(command) { case MPQLIB_IOCTL_NO_ACTION: - return 0; + break; + case MPQLIB_IOCTL_SEEK: + u64 = va_arg(ap, uint64_t); + if (lseek64(mpq_a->fd, u64, SEEK_SET) != u64) { + r = -1; + __mpqlib_errno = MPQLIB_ERROR_SEEK; + } + break; + case MPQLIB_IOCTL_READ: + buffer = va_arg(ap, void *); + u32 = va_arg(ap, uint32_t); + r = read_data(mpq_a, buffer, u32) ? 0 : -1; + if (r == -1) + __mpqlib_errno = MPQLIB_ERROR_READ; + break; + case MPQLIB_IOCTL_WRITE: + if (!mpq_a->for_write) { + __mpqlib_errno = MPQLIB_ERROR_READONLY; + r = -1; + break; + } + buffer = va_arg(ap, void *); + u32 = va_arg(ap, uint32_t); + r = write_data(mpq_a, buffer, u32) ? 0 : -1; + if (r == -1) + __mpqlib_errno = MPQLIB_ERROR_WRITE; + break; case MPQLIB_IOCTL_GET_FORMAT_VERSION: - return mpq_a->format_version; + r = mpq_a->format_version; + break; case MPQLIB_IOCTL_GET_SECTOR_SIZE: - return mpq_a->sector_size; + r = mpq_a->sector_size; + break; + case MPQLIB_IOCTL_SET_BLOCK_OFFSET: + case MPQLIB_IOCTL_SET_BLOCK_SIZE: + case MPQLIB_IOCTL_SET_FILE_SIZE: + case MPQLIB_IOCTL_SET_FLAGS: + if (!mpq_a->for_write) { + __mpqlib_errno = MPQLIB_ERROR_READONLY; + r = -1; + break; + } case MPQLIB_IOCTL_ENTRY_EXISTS: case MPQLIB_IOCTL_GET_BLOCK_OFFSET: case MPQLIB_IOCTL_GET_BLOCK_SIZE: case MPQLIB_IOCTL_GET_FILE_SIZE: case MPQLIB_IOCTL_GET_FLAGS: + entry = va_arg(ap, int); if ((entry >= mpq_a->block_table_entries) || (entry < 0)) { __mpqlib_errno = MPQLIB_ERROR_IOCTL_INVALID_ENTRY; - return -1; + r = -1; + break; } switch (command) { case MPQLIB_IOCTL_ENTRY_EXISTS: - return 0; + break; case MPQLIB_IOCTL_GET_BLOCK_OFFSET: - return mpq_a->blocks[entry].block_offset; + r = mpq_a->blocks[entry].block_offset; + break; case MPQLIB_IOCTL_GET_BLOCK_SIZE: - return mpq_a->blocks[entry].block_size; + r = mpq_a->blocks[entry].block_size; + break; case MPQLIB_IOCTL_GET_FILE_SIZE: - return mpq_a->blocks[entry].file_size; + r = mpq_a->blocks[entry].file_size; + break; case MPQLIB_IOCTL_GET_FLAGS: - return mpq_a->blocks[entry].flags; + r = mpq_a->blocks[entry].flags; + break; + case MPQLIB_IOCTL_SET_BLOCK_OFFSET: + u64 = va_arg(ap, uint64_t); + mpq_a->blocks[entry].block_offset = u64; + break; + case MPQLIB_IOCTL_SET_BLOCK_SIZE: + u32 = va_arg(ap, uint32_t); + mpq_a->blocks[entry].block_size = u32; + break; + case MPQLIB_IOCTL_SET_FILE_SIZE: + u32 = va_arg(ap, uint32_t); + mpq_a->blocks[entry].file_size = u32; + break; + case MPQLIB_IOCTL_SET_FLAGS: + u32 = va_arg(ap, uint32_t); + mpq_a->blocks[entry].flags = u32; + break; default: // should never get there. __mpqlib_errno = MPQLIB_ERROR_UNKNOWN; - return -1; + r = -1; + break; } + break; default: __mpqlib_errno = MPQLIB_ERROR_INVALID_IOCTL; - return -1; + r = -1; + break; } + + va_end(ap); + return r; } diff --git a/mpq-bios.h b/mpq-bios.h index af58b93..5444469 100644 --- a/mpq-bios.h +++ b/mpq-bios.h @@ -15,6 +15,9 @@ struct mpq_archive_t; enum mpqlib_ioctl_t { MPQLIB_IOCTL_NO_ACTION = 0, + MPQLIB_IOCTL_SEEK, + MPQLIB_IOCTL_READ, + MPQLIB_IOCTL_WRITE, MPQLIB_IOCTL_ENTRY_EXISTS, MPQLIB_IOCTL_GET_FORMAT_VERSION, MPQLIB_IOCTL_GET_SECTOR_SIZE, @@ -22,6 +25,10 @@ enum mpqlib_ioctl_t { MPQLIB_IOCTL_GET_BLOCK_SIZE, MPQLIB_IOCTL_GET_FILE_SIZE, MPQLIB_IOCTL_GET_FLAGS, + MPQLIB_IOCTL_SET_BLOCK_OFFSET, + MPQLIB_IOCTL_SET_BLOCK_SIZE, + MPQLIB_IOCTL_SET_FILE_SIZE, + MPQLIB_IOCTL_SET_FLAGS, }; #ifdef __cplusplus @@ -34,9 +41,11 @@ struct mpq_archive_t * mpqlib_open_archive_for_writing(const char * fname); struct mpq_archive_t * mpqlib_reopen_archive(int fd); void mpqlib_printtables(struct mpq_archive_t *); void mpqlib_close_archive(struct mpq_archive_t *); -int mpqlib_find_hash_entry_by_name(struct mpq_archive_t *, const char * name, uint32_t language, uint32_t platform); -int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t *, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform); -uint64_t mpqlib_ioctl(struct mpq_archive_t *, enum mpqlib_ioctl_t command, int entry); +int mpqlib_find_hash_entry_by_name(struct mpq_archive_t *, const char * name, uint16_t language, uint16_t platform); +int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t *, uint32_t h, uint32_t hA, uint32_t hB, uint16_t language, uint16_t platform); +int mpqlib_add_hash_entry_by_name(struct mpq_archive_t *, const char * name, uint16_t language, uint16_t platform, int entry); +int mpqlib_add_hash_entry_by_hash(struct mpq_archive_t *, uint32_t h, uint32_t hA, uint32_t hB, uint16_t language, uint16_t, int entry); +uint64_t mpqlib_ioctl(struct mpq_archive_t *, enum mpqlib_ioctl_t command, ...); #ifdef __cplusplus } diff --git a/mpq-errors.c b/mpq-errors.c index b052e3b..3198e06 100644 --- a/mpq-errors.c +++ b/mpq-errors.c @@ -7,7 +7,9 @@ static const char * error_strings[] = { "Error opening file.", "File specified isn't an MPQ archive.", "Not enough memory.", + "File seek error." "File read error.", + "File write error." "Invalid ioctl.", "Invalid ioctl's file entry.", "File not found.", diff --git a/mpq-errors.h b/mpq-errors.h index ada05f1..e22d370 100644 --- a/mpq-errors.h +++ b/mpq-errors.h @@ -18,7 +18,9 @@ enum { MPQLIB_ERROR_OPEN, MPQLIB_ERROR_NOT_MPQ_ARCHIVE, MPQLIB_ERROR_MEMORY, + MPQLIB_ERROR_SEEK, MPQLIB_ERROR_READ, + MPQLIB_ERROR_WRITE, MPQLIB_ERROR_INVALID_IOCTL, MPQLIB_ERROR_IOCTL_INVALID_ENTRY, MPQLIB_ERROR_FILE_NOT_FOUND, diff --git a/mpq-file.c b/mpq-file.c index 56fe2b5..8356483 100644 --- a/mpq-file.c +++ b/mpq-file.c @@ -4,7 +4,6 @@ #include "mpq-bios.h" #include "mpq-file.h" #include "mpq-errors.h" -#include "int-bios.h" #include "extract.h" #include "errors.h" @@ -64,7 +63,7 @@ struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry) { return NULL; } - r->sector_size = mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_GET_SECTOR_SIZE, 0); + r->sector_size = mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_GET_SECTOR_SIZE); /* Allocating and filling up the mpq_file_t structure. */ if (!(r->buffer = malloc(r->sector_size))) { @@ -102,9 +101,9 @@ struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry) { } /* Reading the offset table and building the size table */ - __mpqlib_seek(mpq_a, r->offset); + mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_SEEK, r->offset); for (i = 0; i <= r->number_of_sectors; i++) { - __mpqlib_read(mpq_a, &o, 4); + mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_READ, &o, 4); r->offsets[i] = r->offset + o; } @@ -138,8 +137,8 @@ static int cache_sector(struct mpq_file_t * mpq_f, int sector) { /* current_sector should be initialized to -1 */ if (mpq_f->current_sector != sector) { int il, ol; - __mpqlib_seek(mpq_f->mpq_a, mpq_f->offsets[sector]); - __mpqlib_read(mpq_f->mpq_a, in_buf, mpq_f->sizes[sector]); + mpqlib_ioctl(mpq_f->mpq_a, MPQLIB_IOCTL_SEEK, mpq_f->offsets[sector]); + mpqlib_ioctl(mpq_f->mpq_a, MPQLIB_IOCTL_READ, mpq_f->sizes[sector]); mpq_f->current_sector = sector; il = ol = sector == (mpq_f->number_of_sectors - 1) ? mpq_f->remaining_bytes : mpq_f->sector_size; -- cgit v1.2.3