// 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 #include #include // ------------------------------------------------------------------ // 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); }