This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/deps/jamlib/mbase.c
2017-03-18 14:37:16 +10:00

592 lines
15 KiB
C

/*
JAMLIB - A JAM subroutine library
Copyright (C) 1999 Björn Stenberg
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Changes made by Johan Billing 2000-04-16:
- Added support for Win32 and Linux
- Changed JAM_OpenMB to open files in binary mode
- Changed source to use feof() instead of errno == EPASTEOF
- Changed source to use structrw to read and write structures
- Fixed broken JAM_FindUser()
- #includes string.h and stdlib.h instead of memory.h
Backported changes from JAMLIB 1.4.7 made by Johan Billing 2003-10-26
- Now uses calloc instead of malloc/memset
- (*NewArea_PPS) will be set to zero even if calloc() failed in
JAM_OpenMB() and JAM_CreateMB()
- JAM_CreateMB() no longer attempts to forever to lock the newly created
messagebase. If the first attempt fails, it will return an error.
- jam_Lock() now sets Base_PS->Errno under Linux
Other changes made by Johan Billing 2003-10-26
- Fixed comparison between signed and unsigned variable in JAM_GetMBSize()
- JAM_CreateMB() would not unlock and close the newly created messagebase
upon failure.
Changes made by Johan Billing 2004-07-10
- Updated the Win32-specific parts of the code to make it compatible with
newer versions of MinGW (tested with 3.1.0-1):
* Now uses Sleep() instead of sleep()
* Changed _LK_UNLOCK to _LK_UNLCK in jam_Lock()
*/
/***********************************************************************
**
** MBASE.C -- Message base handling
**
** Author: Bj”rn Stenberg (bjorn.stenberg@sth.frontec.se)
**
***********************************************************************/
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "jam.h"
#include "structrw.h"
#if defined( __OS2__ )
#include <os2.h> /* ANSI C does not include file locking :-( */
#endif
#if defined( __WIN32__ )
#include <sys/locking.h>
#include <io.h>
#include <windows.h>
#if !defined( _LK_UNLCK ) && defined ( _LK_UNLOCK )
#define _LK_UNLCK _LK_UNLOCK /* For backwards compatibility */
#endif
#endif
#if defined( __LINUX__ )
#include <sys/file.h>
#include <unistd.h>
#endif
#define OS_ERROR_OFFSET 10000
#if defined( __OS2__ )
#define JAM_Sleep( _x_ ) DosSleep( _x_*1000 )
#endif
#if defined( __WIN32__ )
#define JAM_Sleep(x) Sleep(x*1000)
#endif
#if defined( __LINUX__ )
#define JAM_Sleep(x) sleep(x)
#endif
/*************************************<**********************************
**
** File-global functions
**
***********************************************************************/
int jam_Open( s_JamBase* Base_PS, char* Filename_PC, char* Mode_PC );
int jam_Lock( s_JamBase* Base_PS, int DoLock_I );
/***********************************************************************
**
** JAM_OpenMB - Open message base
**
***********************************************************************/
int JAM_OpenMB( char* Basename_PC, s_JamBase** NewArea_PPS )
{
s_JamBase* Base_PS;
int Status_I;
if ( !NewArea_PPS )
return JAM_BAD_PARAM;
*NewArea_PPS = NULL;
Base_PS = (s_JamBase*) calloc( 1, sizeof( s_JamBase ) );
if (!Base_PS)
return JAM_NO_MEMORY;
*NewArea_PPS = Base_PS;
Status_I = jam_Open( Base_PS, Basename_PC, "r+b" );
if ( Status_I ) {
return Status_I;
}
return 0;
}
/***********************************************************************
**
** JAM_CreateMB - Create a new message base
**
***********************************************************************/
int JAM_CreateMB( char* Basename_PC,
uint32_t BaseMsg_I,
s_JamBase** NewArea_PPS )
{
s_JamBaseHeader Base_S;
int Status_I;
s_JamBase* Base_PS;
if ( !NewArea_PPS || !BaseMsg_I )
return JAM_BAD_PARAM;
*NewArea_PPS = NULL;
Base_PS = (s_JamBase*) calloc( 1, sizeof( s_JamBase ) );
if (!Base_PS)
return JAM_NO_MEMORY;
*NewArea_PPS = Base_PS;
Status_I = jam_Open( Base_PS, Basename_PC, "w+b" );
if ( Status_I )
return Status_I;
Base_S.DateCreated = time(NULL);
Base_S.ModCounter = 0;
Base_S.ActiveMsgs = 0;
Base_S.PasswordCRC = 0xffffffff;
Base_S.BaseMsgNum = BaseMsg_I;
memset( &Base_S.RSRVD, 0, sizeof( Base_S.RSRVD ) );
Status_I = JAM_LockMB( Base_PS, 0 ); /* If the new base cannot be locked directly, something is seriously wrong */
if ( Status_I ) {
JAM_CloseMB(Base_PS);
return Status_I;
}
Status_I = JAM_WriteMBHeader( Base_PS, &Base_S );
if ( Status_I ) {
JAM_UnlockMB( Base_PS );
JAM_CloseMB(Base_PS);
return Status_I;
}
JAM_UnlockMB( Base_PS );
return 0;
}
/***********************************************************************
**
** JAM_CloseMB - Close message base
**
***********************************************************************/
int JAM_CloseMB( s_JamBase* Base_PS )
{
if ( Base_PS->Locked_I ) {
int Status_I = JAM_UnlockMB( Base_PS );
if ( Status_I )
return Status_I;
}
if ( Base_PS->HdrFile_PS ) {
fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL;
fclose( Base_PS->LrdFile_PS ); Base_PS->LrdFile_PS = NULL;
}
Base_PS->Locked_I = 0;
return 0;
}
/***********************************************************************
**
** JAM_RemoveMB - Remove a message base
**
***********************************************************************/
int JAM_RemoveMB( s_JamBase* Base_PS, char* Basename_PC )
{
char Filename_AC[250];
int Status_AI[4];
/* .JHR file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_HDRFILE );
Status_AI[0] = remove( Filename_AC );
if ( Status_AI[0] )
Base_PS->Errno_I = errno;
/* .JDT file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_TXTFILE );
Status_AI[1] = remove( Filename_AC );
if ( Status_AI[1] )
Base_PS->Errno_I = errno;
/* .JDX file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_IDXFILE );
Status_AI[2] = remove( Filename_AC );
if ( Status_AI[2] )
Base_PS->Errno_I = errno;
/* .JLR file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_LRDFILE );
Status_AI[3] = remove( Filename_AC );
if ( Status_AI[3] )
Base_PS->Errno_I = errno;
if (Status_AI[0] || Status_AI[1] || Status_AI[2] || Status_AI[3])
return JAM_IO_ERROR;
return 0;
}
/***********************************************************************
**
** JAM_GetMBSize - Get the number of messages in message base
**
***********************************************************************/
int JAM_GetMBSize( s_JamBase* Base_PS, uint32_t* Messages_PI )
{
long Offset_I;
/* go to end of index file */
if ( fseek( Base_PS->IdxFile_PS, 0, SEEK_END ) ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
Offset_I = ftell( Base_PS->IdxFile_PS );
if ( Offset_I == -1 ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
*Messages_PI = Offset_I / sizeof( s_JamIndex );
return 0;
}
/***********************************************************************
**
** JAM_LockMB - Lock message base
**
***********************************************************************/
int JAM_LockMB( s_JamBase* Base_PS, int Timeout_I )
{
if ( Base_PS->Locked_I )
return 0;
switch ( Timeout_I )
{
/* unlimited timeout */
case -1:
while ( jam_Lock( Base_PS, 1 ) == JAM_LOCK_FAILED )
JAM_Sleep( 1 );
return 0;
/* no timeout */
case 0:
return jam_Lock( Base_PS, 1 );
/* X seconds timeout */
default:
{
time_t Time_I = time(NULL) + Timeout_I;
while ( time(NULL) < Time_I )
{
int Result_I;
Result_I = jam_Lock( Base_PS, 1 );
if ( Result_I == JAM_LOCK_FAILED )
JAM_Sleep( 1 );
else
return Result_I;
}
return JAM_LOCK_FAILED;
}
}
}
/***********************************************************************
**
** JAM_UnlockMB - Flush all writes and unlock message base
**
***********************************************************************/
int JAM_UnlockMB( s_JamBase* Base_PS )
{
fflush( Base_PS->HdrFile_PS );
fflush( Base_PS->TxtFile_PS );
fflush( Base_PS->IdxFile_PS );
fflush( Base_PS->LrdFile_PS );
return jam_Lock( Base_PS, 0 );
}
/***********************************************************************
**
** JAM_ReadMBHeader - Read message base header
**
***********************************************************************/
int JAM_ReadMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS )
{
if ( !Header_PS || !Base_PS )
return JAM_BAD_PARAM;
if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_SET ) ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
if ( 1 > freadjambaseheader(Base_PS->HdrFile_PS,Header_PS) ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
return 0;
}
/***********************************************************************
**
** JAM_WriteMBHeader - Write message base header
**
***********************************************************************/
int JAM_WriteMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS )
{
if ( !Header_PS || !Base_PS )
return JAM_BAD_PARAM;
if ( !Base_PS->Locked_I )
return JAM_NOT_LOCKED;
if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_SET ) ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
/* ensure header looks right */
memcpy( Header_PS->Signature, HEADERSIGNATURE, 4 );
Header_PS->ModCounter++;
if ( 1 > fwritejambaseheader(Base_PS->HdrFile_PS,Header_PS) ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
fflush( Base_PS->HdrFile_PS );
return 0;
}
/***********************************************************************
**
** JAM_FindUser - Scan scan file for messages to a user
**
***********************************************************************/
int JAM_FindUser( s_JamBase* Base_PS,
uint32_t UserCrc_I,
uint32_t StartMsg_I,
uint32_t* MsgNo_PI )
{
uint32_t MsgNo_I;
/* go to start message */
if ( fseek( Base_PS->IdxFile_PS, StartMsg_I * sizeof( s_JamIndex ),
SEEK_SET ) ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
/* scan file */
for ( MsgNo_I = StartMsg_I; ; MsgNo_I++ ) {
s_JamIndex Index_S;
if ( 1 > freadjamindex(Base_PS->IdxFile_PS,&Index_S) ) {
if ( feof(Base_PS->IdxFile_PS) )
return JAM_NO_USER;
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
if ( Index_S.UserCRC == UserCrc_I )
break;
}
*MsgNo_PI = MsgNo_I;
return 0;
}
/***********************************************************************
**
** jam_Lock - Lock/unlock a message base
**
***********************************************************************/
int jam_Lock( s_JamBase* Base_PS, int DoLock_I )
{
#if defined(__OS2__)
FILELOCK Area_S;
APIRET Status_I;
ULONG Timeout_I = 0;
int Handle_I;
Handle_I = fileno( Base_PS->HdrFile_PS );
if ( Handle_I == -1 ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
Area_S.lOffset = 0;
Area_S.lRange = 1;
if ( DoLock_I )
Status_I = DosSetFileLocks( Handle_I, NULL, &Area_S, Timeout_I, 0 );
else
Status_I = DosSetFileLocks( Handle_I, &Area_S, NULL, Timeout_I, 0 );
if ( Status_I ) {
if ( 232 == Status_I )
return JAM_LOCK_FAILED;
Base_PS->Errno_I = Status_I + OS_ERROR_OFFSET;
return JAM_IO_ERROR;
}
if ( DoLock_I )
Base_PS->Locked_I = 1;
else
Base_PS->Locked_I = 0;
return 0;
#elif defined(__WIN32__)
int Handle_I,Status_I;
fseek(Base_PS->HdrFile_PS,0,SEEK_SET); /* Lock from start of file */
Handle_I = fileno( Base_PS->HdrFile_PS );
if ( Handle_I == -1 ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
if ( DoLock_I )
Status_I = _locking(Handle_I,_LK_NBLCK,1);
else
Status_I = _locking(Handle_I,_LK_UNLCK,1);
if ( Status_I )
return JAM_LOCK_FAILED;
if ( DoLock_I )
Base_PS->Locked_I = 1;
else
Base_PS->Locked_I = 0;
return 0;
#elif defined(__LINUX__)
int Handle_I,Status_I;
struct flock fl;
fseek(Base_PS->HdrFile_PS,0,SEEK_SET); /* Lock from start of file */
Handle_I = fileno( Base_PS->HdrFile_PS );
if ( Handle_I == -1 ) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
if(DoLock_I) fl.l_type=F_WRLCK;
else fl.l_type=F_UNLCK;
fl.l_whence=SEEK_SET;
fl.l_start=0;
fl.l_len=1;
fl.l_pid=getpid();
Status_I=fcntl(Handle_I,F_SETLK,&fl);
if ( Status_I ) {
Base_PS->Errno_I = errno;
return JAM_LOCK_FAILED;
}
if ( DoLock_I )
Base_PS->Locked_I = 1;
else
Base_PS->Locked_I = 0;
return 0;
#else
#error Unsupported platform
#endif
}
/***********************************************************************
**
** jam_Open - Open/create message base files
**
***********************************************************************/
int jam_Open( s_JamBase* Base_PS, char* Basename_PC, char* Mode_PC )
{
char Filename_AC[250];
/* .JHR file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_HDRFILE );
Base_PS->HdrFile_PS = fopen( Filename_AC, Mode_PC );
if (!Base_PS->HdrFile_PS) {
Base_PS->Errno_I = errno;
return JAM_IO_ERROR;
}
/* .JDT file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_TXTFILE );
Base_PS->TxtFile_PS = fopen( Filename_AC, Mode_PC );
if (!Base_PS->TxtFile_PS) {
Base_PS->Errno_I = errno;
fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
return JAM_IO_ERROR;
}
/* .JDX file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_IDXFILE );
Base_PS->IdxFile_PS = fopen( Filename_AC, Mode_PC );
if (!Base_PS->IdxFile_PS) {
Base_PS->Errno_I = errno;
fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
return JAM_IO_ERROR;
}
/* .JLR file */
sprintf( Filename_AC, "%s%s", Basename_PC, EXT_LRDFILE );
Base_PS->LrdFile_PS = fopen( Filename_AC, Mode_PC );
if (!Base_PS->LrdFile_PS) {
Base_PS->Errno_I = errno;
fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL;
return JAM_IO_ERROR;
}
return 0;
}