/*****************************************************************************\ * Copyright (c) 2004 Mark Aylett * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to permit * * persons to whom the Software is furnished to do so, subject to the * * following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * * USE OR OTHER DEALINGS IN THE SOFTWARE. * \*****************************************************************************/ static const char rcsid[] = "$Id: mar_c.c,v 1.12 2004/12/14 13:09:23 marayl Exp $"; #include "mar_c.h" #include "mar_debug_c.h" #include "mar_defs_c.h" #include "mar_format_c.h" #include "mar_info_c.h" #include "mar_meta_c.h" #include "mar_mfile_c.h" #include "mar_user_c.h" #if defined(WIN32) && defined(MAR_SHARED) #include "mar_windows_c.h" #endif /* WIN32 && MAR_SHARED */ #include #include #include #include #include #define MAR_READ 0x0001 #define MAR_WRITE 0x0002 #define MAR_READABLE(x) (x && (mar_torw((x)->flags_) & MAR_READ)) #define MAR_WRITABLE(x) (x && (mar_torw((x)->flags_) & MAR_WRITE)) struct mar_ { mar_seq_t seq_; int flags_; size_t isize_, offset_, refs_; }; static unsigned int mar_torw(int from) { switch (from & (MAR_RDONLY | MAR_WRONLY | MAR_RDWR)) { case MAR_RDONLY: return MAR_READ; case MAR_WRONLY: return MAR_WRITE; case MAR_RDWR: return MAR_READ | MAR_WRITE; } return 0; } static int mar_initialise(mar_seq_t seq, size_t* isize) { static const mar_uint16_t VERNO = 1; size_t local; size_t size = mar_seqsize_(seq); size = MAR_MIN(size, MAR_INIT_SIZE); if (-1 == mar_setregion_(seq, 0, size)) return -1; /** * Any existing archive will be of at least a minimum size. */ if (MAR_INIT_SIZE > size) { mar_byte_t* ptr; if (!(ptr = mar_resizeseq_(seq, MAR_INIT_SIZE))) return -1; mar_encode16_(ptr + MAR_VERNO, VERNO); mar_encode16_(ptr + MAR_ISIZE, 0); /** * Where there is an empty index, the usize value is positioned * immediately after the archive header. */ mar_encode16_(ptr + MAR_ISIZE, 0); local = 0; } else { /** * Verify version number embedded within header. */ const mar_byte_t* ptr = mar_seqaddr_(seq); if (VERNO != mar_decode16_(ptr + MAR_VERNO)) { MAR_DEBUG_MSG("Failed to initialise archive:" " Invalid version number\n"); errno = EINVAL; return -1; } local = mar_decode16_(ptr + MAR_ISIZE); } /** * Set the optional output parameter. */ if (isize) *isize = local; return 0; } #if defined(WIN32) && defined(MAR_SHARED) MAR_EXTERN BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { switch (reason) { case DLL_PROCESS_ATTACH: MAR_INITLEAKDUMP(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: MAR_DUMPLEAKS(); break; }; return TRUE; } #endif /* WIN32 && MAR_SHARED */ MAR_API int mar_copy(mar_t dst, mar_t src) { if (!MAR_WRITABLE(dst)) { MAR_DEBUG_MSG("Failed to copy archive:" " Null destination handle or not writable\n"); errno = EBADF; return -1; } if (!MAR_READABLE(src)) { MAR_DEBUG_MSG("Failed to copy archive:" " Null source handle or not readable\n"); errno = EBADF; return -1; } if (-1 == mar_copyseq_(dst->seq_, src->seq_)) return -1; dst->isize_ = src->isize_; return 0; } MAR_API mar_t mar_create(void) { mar_t mar; mar_seq_t seq = mar_createseq_(sizeof(struct mar_)); size_t isize; if (!seq) return NULL; if (-1 == mar_initialise(seq, &isize)) goto fail; mar = (mar_t)mar_seqtail_(seq); mar->seq_ = seq; mar->flags_ = MAR_RDWR; mar->isize_ = isize; mar->offset_ = 0; mar->refs_ = 1; return mar; fail: mar_freeseq_(seq); return NULL; } MAR_API mar_t mar_open(const char* path, int flags, ...) { mar_t mar; mar_seq_t seq; size_t isize; mode_t mode; if (flags & MAR_CREAT) { va_list args; assert(MAR_CREAT == (flags & MAR_CREAT)); va_start(args, flags); mode = va_arg(args, int); va_end(args); } else mode = 0; if (!(seq = mar_openseq_(path, flags & ~MAR_TRUNC, mode, sizeof(struct mar_)))) return NULL; if (-1 == mar_initialise(seq, &isize)) goto fail; mar = (mar_t)mar_seqtail_(seq); mar->seq_ = seq; mar->flags_ = flags; mar->isize_ = isize; mar->offset_ = 0; mar->refs_ = 1; if (flags & MAR_TRUNC) { assert(MAR_TRUNC == (flags & MAR_TRUNC)); if (-1 == mar_truncate(mar, 0)) goto fail; } return mar; fail: mar_freeseq_(seq); return NULL; } MAR_API int mar_release(mar_t mar) { if (0 == --mar->refs_) return mar_freeseq_(mar->seq_); return 0; } MAR_API int mar_retain(mar_t mar) { if (!mar) { MAR_DEBUG_MSG("Failed to retain handle:" " Null archive handle\n"); errno = EBADF; return -1; } ++mar->refs_; return 0; } MAR_API int mar_removepairs(mar_t mar) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to remove meta pairs:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } return mar_removepairs_(mar->seq_, &mar->isize_); } MAR_API int mar_setpair(mar_t mar, const mar_pair_t* pair, size_t* ord) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to set meta pairs:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } return mar_setpair_(mar->seq_, &mar->isize_, pair, ord); } MAR_API int mar_setmeta(mar_t mar, size_t ord, const void* data, size_t size) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to set meta data:" " Null archive handle not writable\n"); errno = EBADF; return -1; } return mar_setmeta_(mar->seq_, &mar->isize_, ord, data, size); } MAR_API int mar_unsetbykey(mar_t mar, const char* key, size_t* ord) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to unset meta pair by key:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } return mar_unsetbykey_(mar->seq_, &mar->isize_, key, ord); } MAR_API int mar_unsetbyord(mar_t mar, size_t ord) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to unset meta pair by ordinal:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } return mar_unsetbyord_(mar->seq_, &mar->isize_, ord); } MAR_API const void* mar_metabykey(mar_t mar, const char* key, size_t* size) { if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to get meta data by key:" " Null archive handle or not readable\n"); errno = EBADF; return NULL; } return mar_metabykey_(mar->seq_, mar->isize_, key, size); } MAR_API const void* mar_metabyord(mar_t mar, size_t ord, size_t* size) { if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to get meta data by ordinal:" " Null archive handle or not readable\n"); errno = EBADF; return NULL; } return mar_metabyord_(mar->seq_, mar->isize_, ord, size); } MAR_API int mar_metapair(mar_t mar, mar_pair_t* pair, size_t ord) { if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to get meta pair:" " Null archive handle or not readable\n"); errno = EBADF; return -1; } return mar_metapair_(mar->seq_, mar->isize_, pair, ord); } MAR_API int mar_metapairs(mar_t mar, size_t* size) { if (!mar) { MAR_DEBUG_MSG("Failed to get meta pairs:" " Null archive handle\n"); errno = EBADF; return -1; } if (!size) { MAR_DEBUG_MSG("Failed to get meta pairs:" " Null size pointer\n"); errno = EINVAL; return -1; } *size = mar->isize_; return 0; } MAR_API int mar_tokey(mar_t mar, mar_key_t key, size_t ord) { if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to get key:" " Null archive handle or not readable\n"); errno = EBADF; return -1; } return mar_tokey_(mar->seq_, mar->isize_, key, ord); } MAR_API int mar_toord(mar_t mar, size_t* ord, const char* key) { if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to get ordinal:" " Null archive handle or not readable\n"); errno = EBADF; return -1; } return mar_toord_(mar->seq_, mar->isize_, ord, key); } MAR_API int mar_insert(mar_t mar, const char* path) { mar_mfile_t mfile; const void* addr; size_t size; if (!(mfile = mar_openmfile_(path, MAR_RDONLY, 0, 0))) return -1; if (0 != (size = mar_mfileresvd_(mfile))) { if (!(addr = mar_mapmfile_(mfile, size))) goto fail; if (-1 == mar_setuser(mar, addr, size)) goto fail; } return mar_closemfile_(mfile); fail: mar_closemfile_(mfile); return -1; } MAR_API ssize_t mar_read(mar_t mar, void* buf, size_t size) { ssize_t ret; if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to read user data:" " Null archive handle or not readable\n"); errno = EBADF; return -1; } ret = mar_read_(mar->seq_, mar->isize_, mar->offset_, buf, size); if (-1 == ret) return -1; mar->offset_ += ret; return ret; } MAR_API off_t mar_seek(mar_t mar, off_t offset, int whence) { off_t local; if (!mar) { MAR_DEBUG_MSG("Failed to seek user data:" " Null archive handle\n"); errno = EBADF; return -1; } switch (whence) { case MAR_SET: local = offset; break; case MAR_CUR: local = mar->offset_ + offset; break; case MAR_END: { size_t size; if (-1 == mar_usersize_(mar->seq_, mar->isize_, &size)) return -1; local = size + offset; } break; default: MAR_DEBUG_MSG("Failed to seek user data:" " Invalid whence value\n"); goto fail; } if (0 > local) { MAR_DEBUG_MSG("Failed to seek user data:" " Negative file position\n"); goto fail; } mar->offset_ = local; return 0; fail: errno = EINVAL; return -1; } MAR_API int mar_setuser(mar_t mar, const void* data, size_t size) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to set user data:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } return mar_setuser_(mar->seq_, mar->isize_, data, size); } MAR_API int mar_sync(mar_t mar) { if (!mar) { MAR_DEBUG_MSG("Failed to sync archive:" " Null archive handle\n"); errno = EBADF; return -1; } return mar_syncseq_(mar->seq_); } MAR_API int mar_truncate(mar_t mar, size_t size) { if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to truncate user data:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } return mar_truncate_(mar->seq_, mar->isize_, size); } MAR_API ssize_t mar_write(mar_t mar, const void* buf, size_t size) { ssize_t ret; if (!MAR_WRITABLE(mar)) { MAR_DEBUG_MSG("Failed to write user data:" " Null archive handle or not writable\n"); errno = EBADF; return -1; } if (mar->flags_ & MAR_APPEND) { assert(MAR_APPEND == (mar->flags_ & MAR_APPEND)); if (-1 == mar_seek(mar, 0, MAR_END)) return -1; } ret = mar_write_(mar->seq_, mar->isize_, mar->offset_, buf, size); if (-1 == ret) return -1; mar->offset_ += ret; return ret; } MAR_API int mar_extract(mar_t mar, const char* path) { mar_mfile_t mfile; void* dst; const void* src; size_t size; if (!(src = mar_user(mar, &size))) return -1; if (!(mfile = mar_openmfile_(path, MAR_WRONLY | MAR_CREAT | MAR_TRUNC, 0666, 0))) return -1; if (size) { if (!(dst = mar_mapmfile_(mfile, size))) goto fail; memcpy(dst, src, size); } return mar_closemfile_(mfile); fail: mar_closemfile_(mfile); return -1; } MAR_API const void* mar_user(mar_t mar, size_t* size) { if (!MAR_READABLE(mar)) { MAR_DEBUG_MSG("Failed to get user data:" " Null archive handle or not readable\n"); errno = EBADF; return NULL; } return mar_user_(mar->seq_, mar->isize_, size); } MAR_API int mar_usersize(mar_t mar, size_t* size) { if (!mar) { MAR_DEBUG_MSG("Failed to get user size:" " Null archive handle\n"); errno = EBADF; return -1; } return mar_usersize_(mar->seq_, mar->isize_, size); } MAR_API int mar_errno(void) { return errno; }