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.
deb-goldedplus/goldlib/gmb3/gmosmb3.cpp
2000-02-25 10:15:17 +00:00

1043 lines
29 KiB
C++

// This may look like C code, but it is really -*- C++ -*-
// ------------------------------------------------------------------
// The Goldware Library
// Copyright (C) 2000 Alexander S. Aganichev
// ------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ------------------------------------------------------------------
// $Id$
// ------------------------------------------------------------------
// Based on freeware sources from Digital Dynamics
// ------------------------------------------------------------------
// Synchronet message base
// ------------------------------------------------------------------
#include <cerrno>
#include <gmemdbg.h>
#include <gmosmb.h>
// ------------------------------------------------------------------
// Open a message base
// If retry_time is 0, fast open method (no compatibility/validity check)
// Opens files for READing messages or updating message indices only
int SMBArea::smb_open(int retry_time)
{
int file;
smbhdr_t hdr;
data->shd_fp = data->sdt_fp = data->sid_fp = NULL;
if ((data->shd_fp = fsopen(AddPath(path(), ".shd"), "rb+", WideSharemode)) == NULL)
return (2);
file = fileno(data->shd_fp);
if (retry_time && filelength(file) >= sizeof(smbhdr_t)) {
setvbuf(data->shd_fp, data->shd_buf, _IONBF, SHD_BLOCK_LEN);
if (smb_locksmbhdr(retry_time)) {
smb_close();
return (-1);
}
memset(&hdr, 0, sizeof(smbhdr_t));
fread(&hdr, sizeof(smbhdr_t), 1, data->shd_fp);
if (memcmp(hdr.id, "SMB\x1a", 4)) {
smb_close();
return (-2);
}
if (hdr.version < 0x110) { // Compatibility check
smb_close();
return (-3);
}
smb_unlocksmbhdr();
rewind(data->shd_fp);
}
if ((data->sdt_fp = fsopen(AddPath(path(), ".sdt"), "rb+", WideSharemode)) == NULL) {
smb_close();
return (1);
}
if ((data->sid_fp = fsopen(AddPath(path(), ".sid"), "rb+", WideSharemode)) == NULL) {
smb_close();
return (3);
}
return (0);
}
// ------------------------------------------------------------------
// Closes the currently open message base
void SMBArea::smb_close(void)
{
if (data->shd_fp != NULL) {
// In case it's been locked
smb_unlocksmbhdr();
fclose(data->shd_fp);
}
if (data->sid_fp != NULL)
fclose(data->sid_fp);
if (data->sdt_fp != NULL)
fclose(data->sdt_fp);
data->sid_fp = data->shd_fp = data->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 SMBArea::smb_open_da(int retry_time)
{
data->sda_fp = smb_openexlusively(AddPath(path(), ".sda"), retry_time);
return data->sda_fp == NULL ? 1 : 0;
}
// ------------------------------------------------------------------
// Opens the header block allocation table for message base 'smb_file'
// Retrys for retry_time number of seconds
// Return 0 on success, non-zero otherwise
int SMBArea::smb_open_ha(int retry_time)
{
data->sha_fp = smb_openexlusively(AddPath(path(), ".sha"), retry_time);
return data->sha_fp == NULL ? 1 : 0;
}
// ------------------------------------------------------------------
// Truncates header file
// Retrys for retry_time number of seconds
// Return 0 on success, non-zero otherwise
int SMBArea::smb_trunchdr(int retry_time)
{
long start;
start = time(NULL);
rewind(data->shd_fp);
while (1) {
if (not chsize(fileno(data->shd_fp), 0L))
break;
if (errno != EACCES)
return (-1);
if (time(NULL) - start >= retry_time) // Time-out
return (-2);
}
return (0);
}
// ------------------------------------------------------------------
// Message Base Header Functions
// ------------------------------------------------------------------
// Attempts for retry_time number of seconds to lock the message base hdr
int SMBArea::smb_locksmbhdr(int retry_time)
{
dword start;
if(WideCanLock) {
start = time(NULL);
while (1) {
if (not ::lock(fileno(data->shd_fp), 0L, sizeof(smbhdr_t) + sizeof(smbstatus_t)))
return (0);
if (time(NULL) - start >= retry_time)
break; // Incase we've already locked it
::unlock(fileno(data->shd_fp), 0L, sizeof(smbhdr_t) + sizeof(smbstatus_t));
}
return (-1);
}
return (0);
}
// ------------------------------------------------------------------
// Read the SMB header from the header file and place into "status"
int SMBArea::smb_getstatus(smbstatus_t *status)
{
int i;
clearerr(data->shd_fp);
fseek(data->shd_fp, sizeof(smbhdr_t), SEEK_SET);
i = fread(status, 1, sizeof(smbstatus_t), data->shd_fp);
if (i == sizeof(smbstatus_t))
return (0);
return (1);
}
// ------------------------------------------------------------------
// Writes message base header
int SMBArea::smb_putstatus(smbstatus_t status)
{
int i;
clearerr(data->shd_fp);
fseek(data->shd_fp, sizeof(smbhdr_t), SEEK_SET);
i = fwrite(&status, 1, sizeof(smbstatus_t), data->shd_fp);
fflush(data->shd_fp);
if (i == sizeof(smbstatus_t))
return (0);
return (1);
}
// ------------------------------------------------------------------
// Unlocks previously locks message base header
int SMBArea::smb_unlocksmbhdr()
{
if(not WideCanLock) return 0;
return (::unlock(fileno(data->shd_fp), 0L, sizeof(smbhdr_t) + sizeof(smbstatus_t)));
}
// ------------------------------------------------------------------
// Individual Message Functions
// ------------------------------------------------------------------
// Attempts for retry_time number of seconds to lock the header for 'msg'
int SMBArea::smb_lockmsghdr(smbmsg_t msg, int retry_time)
{
dword start;
if(WideCanLock) {
start = time(NULL);
while (1) {
if (not ::lock(fileno(data->shd_fp), msg.idx.offset, sizeof(msghdr_t)))
return (0);
if (time(NULL) - start >= retry_time)
break;
::unlock(fileno(data->shd_fp), msg.idx.offset, sizeof(msghdr_t));
}
return (-1);
}
return 0;
}
// ------------------------------------------------------------------
// 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 SMBArea::smb_getmsgidx(smbmsg_t *msg)
{
idxrec_t idx;
dword l, length, total, bot, top;
clearerr(data->sid_fp);
if (not msg->hdr.number) {
fseek(data->sid_fp, msg->offset * sizeof(idxrec_t), SEEK_SET);
if (not fread(&msg->idx, sizeof(idxrec_t), 1, data->sid_fp))
return (1);
return (0);
}
length = filelength(fileno(data->sid_fp));
if (not length)
return (1);
total = length / sizeof(idxrec_t);
if (not total)
return (1);
bot = 0;
top = total;
l = total / 2; // Start at middle index
while (1) {
fseek(data->sid_fp, l * sizeof(idxrec_t), SEEK_SET);
if (not fread(&idx, sizeof(idxrec_t), 1, data->sid_fp))
return (1);
if (bot == top - 1 and idx.number != 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 last index record in the open message base
int SMBArea::smb_getlastidx(idxrec_t *idx)
{
long length;
clearerr(data->sid_fp);
length = filelength(fileno(data->sid_fp));
if (length < sizeof(idxrec_t))
return (-1);
fseek(data->sid_fp, length - sizeof(idxrec_t), SEEK_SET);
if (not fread(idx, sizeof(idxrec_t), 1, data->sid_fp))
return (-2);
return (0);
}
// ------------------------------------------------------------------
// Figures out the total length of the header record for 'msg'
// Returns length
uint SMBArea::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
dword SMBArea::smb_getmsgdatlen(smbmsg_t msg)
{
int i;
dword 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 SMBArea::smb_getmsghdr(smbmsg_t *msg)
{
word i;
dword l, offset;
idxrec_t idx;
rewind(data->shd_fp);
fseek(data->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 (not fread(&msg->hdr, sizeof(msghdr_t), 1, data->shd_fp))
return (-1);
if (memcmp(msg->hdr.id, "SHD\x1a", 4))
return (-2);
if (msg->hdr.version < 0x110)
return (-9);
l = sizeof(msghdr_t);
msg->dfield = (dfield_t *)throw_xmalloc(msg->hdr.total_dfields*sizeof(dfield_t));
i = 0;
while (i < msg->hdr.total_dfields and l < msg->hdr.length) {
if (not fread(&msg->dfield[i], sizeof(dfield_t), 1, data->shd_fp)) {
smb_freemsgmem(*msg);
return (-4);
}
i++;
l += sizeof(dfield_t);
}
if (i < msg->hdr.total_dfields) {
smb_freemsgmem(*msg);
return (-8);
}
while (l < msg->hdr.length) {
i = msg->total_hfields++;
msg->hfield_dat = (void **)throw_xrealloc(msg->hfield_dat, msg->total_hfields*sizeof(void *));
msg->hfield = (hfield_t *)throw_xrealloc(msg->hfield, msg->total_hfields*sizeof(hfield_t));
if (not fread(&msg->hfield[i], sizeof(hfield_t), 1, data->shd_fp)) {
smb_freemsgmem(*msg);
return (-5);
}
l += sizeof(hfield_t);
msg->hfield_dat[i] = (char *)throw_xmalloc(msg->hfield[i].length + 1);
memset(msg->hfield_dat[i], 0, msg->hfield[i].length + 1); // init to NULL
if (msg->hfield[i].length and not fread(msg->hfield_dat[i], msg->hfield[i].length, 1, data->shd_fp)) {
smb_freemsgmem(*msg);
return (-6);
}
switch (msg->hfield[i].type) { // convenience variables
case SENDER:
if (not msg->from) {
msg->from = (uchar *)msg->hfield_dat[i];
break;
}
case FORWARDED: // fall through
msg->forwarded = 1;
break;
case SENDERAGENT:
if (not msg->forwarded)
msg->from_agent = *(word *)msg->hfield_dat[i];
break;
case SENDEREXT:
if (not msg->forwarded)
msg->from_ext = (uchar *)msg->hfield_dat[i];
break;
case SENDERNETTYPE:
if (not msg->forwarded)
msg->from_net.type = *(word *)msg->hfield_dat[i];
break;
case SENDERNETADDR:
if (not msg->forwarded)
msg->from_net.addr = (char *)msg->hfield_dat[i];
break;
case REPLYTO:
msg->replyto = (uchar *)msg->hfield_dat[i];
break;
case REPLYTOEXT:
msg->replyto_ext = (uchar *)msg->hfield_dat[i];
break;
case REPLYTOAGENT:
msg->replyto_agent = *(word *)msg->hfield_dat[i];
break;
case REPLYTONETTYPE:
msg->replyto_net.type = *(word *)msg->hfield_dat[i];
break;
case REPLYTONETADDR:
msg->replyto_net.addr = (char *)msg->hfield_dat[i];
break;
case RECIPIENT:
msg->to = (uchar *)msg->hfield_dat[i];
break;
case RECIPIENTEXT:
msg->to_ext = (uchar *)msg->hfield_dat[i];
break;
case RECIPIENTAGENT:
msg->to_agent = *(word *)msg->hfield_dat[i];
break;
case RECIPIENTNETTYPE:
msg->to_net.type = *(word *)msg->hfield_dat[i];
break;
case RECIPIENTNETADDR:
msg->to_net.addr = (char *)msg->hfield_dat[i];
break;
case SUBJECT:
msg->subj = (uchar *)msg->hfield_dat[i];
break;
}
l += msg->hfield[i].length;
}
if (not msg->from or not msg->to or not msg->subj) {
smb_freemsgmem(*msg);
return (-7);
}
return (0);
}
// ------------------------------------------------------------------
// Frees memory allocated for 'msg'
void SMBArea::smb_freemsgmem(smbmsg_t msg)
{
word i;
throw_xfree(msg.dfield);
for (i = 0; i < msg.total_hfields; i++)
throw_xfree(msg.hfield_dat[i]);
throw_xfree(msg.hfield);
throw_xfree(msg.hfield_dat);
}
// ------------------------------------------------------------------
// Unlocks header for 'msg'
int SMBArea::smb_unlockmsghdr(smbmsg_t msg)
{
if(not WideCanLock) return 0;
return (::unlock(fileno(data->shd_fp), msg.idx.offset, sizeof(msghdr_t)));
}
// ------------------------------------------------------------------
// Adds a header field to the 'msg' structure (in memory only)
int SMBArea::smb_hfield(smbmsg_t * msg, word type, word length, void *data)
{
int i;
i = msg->total_hfields;
msg->hfield = (hfield_t *)throw_xrealloc(msg->hfield, (i+1)*sizeof(hfield_t));
msg->hfield_dat = (void **)throw_xrealloc(msg->hfield_dat, (i+1)*sizeof(void *));
msg->total_hfields++;
msg->hfield[i].type = type;
msg->hfield[i].length = length;
if (length) {
msg->hfield_dat[i] = (void *)throw_xmalloc(length);
memcpy(msg->hfield_dat[i], data, length);
} else
msg->hfield_dat[i] = NULL;
return (0);
}
// ------------------------------------------------------------------
// 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 SMBArea::smb_dfield(smbmsg_t * msg, word type, dword length)
{
int i, j;
i = msg->hdr.total_dfields;
msg->dfield = (dfield_t *)throw_xrealloc(msg->dfield, (i+1)*sizeof(dfield_t));
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 SMBArea::smb_addcrc(dword max_crcs, dword crc, int retry_time)
{
int file;
long length;
dword l, *buf;
if (not max_crcs)
return (0);
file = smb_openexlusively2(AddPath(path(), ".sch"), retry_time);
length = filelength(file);
if (length < 0L) {
::close(file);
return (-4);
}
buf = (dword *)throw_xmalloc(max_crcs * sizeof(dword));
if (length >= max_crcs * 4) { // Reached or exceeds max crcs
read(file, buf, max_crcs * 4);
for (l = 0; l < max_crcs; l++)
if (crc == buf[l])
break;
if (l < max_crcs) { // Dupe CRC found
::close(file);
throw_xfree(buf);
return (1);
}
chsize(file, 0L); // truncate it
lseek(file, 0L, SEEK_SET);
write(file, buf + 4, (max_crcs - 1) * 4);
} else if (length / 4) { // Less than max crcs
read(file, buf, length);
for (l = 0; l < length / 4; l++)
if (crc == buf[l])
break;
if (l < length / 4) { // Dupe CRC found
::close(file);
throw_xfree(buf);
return (1);
}
}
lseek(file, 0L, SEEK_END);
write(file, &crc, 4); // Write to the end
throw_xfree(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)
int SMBArea::smb_addmsghdr(smbmsg_t * msg, smbstatus_t * status, int storage, int retry_time)
{
int i;
long l;
if (smb_locksmbhdr(retry_time))
return (1);
if (smb_getstatus(status))
return (2);
if (storage != SMB_HYPERALLOC and (i = smb_open_ha(retry_time)) != 0)
return (i);
msg->hdr.length = smb_getmsghdrlen(*msg);
if (storage == SMB_HYPERALLOC)
l = smb_hallochdr(status->header_offset);
else if (storage == SMB_FASTALLOC)
l = smb_fallochdr(msg->hdr.length);
else
l = smb_allochdr(msg->hdr.length);
if (l == -1L) {
smb_unlocksmbhdr();
fclose(data->sha_fp);
return (-1);
}
status->last_msg++;
msg->idx.number = msg->hdr.number = status->last_msg;
msg->idx.offset = status->header_offset + l;
msg->idx.time = msg->hdr.when_imported.time;
msg->idx.attr = msg->hdr.attr;
msg->offset = status->total_msgs;
status->total_msgs++;
smb_putstatus(*status);
if (storage != SMB_HYPERALLOC)
fclose(data->sha_fp);
i = smb_putmsg(*msg);
smb_unlocksmbhdr();
return (i);
}
// ------------------------------------------------------------------
// Writes both header and index information for msg 'msg'
int SMBArea::smb_putmsg(smbmsg_t msg)
{
int i;
i = smb_putmsghdr(msg);
if (i)
return (i);
return (smb_putmsgidx(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 SMBArea::smb_putmsgidx(smbmsg_t msg)
{
clearerr(data->sid_fp);
fseek(data->sid_fp, msg.offset * sizeof(idxrec_t), SEEK_SET);
if (not fwrite(&msg.idx, sizeof(idxrec_t), 1, data->sid_fp))
return (1);
fflush(data->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 SMBArea::smb_putmsghdr(smbmsg_t msg)
{
word i;
dword l;
clearerr(data->shd_fp);
if (fseek(data->shd_fp, msg.idx.offset, SEEK_SET))
return (-1);
// Write the fixed portion of the header record
if (not fwrite(&msg.hdr, sizeof(msghdr_t), 1, data->shd_fp))
return (-2);
// Write the data fields (each is fixed length)
for (i = 0; i < msg.hdr.total_dfields; i++)
if (not fwrite(&msg.dfield[i], sizeof(dfield_t), 1, data->shd_fp))
return (-3);
// Write the variable length header fields
for (i = 0; i < msg.total_hfields; i++) {
if (not fwrite(&msg.hfield[i], sizeof(hfield_t), 1, data->shd_fp))
return (-4);
if (msg.hfield[i].length and not fwrite(msg.hfield_dat[i], msg.hfield[i].length, 1, data->shd_fp))
return (-5);
}
l = smb_getmsghdrlen(msg);
while (l % SHD_BLOCK_LEN) {
if (fputc(0, data->shd_fp) == EOF) // pad block with NULL
return (-6);
l++;
}
fflush(data->shd_fp);
return (0);
}
// ------------------------------------------------------------------
// Creates a sub-board's initial header file
// Truncates and deletes other associated SMB files
int SMBArea::smb_create(dword max_crcs, dword max_msgs, word max_age, word attr, int retry_time)
{
smbhdr_t hdr;
smbstatus_t status;
if (filelength(fileno(data->shd_fp)) >= sizeof(smbhdr_t) + sizeof(smbstatus_t)
and smb_locksmbhdr(retry_time)) // header exists, so lock it
return (1);
memset(&hdr, 0, sizeof(smbhdr_t));
memset(&status, 0, sizeof(smbstatus_t));
memcpy(hdr.id, "SMB\x1a", 4);
hdr.version = SMB_VERSION;
hdr.length = sizeof(smbhdr_t) + sizeof(smbstatus_t);
status.last_msg = status.total_msgs = 0;
status.header_offset = sizeof(smbhdr_t) + sizeof(smbstatus_t);
status.max_crcs = max_crcs;
status.max_msgs = max_msgs;
status.max_age = max_age;
status.attr = attr;
rewind(data->shd_fp);
fwrite(&hdr, 1, sizeof(smbhdr_t), data->shd_fp);
fwrite(&status, 1, sizeof(smbstatus_t), data->shd_fp);
rewind(data->shd_fp);
chsize(fileno(data->shd_fp), sizeof(smbhdr_t) + sizeof(smbstatus_t));
fflush(data->shd_fp);
rewind(data->sdt_fp);
chsize(fileno(data->sdt_fp), 0L);
rewind(data->sid_fp);
chsize(fileno(data->sid_fp), 0L);
remove(AddPath(path(), ".sda")); // if it exists, delete it
remove(AddPath(path(), ".sha")); // if it exists, delete it
remove(AddPath(path(), ".sch"));
smb_unlocksmbhdr();
return (0);
}
// ------------------------------------------------------------------
// Returns number of data blocks required to store "length" amount of data
dword SMBArea::smb_datblocks(dword length)
{
dword 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
dword SMBArea::smb_hdrblocks(dword length)
{
dword 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
// fclose(data->sda_fp) should be called after
// Returns negative on error
long SMBArea::smb_allocdat(dword length, word headers)
{
word i, j;
dword l, blocks, offset = 0L;
blocks = smb_datblocks(length);
j = 0; // j is consecutive unused block counter
fflush(data->sda_fp);
rewind(data->sda_fp);
while (not feof(data->sda_fp)) {
if (not fread(&i, 2, 1, data->sda_fp))
break;
offset += SDT_BLOCK_LEN;
if (not i)
j++;
else
j = 0;
if (j == blocks) {
offset -= (blocks * SDT_BLOCK_LEN);
break;
}
}
clearerr(data->sda_fp);
fseek(data->sda_fp, (offset / SDT_BLOCK_LEN) * 2L, SEEK_SET);
for (l = 0; l < blocks; l++)
if (not fwrite(&headers, 2, 1, data->sda_fp))
return (-1);
fflush(data->sda_fp);
return (offset);
}
// ------------------------------------------------------------------
// Allocates space for data, but doesn't search for unused blocks
// Returns negative on error
long SMBArea::smb_fallocdat(dword length, word headers)
{
dword l, blocks, offset;
fflush(data->sda_fp);
clearerr(data->sda_fp);
blocks = smb_datblocks(length);
fseek(data->sda_fp, 0L, SEEK_END);
offset = (ftell(data->sda_fp) / 2L) * SDT_BLOCK_LEN;
for (l = 0; l < blocks; l++)
if (not fwrite(&headers, 2, 1, data->sda_fp))
break;
fflush(data->sda_fp);
if (l < blocks)
return (-1L);
return (offset);
}
// ------------------------------------------------------------------
// De-allocates space for data
// Returns non-zero on error
int SMBArea::smb_freemsgdat(dword offset, dword length, word headers)
{
word i;
dword l, blocks;
blocks = smb_datblocks(length);
clearerr(data->sda_fp);
for (l = 0; l < blocks; l++) {
if (fseek(data->sda_fp, ((offset / SDT_BLOCK_LEN) + l) * 2L, SEEK_SET))
return (1);
if (not fread(&i, 2, 1, data->sda_fp))
return (2);
if (headers > i)
i = 0; // don't want to go negative
else
i -= headers;
if (fseek(data->sda_fp, -2L, SEEK_CUR))
return (3);
if (not fwrite(&i, 2, 1, data->sda_fp))
return (4);
}
fflush(data->sda_fp);
return (0);
}
// ------------------------------------------------------------------
// Adds to data allocation records for blocks starting at 'offset'
// Returns non-zero on error
int SMBArea::smb_incdat(dword offset, dword length, word headers)
{
word i;
dword l, blocks;
clearerr(data->sda_fp);
blocks = smb_datblocks(length);
for (l = 0; l < blocks; l++) {
fseek(data->sda_fp, ((offset / SDT_BLOCK_LEN) + l) * 2L, SEEK_SET);
if (not fread(&i, 2, 1, data->sda_fp))
return (1);
i += headers;
fseek(data->sda_fp, -2L, SEEK_CUR);
if (not fwrite(&i, 2, 1, data->sda_fp))
return (2);
}
fflush(data->sda_fp);
return (0);
}
// ------------------------------------------------------------------
// De-allocates blocks for header record
// Returns non-zero on error
int SMBArea::smb_freemsghdr(dword offset, dword length)
{
uchar c = 0;
dword l, blocks;
clearerr(data->sha_fp);
blocks = smb_hdrblocks(length);
fseek(data->sha_fp, offset / SHD_BLOCK_LEN, SEEK_SET);
for (l = 0; l < blocks; l++)
if (not fwrite(&c, 1, 1, data->sha_fp))
return (1);
fflush(data->sha_fp);
return (0);
}
// ------------------------------------------------------------------
// Frees all allocated header and data blocks for 'msg'
int SMBArea::smb_freemsg(smbmsg_t msg, smbstatus_t status)
{
int i;
word x;
if (status.attr & SMB_HYPERALLOC)
return (0); // Nothing to do
for (x = 0; x < msg.hdr.total_dfields; x++) {
if ((i = smb_freemsgdat(msg.hdr.offset + msg.dfield[x].offset, msg.dfield[x].length, 1)) != 0)
return (i);
}
return (smb_freemsghdr(msg.idx.offset - 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
// fclose(data->sha_fp) should be called after
// Returns -1L on error
long SMBArea::smb_allochdr(dword length)
{
uchar c;
word i;
dword l, blocks, offset = 0;
blocks = smb_hdrblocks(length);
i = 0; // i is consecutive unused block counter
fflush(data->sha_fp);
rewind(data->sha_fp);
while (not feof(data->sha_fp)) {
if (not fread(&c, 1, 1, data->sha_fp))
break;
offset += SHD_BLOCK_LEN;
if (not c)
i++;
else
i = 0;
if (i == blocks) {
offset -= (blocks * SHD_BLOCK_LEN);
break;
}
}
clearerr(data->sha_fp);
fseek(data->sha_fp, offset / SHD_BLOCK_LEN, SEEK_SET);
c = 1;
for (l = 0; l < blocks; l++)
if (not fwrite(&c, 1, 1, data->sha_fp))
return (-1L);
fflush(data->sha_fp);
return (offset);
}
// ------------------------------------------------------------------
// Allocates space for index, but doesn't search for unused blocks
// Returns -1L on error
long SMBArea::smb_fallochdr(dword length)
{
uchar c = 1;
dword l, blocks, offset;
blocks = smb_hdrblocks(length);
fflush(data->sha_fp);
clearerr(data->sha_fp);
fseek(data->sha_fp, 0L, SEEK_END);
offset = ftell(data->sha_fp) * SHD_BLOCK_LEN;
for (l = 0; l < blocks; l++)
if (not fwrite(&c, 1, 1, data->sha_fp))
return (-1L);
fflush(data->sha_fp);
return (offset);
}
// ------------------------------------------------------------------
// Allocate header blocks using Hyper Allocation
// this function should be most likely not be called from anywhere but
// smb_addmsghdr()
long SMBArea::smb_hallochdr(dword header_offset)
{
long l;
fflush(data->shd_fp);
fseek(data->shd_fp, 0L, SEEK_END);
l = ftell(data->shd_fp);
if (l < header_offset) // Header file truncated?!?
return (header_offset);
while ((l - header_offset) % SHD_BLOCK_LEN) // Make sure even block boundry
l++;
return (l - 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
long SMBArea::smb_hallocdat()
{
long l;
fflush(data->sdt_fp);
fseek(data->sdt_fp, 0L, SEEK_END);
l = ftell(data->sdt_fp);
if (l <= 0)
return (l);
while (l % SDT_BLOCK_LEN) // Make sure even block boundry
l++;
return (l);
}