1733 lines
58 KiB
C++
1733 lines
58 KiB
C++
/* smblib.c */
|
|
|
|
/* Synchronet message base (SMB) library routines */
|
|
|
|
/* $Id$ */
|
|
|
|
/****************************************************************************
|
|
* @format.tab-size 4 (Plain Text/Source Code File Header) *
|
|
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
|
|
* *
|
|
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
|
|
* *
|
|
* 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 *
|
|
* of the License, or (at your option) any later version. *
|
|
* See the GNU Lesser General Public License for more details: lgpl.txt or *
|
|
* http://www.fsf.org/copyleft/lesser.html *
|
|
* *
|
|
* Anonymous FTP access to the most recent released source is available at *
|
|
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
|
|
* *
|
|
* Anonymous CVS access to the development source and modification history *
|
|
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
|
|
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
|
|
* (just hit return, no password is necessary) *
|
|
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
|
|
* *
|
|
* For Synchronet coding style and modification guidelines, see *
|
|
* http://www.synchro.net/source.html *
|
|
* *
|
|
* You are encouraged to submit any modifications (preferably in Unix diff *
|
|
* format) via e-mail to mods@synchro.net *
|
|
* *
|
|
* Note: If this box doesn't appear square, then you need to fix your tabs. *
|
|
****************************************************************************/
|
|
|
|
#if defined __WATCOMC__ || defined __TURBOC__
|
|
#include <mem.h>
|
|
#else
|
|
#include <memory.h>
|
|
#endif
|
|
|
|
#ifdef __WATCOMC__
|
|
#include <dos.h>
|
|
#elif defined __TURBOC__
|
|
#include <dir.h>
|
|
#endif
|
|
|
|
/* ANSI C Library headers */
|
|
|
|
#ifdef HAVE_MALLOC_H
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
/* SMB-specific headers */
|
|
#include "smblib.h"
|
|
#include <gtimall.h>
|
|
#include <gfilutil.h>
|
|
|
|
/* Use smb_ver() and smb_lib_ver() to obtain these values */
|
|
#define SMBLIB_VERSION "2.16" /* SMB library version */
|
|
#define SMB_VERSION 0x0121 /* SMB format version */
|
|
/* High byte major, low byte minor */
|
|
|
|
#define U_MODE 777 /* permitions for the new files (real: U_MODE XOR UMASK) */
|
|
/* This is required for sopen(,,,) */
|
|
|
|
#ifndef __gtimall_h
|
|
time32_t gtime(time32_t *timep)
|
|
{
|
|
time32_t temp = (time32_t)time(NULL);
|
|
return timep ? *timep = temp : temp;
|
|
}
|
|
#endif //#ifndef __gtimall_h
|
|
|
|
int SMBCALL smb_ver(void)
|
|
{
|
|
return(SMB_VERSION);
|
|
}
|
|
|
|
char* SMBCALL smb_lib_ver(void)
|
|
{
|
|
return(SMBLIB_VERSION);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Open a message base of name 'smb->file' */
|
|
/* Opens files for READing messages or updating message indices only */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_open(smb_t* smb)
|
|
{
|
|
int file;
|
|
char str[128];
|
|
smbhdr_t hdr;
|
|
|
|
/* Set default values, if uninitialized */
|
|
if(!smb->retry_time)
|
|
smb->retry_time=10; /* seconds */
|
|
if(!smb->retry_delay
|
|
|| smb->retry_delay>(smb->retry_time*100)) /* at least ten retries */
|
|
smb->retry_delay=250; /* milliseconds */
|
|
smb->shd_fp=smb->sdt_fp=smb->sid_fp=NULL;
|
|
smb->last_error[0]=0;
|
|
sprintf(str,"%s.shd",smb->file);
|
|
if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,U_MODE))==-1) {
|
|
sprintf(smb->last_error,"%d opening %s",errno,str);
|
|
return(2);
|
|
}
|
|
|
|
if((smb->shd_fp=fdopen(file,"r+b"))==NULL) {
|
|
sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
|
|
close(file);
|
|
return(4);
|
|
}
|
|
|
|
if(filelength(file)>=sizeof(smbhdr_t)) {
|
|
setvbuf(smb->shd_fp,smb->shd_buf,_IONBF,SHD_BLOCK_LEN);
|
|
if(smb_locksmbhdr(smb)!=0) {
|
|
smb_close(smb);
|
|
/* smb_lockmsghdr set last_error */
|
|
return(-1);
|
|
}
|
|
memset(&hdr,0,sizeof(smbhdr_t));
|
|
if(fread(&hdr,sizeof(smbhdr_t),1,smb->shd_fp)!=1) {
|
|
sprintf(smb->last_error,"reading header");
|
|
smb_close(smb);
|
|
return(-10);
|
|
}
|
|
if(memcmp(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID)) {
|
|
sprintf(smb->last_error,"corrupt SMB header ID: %.*s",LEN_HEADER_ID,hdr.id);
|
|
smb_close(smb);
|
|
return(-2);
|
|
}
|
|
if(hdr.version<0x110) { /* Compatibility check */
|
|
sprintf(smb->last_error,"insufficient header version: %X",hdr.version);
|
|
smb_close(smb);
|
|
return(-3);
|
|
}
|
|
if(fread(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp)
|
|
!=sizeof(smbstatus_t)) {
|
|
sprintf(smb->last_error,"failed to read status");
|
|
smb_close(smb);
|
|
return(-4);
|
|
}
|
|
smb_unlocksmbhdr(smb);
|
|
rewind(smb->shd_fp);
|
|
}
|
|
|
|
setvbuf(smb->shd_fp,smb->shd_buf,_IOFBF,SHD_BLOCK_LEN);
|
|
|
|
sprintf(str,"%s.sdt",smb->file);
|
|
if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,U_MODE))==-1) {
|
|
sprintf(smb->last_error,"%d opening %s",errno,str);
|
|
smb_close(smb);
|
|
return(1);
|
|
}
|
|
|
|
if((smb->sdt_fp=fdopen(file,"r+b"))==NULL) {
|
|
sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
|
|
close(file);
|
|
smb_close(smb);
|
|
return(5);
|
|
}
|
|
|
|
setvbuf(smb->sdt_fp,NULL,_IOFBF,2*1024);
|
|
|
|
sprintf(str,"%s.sid",smb->file);
|
|
if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,U_MODE))==-1) {
|
|
sprintf(smb->last_error,"%d opening %s",errno,str);
|
|
smb_close(smb);
|
|
return(3);
|
|
}
|
|
|
|
if((smb->sid_fp=fdopen(file,"r+b"))==NULL) {
|
|
sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
|
|
close(file);
|
|
smb_close(smb);
|
|
return(6);
|
|
}
|
|
|
|
setvbuf(smb->sid_fp,NULL,_IOFBF,2*1024);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Closes the currently open message base */
|
|
/****************************************************************************/
|
|
void SMBCALL smb_close(smb_t* smb)
|
|
{
|
|
if(smb->shd_fp!=NULL) {
|
|
smb_unlocksmbhdr(smb); /* In case it's been locked */
|
|
fclose(smb->shd_fp);
|
|
}
|
|
if(smb->sid_fp!=NULL)
|
|
fclose(smb->sid_fp);
|
|
if(smb->sdt_fp!=NULL)
|
|
fclose(smb->sdt_fp);
|
|
smb->sid_fp=smb->shd_fp=smb->sdt_fp=NULL;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Opens the data block allocation table message base 'smb->file' */
|
|
/* Retrys for retry_time number of seconds */
|
|
/* Return 0 on success, non-zero otherwise */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_open_da(smb_t* smb)
|
|
{
|
|
int file;
|
|
char str[128];
|
|
time32_t start = 0;
|
|
|
|
sprintf(str,"%s.sda",smb->file);
|
|
while(1) {
|
|
if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,U_MODE))!=-1)
|
|
break;
|
|
if(errno!=EACCES && errno!=EAGAIN) {
|
|
sprintf(smb->last_error,"%d opening %s",errno,str);
|
|
return(-1);
|
|
}
|
|
if(!start)
|
|
start = gtime(NULL);
|
|
else
|
|
if(gtime(NULL)-start >= smb->retry_time) {
|
|
sprintf(smb->last_error,"timeout opening %s (retry_time=%d)"
|
|
,str,smb->retry_time);
|
|
return(-2);
|
|
}
|
|
usleep(smb->retry_delay);
|
|
}
|
|
if((smb->sda_fp=fdopen(file,"r+b"))==NULL) {
|
|
sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
|
|
close(file);
|
|
return(-3);
|
|
}
|
|
setvbuf(smb->sda_fp,NULL,_IOFBF,2*1024);
|
|
return(0);
|
|
}
|
|
|
|
void SMBCALL smb_close_da(smb_t* smb)
|
|
{
|
|
if(smb->sda_fp!=NULL)
|
|
fclose(smb->sda_fp);
|
|
smb->sda_fp=NULL;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Opens the header block allocation table for message base 'smb.file' */
|
|
/* Retrys for smb.retry_time number of seconds */
|
|
/* Return 0 on success, non-zero otherwise */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_open_ha(smb_t* smb)
|
|
{
|
|
int file;
|
|
char str[128];
|
|
time32_t start = 0;
|
|
|
|
sprintf(str,"%s.sha",smb->file);
|
|
while(1) {
|
|
if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,U_MODE))!=-1)
|
|
break;
|
|
if(errno!=EACCES && errno!=EAGAIN) {
|
|
sprintf(smb->last_error,"%d opening %s",errno,str);
|
|
return(-1);
|
|
}
|
|
if(!start)
|
|
start = gtime(NULL);
|
|
else
|
|
if(gtime(NULL)-start >= smb->retry_time) {
|
|
sprintf(smb->last_error,"timeout opening %s (retry_time=%d)"
|
|
,str,smb->retry_time);
|
|
return(-2);
|
|
}
|
|
usleep(smb->retry_delay);
|
|
}
|
|
if((smb->sha_fp=fdopen(file,"r+b"))==NULL) {
|
|
sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
|
|
close(file);
|
|
return(-3);
|
|
}
|
|
setvbuf(smb->sha_fp,NULL,_IOFBF,2*1024);
|
|
return(0);
|
|
}
|
|
|
|
void SMBCALL smb_close_ha(smb_t* smb)
|
|
{
|
|
if(smb->sha_fp!=NULL)
|
|
fclose(smb->sha_fp);
|
|
smb->sha_fp=NULL;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* If the parameter 'push' is non-zero, this function stores the currently */
|
|
/* open message base to the "virtual" smb stack. Up to SMB_STACK_LEN */
|
|
/* message bases may be stored (defined in SMBDEFS.H). */
|
|
/* The parameter 'op' is the operation to perform on the stack. Either */
|
|
/* SMB_STACK_PUSH, SMB_STACK_POP, or SMB_STACK_XCHNG */
|
|
/* If the operation is SMB_STACK_POP, this function restores a message base */
|
|
/* previously saved with a SMB_STACK_PUSH call to this same function. */
|
|
/* If the operation is SMB_STACK_XCHNG, then the current message base is */
|
|
/* exchanged with the message base on the top of the stack (most recently */
|
|
/* pushed. */
|
|
/* If the current message base is not open, the SMB_STACK_PUSH and */
|
|
/* SMB_STACK_XCHNG operations do nothing */
|
|
/* Returns 0 on success, non-zero if stack full. */
|
|
/* If operation is SMB_STACK_POP or SMB_STACK_XCHNG, it always returns 0. */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_stack(smb_t* smb, int op)
|
|
{
|
|
static smb_t stack[SMB_STACK_LEN];
|
|
static int stack_idx;
|
|
smb_t tmp_smb;
|
|
|
|
if(op==SMB_STACK_PUSH) {
|
|
if(stack_idx>=SMB_STACK_LEN) {
|
|
sprintf(smb->last_error,"SMB stack overflow");
|
|
return(1);
|
|
}
|
|
if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL)
|
|
return(0); /* Msg base not open */
|
|
memcpy(&stack[stack_idx],smb,sizeof(smb_t));
|
|
stack_idx++;
|
|
return(0);
|
|
}
|
|
/* pop or xchng */
|
|
if(!stack_idx) /* Nothing on the stack, so do nothing */
|
|
return(0);
|
|
if(op==SMB_STACK_XCHNG) {
|
|
if(smb->shd_fp==NULL)
|
|
return(0);
|
|
memcpy(&tmp_smb,smb,sizeof(smb_t));
|
|
}
|
|
|
|
stack_idx--;
|
|
memcpy(smb,&stack[stack_idx],sizeof(smb_t));
|
|
if(op==SMB_STACK_XCHNG) {
|
|
memcpy(&stack[stack_idx],&tmp_smb,sizeof(smb_t));
|
|
stack_idx++;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Truncates header file */
|
|
/* Retrys for smb.retry_time number of seconds */
|
|
/* Return 0 on success, non-zero otherwise */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_trunchdr(smb_t* smb)
|
|
{
|
|
time32_t start = 0;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
rewind(smb->shd_fp);
|
|
while(1) {
|
|
if(!chsize(fileno(smb->shd_fp),0L))
|
|
break;
|
|
if(errno!=EACCES && errno!=EAGAIN) {
|
|
sprintf(smb->last_error,"%d changing header file size",errno);
|
|
return(-1);
|
|
}
|
|
if(!start)
|
|
start = gtime(NULL);
|
|
else
|
|
if(gtime(NULL)-start >= smb->retry_time) { /* Time-out */
|
|
sprintf(smb->last_error,"timeout changing header file size (retry_time=%d)"
|
|
,smb->retry_time);
|
|
return(-2);
|
|
}
|
|
usleep(smb->retry_delay);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*********************************/
|
|
/* Message Base Header Functions */
|
|
/*********************************/
|
|
|
|
/****************************************************************************/
|
|
/* Attempts for smb.retry_time number of seconds to lock the msg base hdr */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_locksmbhdr(smb_t* smb)
|
|
{
|
|
time32_t start = 0;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
while(1) {
|
|
if(lock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))==0) {
|
|
smb->locked=1; /* TRUE */
|
|
return(0);
|
|
}
|
|
if(!start)
|
|
start = gtime(NULL);
|
|
else
|
|
if(gtime(NULL)-start >= smb->retry_time)
|
|
break;
|
|
/* In case we've already locked it */
|
|
if(unlock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))==0)
|
|
smb->locked=0; /* FALSE */
|
|
usleep(smb->retry_delay);
|
|
}
|
|
sprintf(smb->last_error,"timeout locking header");
|
|
return(-1);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Read the SMB header from the header file and place into smb.status */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_getstatus(smb_t* smb)
|
|
{
|
|
int i;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
setvbuf(smb->shd_fp,smb->shd_buf,_IONBF,SHD_BLOCK_LEN);
|
|
clearerr(smb->shd_fp);
|
|
fseek(smb->shd_fp,sizeof(smbhdr_t),SEEK_SET);
|
|
i=fread(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
|
|
setvbuf(smb->shd_fp,smb->shd_buf,_IOFBF,SHD_BLOCK_LEN);
|
|
if(i==sizeof(smbstatus_t))
|
|
return(0);
|
|
sprintf(smb->last_error,"read %d instead of %d",i,(int)sizeof(smbstatus_t));
|
|
return(1);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Writes message base header */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_putstatus(smb_t* smb)
|
|
{
|
|
int i;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->shd_fp);
|
|
fseek(smb->shd_fp,sizeof(smbhdr_t),SEEK_SET);
|
|
i=fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
|
|
fflush(smb->shd_fp);
|
|
if(i==sizeof(smbstatus_t))
|
|
return(0);
|
|
sprintf(smb->last_error,"wrote %d instead of %d",i,(int)sizeof(smbstatus_t));
|
|
return(1);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Unlocks previously locks message base header */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_unlocksmbhdr(smb_t* smb)
|
|
{
|
|
int result;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
result = unlock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t));
|
|
if(result==0)
|
|
smb->locked=0; /* FALSE */
|
|
return(result);
|
|
}
|
|
|
|
/********************************/
|
|
/* Individual Message Functions */
|
|
/********************************/
|
|
|
|
/****************************************************************************/
|
|
/* Attempts for smb.retry_time number of seconds to lock the hdr for 'msg' */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_lockmsghdr(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
time32_t start = 0;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
while(1) {
|
|
if(!lock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t)))
|
|
return(0);
|
|
if(!start)
|
|
start = gtime(NULL);
|
|
else
|
|
if(gtime(NULL)-start >= smb->retry_time)
|
|
break;
|
|
/* In case we've already locked it */
|
|
unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t));
|
|
usleep(smb->retry_delay);
|
|
}
|
|
sprintf(smb->last_error,"timeout locking header");
|
|
return(-1);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Fills msg->idx with message index based on msg->hdr.number */
|
|
/* OR if msg->hdr.number is 0, based on msg->offset (record offset). */
|
|
/* if msg.hdr.number does not equal 0, then msg->offset is filled too. */
|
|
/* Either msg->hdr.number or msg->offset must be initialized before */
|
|
/* calling this function */
|
|
/* Returns 1 if message number wasn't found, 0 if it was */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
idxrec_t idx;
|
|
uint32_t l,length,total,bot,top;
|
|
|
|
if(smb->sid_fp==NULL) {
|
|
sprintf(smb->last_error,"index not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->sid_fp);
|
|
if(!msg->hdr.number) {
|
|
fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET);
|
|
if(!fread(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
|
|
sprintf(smb->last_error,"reading index");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
length=filelength(fileno(smb->sid_fp));
|
|
if(!length) {
|
|
sprintf(smb->last_error,"invalid index file length: %d",length);
|
|
return(1);
|
|
}
|
|
total=length/sizeof(idxrec_t);
|
|
if(!total) {
|
|
sprintf(smb->last_error,"invalid index file length: %d",length);
|
|
return(1);
|
|
}
|
|
|
|
bot=0;
|
|
top=total;
|
|
l=total/2; /* Start at middle index */
|
|
while(1) {
|
|
fseek(smb->sid_fp,l*sizeof(idxrec_t),SEEK_SET);
|
|
if(!fread(&idx,sizeof(idxrec_t),1,smb->sid_fp)) {
|
|
sprintf(smb->last_error,"reading index");
|
|
return(1);
|
|
}
|
|
if(bot==top-1 && idx.number!=msg->hdr.number) {
|
|
sprintf(smb->last_error,"msg %d not found",msg->hdr.number);
|
|
return(1);
|
|
}
|
|
if(idx.number>msg->hdr.number) {
|
|
top=l;
|
|
l=bot+((top-bot)/2);
|
|
continue;
|
|
}
|
|
if(idx.number<msg->hdr.number) {
|
|
bot=l;
|
|
l=top-((top-bot)/2);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
msg->idx=idx;
|
|
msg->offset=l;
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Reads the first index record in the open message base */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx)
|
|
{
|
|
if(smb->sid_fp==NULL) {
|
|
sprintf(smb->last_error,"index not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->sid_fp);
|
|
fseek(smb->sid_fp,0,SEEK_SET);
|
|
if(!fread(idx,sizeof(idxrec_t),1,smb->sid_fp)) {
|
|
sprintf(smb->last_error,"reading index");
|
|
return(-2);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Reads the last index record in the open message base */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx)
|
|
{
|
|
int32_t length;
|
|
|
|
if(smb->sid_fp==NULL) {
|
|
sprintf(smb->last_error,"index not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->sid_fp);
|
|
length=filelength(fileno(smb->sid_fp));
|
|
if(length<sizeof(idxrec_t)) {
|
|
sprintf(smb->last_error,"invalid index file length: %d",length);
|
|
return(-1);
|
|
}
|
|
fseek(smb->sid_fp,length-sizeof(idxrec_t),SEEK_SET);
|
|
if(!fread(idx,sizeof(idxrec_t),1,smb->sid_fp)) {
|
|
sprintf(smb->last_error,"reading index");
|
|
return(-2);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Figures out the total length of the header record for 'msg' */
|
|
/* Returns length */
|
|
/****************************************************************************/
|
|
uint SMBCALL smb_getmsghdrlen(smbmsg_t* msg)
|
|
{
|
|
int i;
|
|
|
|
/* fixed portion */
|
|
msg->hdr.length=sizeof(msghdr_t);
|
|
/* data fields */
|
|
msg->hdr.length+=msg->hdr.total_dfields*sizeof(dfield_t);
|
|
/* header fields */
|
|
for(i=0;i<msg->total_hfields;i++) {
|
|
msg->hdr.length+=sizeof(hfield_t);
|
|
msg->hdr.length+=msg->hfield[i].length;
|
|
}
|
|
return(msg->hdr.length);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Figures out the total length of the data buffer for 'msg' */
|
|
/* Returns length */
|
|
/****************************************************************************/
|
|
uint32_t SMBCALL smb_getmsgdatlen(smbmsg_t* msg)
|
|
{
|
|
int i;
|
|
uint32_t length=0L;
|
|
|
|
for(i=0;i<msg->hdr.total_dfields;i++)
|
|
length+=msg->dfield[i].length;
|
|
return(length);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Read header information into 'msg' structure */
|
|
/* msg->idx.offset must be set before calling this function */
|
|
/* Must call smb_freemsgmem() to free memory allocated for var len strs */
|
|
/* Returns 0 on success, non-zero if error */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
hfield_t *vp;
|
|
void **vpp;
|
|
uint16_t i;
|
|
uint32_t l, offset;
|
|
idxrec_t idx;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
rewind(smb->shd_fp);
|
|
fseek(smb->shd_fp,msg->idx.offset,SEEK_SET);
|
|
idx=msg->idx;
|
|
offset=msg->offset;
|
|
memset(msg,0,sizeof(smbmsg_t));
|
|
msg->idx=idx;
|
|
msg->offset=offset;
|
|
if(!fread(&msg->hdr,sizeof(msghdr_t),1,smb->shd_fp)) {
|
|
sprintf(smb->last_error,"reading msg header");
|
|
return(-1);
|
|
}
|
|
if(memcmp(msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID)) {
|
|
sprintf(smb->last_error,"corrupt message header ID: %.*s",LEN_HEADER_ID,msg->hdr.id);
|
|
return(-2);
|
|
}
|
|
if(msg->hdr.version<0x110) {
|
|
sprintf(smb->last_error,"insufficient header version: %X",msg->hdr.version);
|
|
return(-9);
|
|
}
|
|
l=sizeof(msghdr_t);
|
|
if(msg->hdr.total_dfields && (msg->dfield
|
|
=(dfield_t *)MALLOC(sizeof(dfield_t)*msg->hdr.total_dfields))==NULL) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error,"malloc failure of %d bytes for %d data fields"
|
|
,(int)sizeof(dfield_t)*msg->hdr.total_dfields, msg->hdr.total_dfields);
|
|
return(-3);
|
|
}
|
|
i=0;
|
|
while(i<msg->hdr.total_dfields && l<msg->hdr.length) {
|
|
if(!fread(&msg->dfield[i],sizeof(dfield_t),1,smb->shd_fp)) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error,"reading data field %d",i);
|
|
return(-4);
|
|
}
|
|
i++;
|
|
l+=sizeof(dfield_t);
|
|
}
|
|
if(i<msg->hdr.total_dfields) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error,"insufficient data fields read (%d instead of %d)"
|
|
,i,msg->hdr.total_dfields);
|
|
return(-8);
|
|
}
|
|
while(l<msg->hdr.length) {
|
|
i=msg->total_hfields;
|
|
if((vpp=(void* *)REALLOC(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error
|
|
,"realloc failure of %d bytes for header field data"
|
|
,(int)sizeof(void*)*(i+1));
|
|
return(-3);
|
|
}
|
|
msg->hfield_dat=vpp;
|
|
if((vp=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error
|
|
,"realloc failure of %d bytes for header fields"
|
|
,(int)sizeof(hfield_t)*(i+1));
|
|
return(-3);
|
|
}
|
|
msg->hfield=vp;
|
|
msg->total_hfields++;
|
|
if(!fread(&msg->hfield[i],sizeof(hfield_t),1,smb->shd_fp)) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error,"reading header field");
|
|
return(-5);
|
|
}
|
|
l+=sizeof(hfield_t);
|
|
if((msg->hfield_dat[i]=(char*)MALLOC(msg->hfield[i].length+1))
|
|
==NULL) { /* Allocate 1 extra for NULL terminator */
|
|
sprintf(smb->last_error
|
|
,"malloc failure of %d bytes for header field %d"
|
|
,msg->hfield[i].length+1, i);
|
|
smb_freemsgmem(msg); /* or 0 length field */
|
|
return(-3);
|
|
}
|
|
memset(msg->hfield_dat[i],0,msg->hfield[i].length+1); /* init to NULL */
|
|
if(msg->hfield[i].length
|
|
&& !fread(msg->hfield_dat[i],msg->hfield[i].length,1,smb->shd_fp)) {
|
|
smb_freemsgmem(msg);
|
|
sprintf(smb->last_error,"reading header field data");
|
|
return(-6);
|
|
}
|
|
switch(msg->hfield[i].type) { /* convenience variables */
|
|
case SENDER:
|
|
if(!msg->from) {
|
|
msg->from=(char *)msg->hfield_dat[i];
|
|
break;
|
|
}
|
|
case FORWARDED: /* fall through */
|
|
msg->forwarded=1;
|
|
break;
|
|
case SENDERAGENT:
|
|
if(!msg->forwarded)
|
|
msg->from_agent=*(uint16_t *)msg->hfield_dat[i];
|
|
break;
|
|
case SENDEREXT:
|
|
if(!msg->forwarded)
|
|
msg->from_ext=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case SENDERNETTYPE:
|
|
if(!msg->forwarded)
|
|
msg->from_net.type=*(uint16_t *)msg->hfield_dat[i];
|
|
break;
|
|
case SENDERNETADDR:
|
|
if(!msg->forwarded)
|
|
msg->from_net.addr=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case REPLYTO:
|
|
msg->replyto=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case REPLYTOEXT:
|
|
msg->replyto_ext=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case REPLYTOAGENT:
|
|
msg->replyto_agent=*(uint16_t *)msg->hfield_dat[i];
|
|
break;
|
|
case REPLYTONETTYPE:
|
|
msg->replyto_net.type=*(uint16_t *)msg->hfield_dat[i];
|
|
break;
|
|
case REPLYTONETADDR:
|
|
msg->replyto_net.addr=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case RECIPIENT:
|
|
msg->to=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case RECIPIENTEXT:
|
|
msg->to_ext=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case RECIPIENTAGENT:
|
|
msg->to_agent=*(uint16_t *)msg->hfield_dat[i];
|
|
break;
|
|
case RECIPIENTNETTYPE:
|
|
msg->to_net.type=*(uint16_t *)msg->hfield_dat[i];
|
|
break;
|
|
case RECIPIENTNETADDR:
|
|
msg->to_net.addr=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case SUBJECT:
|
|
msg->subj=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case RFC822MSGID:
|
|
msg->id=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case RFC822REPLYID:
|
|
msg->reply_id=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case USENETPATH:
|
|
msg->path=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case USENETNEWSGROUPS:
|
|
msg->newsgroups=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case FIDOMSGID:
|
|
msg->ftn_msgid=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case FIDOREPLYID:
|
|
msg->ftn_reply=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case FIDOAREA:
|
|
msg->ftn_area=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case FIDOPID:
|
|
msg->ftn_pid=(char *)msg->hfield_dat[i];
|
|
break;
|
|
case FIDOFLAGS:
|
|
msg->ftn_flags=(char *)msg->hfield_dat[i];
|
|
break;
|
|
|
|
}
|
|
l+=msg->hfield[i].length;
|
|
}
|
|
|
|
if(!msg->from || !msg->to || !msg->subj) {
|
|
sprintf(smb->last_error,"missing required header field (from/to/subj)");
|
|
smb_freemsgmem(msg);
|
|
return(-7);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Frees memory allocated for 'msg' */
|
|
/****************************************************************************/
|
|
void SMBCALL smb_freemsgmem(smbmsg_t* msg)
|
|
{
|
|
uint16_t i;
|
|
|
|
if(msg->dfield) {
|
|
FREE(msg->dfield);
|
|
msg->dfield=NULL;
|
|
}
|
|
for(i=0;i<msg->total_hfields;i++)
|
|
if(msg->hfield_dat[i]) {
|
|
FREE(msg->hfield_dat[i]);
|
|
msg->hfield_dat[i]=NULL;
|
|
}
|
|
msg->total_hfields=0;
|
|
if(msg->hfield) {
|
|
FREE(msg->hfield);
|
|
msg->hfield=NULL;
|
|
}
|
|
if(msg->hfield_dat) {
|
|
FREE(msg->hfield_dat);
|
|
msg->hfield_dat=NULL;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Copies memory allocated for 'srcmsg' to 'msg' */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_copymsgmem(smbmsg_t* msg, smbmsg_t* srcmsg)
|
|
{
|
|
int i;
|
|
|
|
memcpy(msg,srcmsg,sizeof(smbmsg_t));
|
|
|
|
/* data field types/lengths */
|
|
if((msg->dfield=(dfield_t *)MALLOC(msg->hdr.total_dfields*sizeof(dfield_t)))==NULL)
|
|
return(1);
|
|
memcpy(msg->dfield,srcmsg->dfield,msg->hdr.total_dfields*sizeof(dfield_t));
|
|
|
|
/* header field types/lengths */
|
|
if((msg->hfield=(hfield_t *)MALLOC(msg->total_hfields*sizeof(hfield_t)))==NULL)
|
|
return(2);
|
|
memcpy(msg->hfield,srcmsg->hfield,msg->total_hfields*sizeof(hfield_t));
|
|
|
|
/* header field data */
|
|
if((msg->hfield_dat=(void* *)MALLOC(msg->total_hfields*sizeof(void*)))==NULL)
|
|
return(3);
|
|
|
|
for(i=0;i<msg->total_hfields;i++) {
|
|
if((msg->hfield_dat[i]=(char*)MALLOC(msg->hfield[i].length))==NULL)
|
|
return(4);
|
|
memcpy(msg->hfield_dat[i],srcmsg->hfield_dat[i],msg->hfield[i].length);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Unlocks header for 'msg' */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
return(unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t)));
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Adds a header field to the 'msg' structure (in memory only) */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_hfield(smbmsg_t* msg, uint16_t type, size_t length, void* data)
|
|
{
|
|
hfield_t* vp;
|
|
void* *vpp;
|
|
int i;
|
|
|
|
i=msg->total_hfields;
|
|
if((vp=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL)
|
|
return(1);
|
|
|
|
msg->hfield=vp;
|
|
if((vpp=(void* *)REALLOC(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL)
|
|
return(2);
|
|
|
|
msg->hfield_dat=vpp;
|
|
msg->total_hfields++;
|
|
msg->hfield[i].type=type;
|
|
msg->hfield[i].length=length;
|
|
if(length) {
|
|
if((msg->hfield_dat[i]=(void* )MALLOC(length))==NULL)
|
|
return(4);
|
|
memcpy(msg->hfield_dat[i],data,length);
|
|
}
|
|
else
|
|
msg->hfield_dat[i]=NULL;
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Searches for a specific header field (by type) and returns it */
|
|
/****************************************************************************/
|
|
void* SMBCALL smb_get_hfield(smbmsg_t* msg, uint16_t type, hfield_t* hfield)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<msg->total_hfields;i++)
|
|
if(msg->hfield[i].type == type) {
|
|
if(hfield != NULL)
|
|
hfield = &msg->hfield[i];
|
|
return(msg->hfield_dat[i]);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Adds a data field to the 'msg' structure (in memory only) */
|
|
/* Automatically figures out the offset into the data buffer from existing */
|
|
/* dfield lengths */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_dfield(smbmsg_t* msg, uint16_t type, uint32_t length)
|
|
{
|
|
dfield_t* vp;
|
|
int i,j;
|
|
|
|
i=msg->hdr.total_dfields;
|
|
if((vp=(dfield_t *)REALLOC(msg->dfield,sizeof(dfield_t)*(i+1)))==NULL)
|
|
return(1);
|
|
|
|
msg->dfield=vp;
|
|
msg->hdr.total_dfields++;
|
|
msg->dfield[i].type=type;
|
|
msg->dfield[i].length=length;
|
|
for(j=msg->dfield[i].offset=0;j<i;j++)
|
|
msg->dfield[i].offset+=msg->dfield[j].length;
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Checks CRC history file for duplicate crc. If found, returns 1. */
|
|
/* If no dupe, adds to CRC history and returns 0, or negative if error. */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
|
|
{
|
|
char str[128];
|
|
int file;
|
|
int32_t length;
|
|
uint32_t l, *buf;
|
|
time32_t start = 0;
|
|
|
|
if(!smb->status.max_crcs)
|
|
return(0);
|
|
|
|
sprintf(str,"%s.sch",smb->file);
|
|
while(1) {
|
|
if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,U_MODE))!=-1)
|
|
break;
|
|
if(errno!=EACCES && errno!=EAGAIN) {
|
|
sprintf(smb->last_error,"%d opening %s", errno, str);
|
|
return(-1);
|
|
}
|
|
if(!start)
|
|
start = gtime(NULL);
|
|
else
|
|
if(gtime(NULL)-start >= smb->retry_time) {
|
|
sprintf(smb->last_error,"timeout opening %s (retry_time=%d)"
|
|
,str,smb->retry_time);
|
|
return(-2);
|
|
}
|
|
usleep(smb->retry_delay);
|
|
}
|
|
|
|
length=filelength(file);
|
|
if(length<0L) {
|
|
close(file);
|
|
sprintf(smb->last_error,"invalid file length: %d", length);
|
|
return(-4);
|
|
}
|
|
if((buf=(uint32_t*)MALLOC(smb->status.max_crcs*4))==NULL) {
|
|
close(file);
|
|
sprintf(smb->last_error
|
|
,"malloc failure of %d bytes"
|
|
,smb->status.max_crcs*4);
|
|
return(-3);
|
|
}
|
|
if((uint32_t)length>=smb->status.max_crcs*4L) { /* Reached or exceeds max crcs */
|
|
read(file,buf,smb->status.max_crcs*4);
|
|
for(l=0;l<smb->status.max_crcs;l++)
|
|
if(crc==buf[l])
|
|
break;
|
|
if(l<smb->status.max_crcs) { /* Dupe CRC found */
|
|
close(file);
|
|
FREE(buf);
|
|
sprintf(smb->last_error
|
|
,"duplicate message detected");
|
|
return(1);
|
|
}
|
|
chsize(file,0L); /* truncate it */
|
|
lseek(file,0L,SEEK_SET);
|
|
write(file,buf+4,(smb->status.max_crcs-1)*4);
|
|
}
|
|
|
|
else if(length/4) { /* Less than max crcs */
|
|
read(file,buf,length);
|
|
for(l=0;l<(uint32_t)(length/4);l++)
|
|
if(crc==buf[l])
|
|
break;
|
|
if(l<(uint32_t)(length/4L)) { /* Dupe CRC found */
|
|
close(file);
|
|
FREE(buf);
|
|
sprintf(smb->last_error
|
|
,"duplicate message detected");
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
lseek(file,0L,SEEK_END);
|
|
write(file,&crc,sizeof(crc)); /* Write to the end */
|
|
FREE(buf);
|
|
close(file);
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Creates a new message header record in the header file. */
|
|
/* If storage is SMB_SELFPACK, self-packing conservative allocation is used */
|
|
/* If storage is SMB_FASTALLOC, fast allocation is used */
|
|
/* If storage is SMB_HYPERALLOC, no allocation tables are used (fastest) */
|
|
/* This function will UN-lock the SMB header */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
|
|
{
|
|
int i;
|
|
int32_t l;
|
|
|
|
if(!smb->locked && smb_locksmbhdr(smb))
|
|
return(1);
|
|
if(smb_getstatus(smb)) {
|
|
smb_unlocksmbhdr(smb);
|
|
return(2);
|
|
}
|
|
|
|
if(storage!=SMB_HYPERALLOC && (i=smb_open_ha(smb))!=0) {
|
|
smb_unlocksmbhdr(smb);
|
|
return(i);
|
|
}
|
|
|
|
msg->hdr.length=smb_getmsghdrlen(msg);
|
|
if(storage==SMB_HYPERALLOC)
|
|
l=smb_hallochdr(smb);
|
|
else if(storage==SMB_FASTALLOC)
|
|
l=smb_fallochdr(smb,msg->hdr.length);
|
|
else
|
|
l=smb_allochdr(smb,msg->hdr.length);
|
|
if(storage!=SMB_HYPERALLOC)
|
|
smb_close_ha(smb);
|
|
if(l==-1L) {
|
|
smb_unlocksmbhdr(smb);
|
|
return(-1);
|
|
}
|
|
|
|
msg->idx.number=msg->hdr.number=smb->status.last_msg+1;
|
|
msg->idx.offset=smb->status.header_offset+l;
|
|
msg->idx.time=msg->hdr.when_imported.time;
|
|
msg->idx.attr=msg->hdr.attr;
|
|
msg->offset=smb->status.total_msgs;
|
|
i=smb_putmsg(smb,msg);
|
|
if(i==0) { /* success */
|
|
smb->status.last_msg++;
|
|
smb->status.total_msgs++;
|
|
smb_putstatus(smb);
|
|
}
|
|
smb_unlocksmbhdr(smb);
|
|
return(i);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Writes both header and index information for msg 'msg' */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
int i;
|
|
|
|
i=smb_putmsghdr(smb,msg);
|
|
if(i)
|
|
return(i);
|
|
return(smb_putmsgidx(smb,msg));
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Writes index information for 'msg' */
|
|
/* msg->idx */
|
|
/* and msg->offset must be set prior to calling to this function */
|
|
/* Returns 0 if everything ok */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
if(smb->sid_fp==NULL) {
|
|
sprintf(smb->last_error,"index not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->sid_fp);
|
|
fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET);
|
|
if(!fwrite(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
|
|
sprintf(smb->last_error,"writing index");
|
|
return(1);
|
|
}
|
|
fflush(smb->sid_fp);
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Writes header information for 'msg' */
|
|
/* msg->hdr.length */
|
|
/* msg->idx.offset */
|
|
/* and msg->offset must be set prior to calling to this function */
|
|
/* Returns 0 if everything ok */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
uint16_t i;
|
|
uint32_t l;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
if(msg->idx.offset<sizeof(smbhdr_t)+sizeof(smbstatus_t)
|
|
|| msg->idx.offset<smb->status.header_offset) {
|
|
sprintf(smb->last_error,"invalid header offset: %d",msg->idx.offset);
|
|
return(-7);
|
|
}
|
|
clearerr(smb->shd_fp);
|
|
if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET)) {
|
|
sprintf(smb->last_error,"seeking to %d in index",msg->idx.offset);
|
|
return(-1);
|
|
}
|
|
|
|
/**********************************/
|
|
/* Set the message header ID here */
|
|
/**********************************/
|
|
memcpy(&msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID);
|
|
|
|
/************************************************/
|
|
/* Write the fixed portion of the header record */
|
|
/************************************************/
|
|
if(!fwrite(&msg->hdr,sizeof(msghdr_t),1,smb->shd_fp)) {
|
|
sprintf(smb->last_error,"writing fixed portion of header record");
|
|
return(-2);
|
|
}
|
|
|
|
/************************************************/
|
|
/* Write the data fields (each is fixed length) */
|
|
/************************************************/
|
|
for(i=0;i<msg->hdr.total_dfields;i++)
|
|
if(!fwrite(&msg->dfield[i],sizeof(dfield_t),1,smb->shd_fp)) {
|
|
sprintf(smb->last_error,"writing data field");
|
|
return(-3);
|
|
}
|
|
|
|
/*******************************************/
|
|
/* Write the variable length header fields */
|
|
/*******************************************/
|
|
for(i=0;i<msg->total_hfields;i++) {
|
|
if(!fwrite(&msg->hfield[i],sizeof(hfield_t),1,smb->shd_fp)) {
|
|
sprintf(smb->last_error,"writing header field");
|
|
return(-4);
|
|
}
|
|
if(msg->hfield[i].length /* more then 0 bytes int32_t */
|
|
&& !fwrite(msg->hfield_dat[i],msg->hfield[i].length,1,smb->shd_fp)) {
|
|
sprintf(smb->last_error,"writing header field data");
|
|
return(-5);
|
|
}
|
|
}
|
|
|
|
l=smb_getmsghdrlen(msg);
|
|
while(l%SHD_BLOCK_LEN) {
|
|
if(fputc(0,smb->shd_fp)==EOF) {
|
|
sprintf(smb->last_error,"padding header block");
|
|
return(-6); /* pad block with NULL */
|
|
}
|
|
l++;
|
|
}
|
|
fflush(smb->shd_fp);
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Creates a sub-board's initial header file */
|
|
/* Truncates and deletes other associated SMB files */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_create(smb_t* smb)
|
|
{
|
|
char str[128];
|
|
smbhdr_t hdr;
|
|
|
|
if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
if(filelength(fileno(smb->shd_fp))>=sizeof(smbhdr_t)+sizeof(smbstatus_t)
|
|
&& smb_locksmbhdr(smb)) /* header exists, so lock it */
|
|
return(1);
|
|
memset(&hdr,0,sizeof(smbhdr_t));
|
|
memcpy(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID);
|
|
hdr.version=SMB_VERSION;
|
|
hdr.length=sizeof(smbhdr_t)+sizeof(smbstatus_t);
|
|
smb->status.last_msg=smb->status.total_msgs=0;
|
|
smb->status.header_offset=sizeof(smbhdr_t)+sizeof(smbstatus_t);
|
|
rewind(smb->shd_fp);
|
|
fwrite(&hdr,1,sizeof(smbhdr_t),smb->shd_fp);
|
|
fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
|
|
rewind(smb->shd_fp);
|
|
chsize(fileno(smb->shd_fp),sizeof(smbhdr_t)+sizeof(smbstatus_t));
|
|
fflush(smb->shd_fp);
|
|
|
|
rewind(smb->sdt_fp);
|
|
chsize(fileno(smb->sdt_fp),0L);
|
|
rewind(smb->sid_fp);
|
|
chsize(fileno(smb->sid_fp),0L);
|
|
|
|
sprintf(str,"%s.sda",smb->file);
|
|
remove(str); /* if it exists, delete it */
|
|
sprintf(str,"%s.sha",smb->file);
|
|
remove(str); /* if it exists, delete it */
|
|
sprintf(str,"%s.sch",smb->file);
|
|
remove(str);
|
|
smb_unlocksmbhdr(smb);
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Returns number of data blocks required to store "length" amount of data */
|
|
/****************************************************************************/
|
|
uint32_t SMBCALL smb_datblocks(uint32_t length)
|
|
{
|
|
uint32_t blocks;
|
|
|
|
blocks=length/SDT_BLOCK_LEN;
|
|
if(length%SDT_BLOCK_LEN)
|
|
blocks++;
|
|
return(blocks);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Returns number of header blocks required to store "length" size header */
|
|
/****************************************************************************/
|
|
uint32_t SMBCALL smb_hdrblocks(uint32_t length)
|
|
{
|
|
uint32_t blocks;
|
|
|
|
blocks=length/SHD_BLOCK_LEN;
|
|
if(length%SHD_BLOCK_LEN)
|
|
blocks++;
|
|
return(blocks);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Finds unused space in data file based on block allocation table and */
|
|
/* marks space as used in allocation table. */
|
|
/* File must be opened read/write DENY ALL */
|
|
/* Returns offset to beginning of data (in bytes, not blocks) */
|
|
/* Assumes smb_open_da() has been called */
|
|
/* smb_close_da() should be called after */
|
|
/* Returns negative on error */
|
|
/****************************************************************************/
|
|
int32_t SMBCALL smb_allocdat(smb_t* smb, uint32_t length, uint16_t headers)
|
|
{
|
|
uint16_t i, j;
|
|
uint32_t l, blocks, offset = 0;
|
|
|
|
if(smb->sda_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
blocks=smb_datblocks(length);
|
|
j=0; /* j is consecutive unused block counter */
|
|
fflush(smb->sda_fp);
|
|
rewind(smb->sda_fp);
|
|
while(!feof(smb->sda_fp)) {
|
|
if(!fread(&i,2,1,smb->sda_fp))
|
|
break;
|
|
offset+=SDT_BLOCK_LEN;
|
|
if(!i) j++;
|
|
else j=0;
|
|
if(j==blocks) {
|
|
offset-=(blocks*SDT_BLOCK_LEN);
|
|
break;
|
|
}
|
|
}
|
|
clearerr(smb->sda_fp);
|
|
fseek(smb->sda_fp,(offset/SDT_BLOCK_LEN)*2L,SEEK_SET);
|
|
for(l=0;l<blocks;l++)
|
|
if(!fwrite(&headers,2,1,smb->sda_fp)) {
|
|
sprintf(smb->last_error,"writing allocation bytes");
|
|
return(-1);
|
|
}
|
|
fflush(smb->sda_fp);
|
|
return(offset);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Allocates space for data, but doesn't search for unused blocks */
|
|
/* Returns negative on error */
|
|
/****************************************************************************/
|
|
int32_t SMBCALL smb_fallocdat(smb_t* smb, uint32_t length, uint16_t headers)
|
|
{
|
|
uint32_t l,blocks,offset;
|
|
|
|
if(smb->sda_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
fflush(smb->sda_fp);
|
|
clearerr(smb->sda_fp);
|
|
blocks=smb_datblocks(length);
|
|
fseek(smb->sda_fp,0L,SEEK_END);
|
|
offset=(ftell(smb->sda_fp)/2L)*SDT_BLOCK_LEN;
|
|
for(l=0;l<blocks;l++)
|
|
if(!fwrite(&headers,2,1,smb->sda_fp))
|
|
break;
|
|
fflush(smb->sda_fp);
|
|
if(l<blocks) {
|
|
sprintf(smb->last_error,"writing allocation bytes");
|
|
return(-1L);
|
|
}
|
|
return(offset);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* De-allocates space for data */
|
|
/* Returns non-zero on error */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_freemsgdat(smb_t* smb, uint32_t offset, uint32_t length, uint16_t headers)
|
|
{
|
|
int da_opened = 0;
|
|
int retval = 0;
|
|
uint16_t i;
|
|
uint32_t l, blocks;
|
|
|
|
if(smb->status.attr&SMB_HYPERALLOC) /* do nothing */
|
|
return(0);
|
|
|
|
blocks=smb_datblocks(length);
|
|
|
|
if(smb->sda_fp==NULL) {
|
|
if((i=smb_open_da(smb))!=0)
|
|
return(i);
|
|
da_opened=1;
|
|
}
|
|
|
|
clearerr(smb->sda_fp);
|
|
for(l=0;l<blocks;l++) {
|
|
if(fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*2L,SEEK_SET)) {
|
|
sprintf(smb->last_error
|
|
,"seeking to %ld of allocation file"
|
|
,((offset/SDT_BLOCK_LEN)+l)*2L);
|
|
retval=1;
|
|
break;
|
|
}
|
|
if(!fread(&i,2,1,smb->sda_fp)) {
|
|
sprintf(smb->last_error,"reading allocation bytes");
|
|
retval=2;
|
|
break;
|
|
}
|
|
if(!headers || headers>i)
|
|
i=0; /* don't want to go negative */
|
|
else
|
|
i-=headers;
|
|
if(fseek(smb->sda_fp,-2L,SEEK_CUR)) {
|
|
sprintf(smb->last_error,"seeking backwards 2 bytes in allocation file");
|
|
retval=3;
|
|
break;
|
|
}
|
|
if(!fwrite(&i,2,1,smb->sda_fp)) {
|
|
sprintf(smb->last_error,"writing allocation bytes");
|
|
retval=4;
|
|
break;
|
|
}
|
|
}
|
|
fflush(smb->sda_fp);
|
|
if(da_opened)
|
|
smb_close_da(smb);
|
|
return(retval);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Adds to data allocation records for blocks starting at 'offset' */
|
|
/* Returns non-zero on error */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_incdat(smb_t* smb, uint32_t offset, uint32_t length, uint16_t headers)
|
|
{
|
|
uint16_t i;
|
|
uint32_t l, blocks;
|
|
|
|
if(smb->sda_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->sda_fp);
|
|
blocks=smb_datblocks(length);
|
|
for(l=0;l<blocks;l++) {
|
|
fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*2L,SEEK_SET);
|
|
if(!fread(&i,2,1,smb->sda_fp)) {
|
|
sprintf(smb->last_error,"reading allocation record");
|
|
return(1);
|
|
}
|
|
i+=headers;
|
|
fseek(smb->sda_fp,-2L,SEEK_CUR);
|
|
if(!fwrite(&i,2,1,smb->sda_fp)) {
|
|
sprintf(smb->last_error,"writing allocation record");
|
|
return(2);
|
|
}
|
|
}
|
|
fflush(smb->sda_fp);
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* De-allocates blocks for header record */
|
|
/* Returns non-zero on error */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_freemsghdr(smb_t* smb, uint32_t offset, uint32_t length)
|
|
{
|
|
uint8_t c = 0;
|
|
uint32_t l,blocks;
|
|
|
|
if(smb->sha_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
clearerr(smb->sha_fp);
|
|
blocks=smb_hdrblocks(length);
|
|
fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET);
|
|
for(l=0;l<blocks;l++)
|
|
if(!fwrite(&c,1,1,smb->sha_fp)) {
|
|
sprintf(smb->last_error,"writing allocation record");
|
|
return(1);
|
|
}
|
|
fflush(smb->sha_fp);
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Frees all allocated header and data blocks for 'msg' */
|
|
/****************************************************************************/
|
|
int SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg)
|
|
{
|
|
int i;
|
|
uint16_t x;
|
|
|
|
if(smb->status.attr&SMB_HYPERALLOC) /* Nothing to do */
|
|
return(0);
|
|
|
|
for(x=0;x<msg->hdr.total_dfields;x++) {
|
|
if((i=smb_freemsgdat(smb,msg->hdr.offset+msg->dfield[x].offset
|
|
,msg->dfield[x].length,1))!=0)
|
|
return(i);
|
|
}
|
|
return(smb_freemsghdr(smb,msg->idx.offset-smb->status.header_offset
|
|
,msg->hdr.length));
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Finds unused space in header file based on block allocation table and */
|
|
/* marks space as used in allocation table. */
|
|
/* File must be opened read/write DENY ALL */
|
|
/* Returns offset to beginning of header (in bytes, not blocks) */
|
|
/* Assumes smb_open_ha() has been called */
|
|
/* smb_close_ha() should be called after */
|
|
/* Returns -1L on error */
|
|
/****************************************************************************/
|
|
int32_t SMBCALL smb_allochdr(smb_t* smb, uint32_t length)
|
|
{
|
|
uint8_t c;
|
|
uint16_t i;
|
|
uint32_t l, blocks, offset = 0;
|
|
|
|
if(smb->sha_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
blocks=smb_hdrblocks(length);
|
|
i=0; /* i is consecutive unused block counter */
|
|
fflush(smb->sha_fp);
|
|
rewind(smb->sha_fp);
|
|
while(!feof(smb->sha_fp)) {
|
|
if(!fread(&c,1,1,smb->sha_fp))
|
|
break;
|
|
offset+=SHD_BLOCK_LEN;
|
|
if(!c) i++;
|
|
else i=0;
|
|
if(i==blocks) {
|
|
offset-=(blocks*SHD_BLOCK_LEN);
|
|
break;
|
|
}
|
|
}
|
|
clearerr(smb->sha_fp);
|
|
fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET);
|
|
c=1;
|
|
for(l=0;l<blocks;l++)
|
|
if(!fwrite(&c,1,1,smb->sha_fp)) {
|
|
sprintf(smb->last_error,"writing allocation record");
|
|
return(-1L);
|
|
}
|
|
fflush(smb->sha_fp);
|
|
return(offset);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Allocates space for index, but doesn't search for unused blocks */
|
|
/* Returns -1L on error */
|
|
/****************************************************************************/
|
|
int32_t SMBCALL smb_fallochdr(smb_t* smb, uint32_t length)
|
|
{
|
|
uint8_t c = 1;
|
|
uint32_t l,blocks,offset;
|
|
|
|
if(smb->sha_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
blocks=smb_hdrblocks(length);
|
|
fflush(smb->sha_fp);
|
|
clearerr(smb->sha_fp);
|
|
fseek(smb->sha_fp,0L,SEEK_END);
|
|
offset=ftell(smb->sha_fp)*SHD_BLOCK_LEN;
|
|
for(l=0;l<blocks;l++)
|
|
if(!fwrite(&c,1,1,smb->sha_fp)) {
|
|
sprintf(smb->last_error,"writing allocation record");
|
|
return(-1L);
|
|
}
|
|
fflush(smb->sha_fp);
|
|
return(offset);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Allocate header blocks using Hyper Allocation */
|
|
/* this function should be most likely not be called from anywhere but */
|
|
/* smb_addmsghdr() */
|
|
/************************************************************************/
|
|
int32_t SMBCALL smb_hallochdr(smb_t* smb)
|
|
{
|
|
uint32_t l;
|
|
|
|
if(smb->shd_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
fflush(smb->shd_fp);
|
|
fseek(smb->shd_fp,0L,SEEK_END);
|
|
l=ftell(smb->shd_fp);
|
|
if(l<smb->status.header_offset) /* Header file truncated?!? */
|
|
return(smb->status.header_offset);
|
|
while((l-smb->status.header_offset)%SHD_BLOCK_LEN) /* Even block boundry */
|
|
l++;
|
|
return(l-smb->status.header_offset);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Allocate data blocks using Hyper Allocation */
|
|
/* smb_locksmbhdr() should be called before this function and not */
|
|
/* unlocked until all data fields for this message have been written */
|
|
/* to the SDT file */
|
|
/************************************************************************/
|
|
int32_t SMBCALL smb_hallocdat(smb_t* smb)
|
|
{
|
|
int32_t l;
|
|
|
|
if(smb->sdt_fp==NULL) {
|
|
sprintf(smb->last_error,"msgbase not open");
|
|
return(SMB_ERR_NOT_OPEN);
|
|
}
|
|
fflush(smb->sdt_fp);
|
|
fseek(smb->sdt_fp,0L,SEEK_END);
|
|
l=ftell(smb->sdt_fp);
|
|
if(l<=0)
|
|
return(l);
|
|
while(l%SDT_BLOCK_LEN) /* Make sure even block boundry */
|
|
l++;
|
|
return(l);
|
|
}
|
|
|
|
|
|
int SMBCALL smb_feof(FILE* fp)
|
|
{
|
|
return(feof(fp));
|
|
}
|
|
|
|
int SMBCALL smb_ferror(FILE* fp)
|
|
{
|
|
return(ferror(fp));
|
|
}
|
|
|
|
int SMBCALL smb_fflush(FILE* fp)
|
|
{
|
|
return(fflush(fp));
|
|
}
|
|
|
|
int SMBCALL smb_fgetc(FILE* fp)
|
|
{
|
|
return(fgetc(fp));
|
|
}
|
|
|
|
int SMBCALL smb_fputc(int ch, FILE* fp)
|
|
{
|
|
return(fputc(ch,fp));
|
|
}
|
|
|
|
int SMBCALL smb_fseek(FILE* fp, int32_t offset, int whence)
|
|
{
|
|
return(fseek(fp,offset,whence));
|
|
}
|
|
|
|
int32_t SMBCALL smb_ftell(FILE* fp)
|
|
{
|
|
return(ftell(fp));
|
|
}
|
|
|
|
int32_t SMBCALL smb_fgetlength(FILE* fp)
|
|
{
|
|
return(filelength(fileno(fp)));
|
|
}
|
|
|
|
int SMBCALL smb_fsetlength(FILE* fp, int32_t length)
|
|
{
|
|
return(chsize(fileno(fp),length));
|
|
}
|
|
|
|
void SMBCALL smb_rewind(FILE* fp)
|
|
{
|
|
rewind(fp);
|
|
}
|
|
|
|
void SMBCALL smb_clearerr(FILE* fp)
|
|
{
|
|
clearerr(fp);
|
|
}
|
|
|
|
int32_t SMBCALL smb_fread(void HUGE16* buf, int32_t bytes, FILE* fp)
|
|
{
|
|
#ifdef __FLAT__
|
|
return(fread(buf,1,bytes,fp));
|
|
#else
|
|
int32_t count;
|
|
|
|
for(count=bytes;count>0x7fff;count-=0x7fff,(char*)buf+=0x7fff)
|
|
if(fread((char*)buf,1,0x7fff,fp)!=0x7fff)
|
|
return(bytes-count);
|
|
if(fread((char*)buf,1,(size_t)count,fp)!=(size_t)count)
|
|
return(bytes-count);
|
|
return(bytes);
|
|
#endif
|
|
}
|
|
|
|
int32_t SMBCALL smb_fwrite(void HUGE16* buf, int32_t bytes, FILE* fp)
|
|
{
|
|
#ifdef __FLAT__
|
|
return(fwrite(buf,1,bytes,fp));
|
|
#else
|
|
int32_t count;
|
|
|
|
for(count=bytes;count>0x7fff;count-=0x7fff,(char*)buf+=0x7fff)
|
|
if(fwrite((char*)buf,1,0x7fff,fp)!=0x7fff)
|
|
return(bytes-count);
|
|
if(fwrite((char*)buf,1,(size_t)count,fp)!=(size_t)count)
|
|
return(bytes-count);
|
|
return(bytes);
|
|
#endif
|
|
}
|
|
|
|
/* End of SMBLIB.C */
|