1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
|
/***************************************************************************
* *
* Squish Developers Kit Source, Version 2.00 *
* Copyright 1989-1994 by SCI Communications. All rights reserved. *
* *
* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE *
* SQUISH DEVELOPERS KIT LICENSING AGREEMENT IN SQDEV.PRN. IF YOU DO NOT *
* FIND THE TEXT OF THIS AGREEMENT IN THE AFOREMENTIONED FILE, OR IF YOU *
* DO NOT HAVE THIS FILE, YOU SHOULD IMMEDIATELY CONTACT THE AUTHOR AT *
* ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT SHOULD YOU PROCEED TO *
* USE THIS FILE WITHOUT HAVING ACCEPTED THE TERMS OF THE SQUISH *
* DEVELOPERS KIT LICENSING AGREEMENT, OR SUCH OTHER AGREEMENT AS YOU ARE *
* ABLE TO REACH WITH THE AUTHOR. *
* *
* You can contact the author at one of the address listed below: *
* *
* Scott Dudley FidoNet 1:249/106 *
* 777 Downing St. Internet sjd@f106.n249.z1.fidonet.org *
* Kingston, Ont. CompuServe >INTERNET:sjd@f106.n249.z1.fidonet.org *
* Canada K7M 5N3 BBS 1-613-634-3058, V.32bis *
* *
***************************************************************************/
/*
#pragma off(unreferenced)
static char rcs_id[]="$Id: sq_write.c,v 1.13 2003/02/01 22:14:51 stas_degteff Exp $";
#pragma on(unreferenced)
*/
#define MSGAPI_HANDLERS
#define MSGAPI_NO_OLD_TYPES
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include "compiler.h"
#ifdef HAS_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAS_IO_H
# include <io.h>
#endif
#ifdef HAS_SHARE_H
#include <share.h>
#endif
#ifdef HAS_MALLOC_H
#include <malloc.h>
#endif
#include "prog.h"
#include "old_msg.h"
#include "msgapi.h"
#include "api_sq.h"
#include "api_sqp.h"
#include "apidebug.h"
#include "unused.h"
/* This function searches the list of free frames to find one which is *
* large enough to hold a message of size dwLen. *
* *
* This function assumes that we have exclusive access to the Squish base. */
static unsigned near _SquishProbeFreeChain(HAREA ha, dword dwLen, FOFS *pfo,
SQHDR *psqh, dword *pdwFrameLen)
{
FOFS foThis, foLast;
assert(Sqd->fHaveExclusive);
/* Assume that we haven't found anything */
*pfo=NULL_FRAME;
*pdwFrameLen=0L;
foLast=NULL_FRAME;
/* Look through all of the entries in the free chain */
for (foThis=Sqd->foFree;
foThis != NULL_FRAME;
foLast=foThis, foThis=psqh->next_frame)
{
/* Try to read the header at this point in the list */
if (!_SquishReadHdr(ha, foThis, psqh))
return FALSE;
/* Verify that this is a valid frame and that we aren't going around *
* in circles. */
if (psqh->frame_type != FRAME_FREE ||
foLast != psqh->prev_frame ||
psqh->next_frame==foThis)
{
msgapierr=MERR_BADF;
return FALSE;
}
/* If the frame is long enough, we can use it */
if (psqh->frame_length >= dwLen)
{
*pdwFrameLen=psqh->frame_length;
*pfo=foThis;
break;
}
}
return TRUE;
}
/* This function removes the frame at offset 'fo' from the free chain. *
* *
* This function assumes that we have exclusive access to the Squish base. */
static unsigned near _SquishRemoveFreeChain(HAREA ha, FOFS fo, SQHDR *psqh)
{
assert(Sqd->fHaveExclusive);
/* Validate that the frames which pretend to be list heads/tails are *
* actually what they seem. */
if ((psqh->prev_frame==NULL_FRAME && fo != Sqd->foFree) ||
(psqh->next_frame==NULL_FRAME && fo != Sqd->foLastFree))
{
msgapierr=MERR_BADF;
return FALSE;
}
/* If there is a frame before this one, set it to skip over this frame */
if (psqh->prev_frame)
if (!_SquishSetFrameNext(ha, psqh->prev_frame, psqh->next_frame))
return FALSE;
/* Do the same for the other side of the linked list */
if (psqh->next_frame)
if (!_SquishSetFramePrev(ha, psqh->next_frame, psqh->prev_frame))
return FALSE;
/* Now update the head and tail pointers for the free message list */
if (Sqd->foFree==fo)
Sqd->foFree=psqh->next_frame;
if (Sqd->foLastFree==fo)
Sqd->foLastFree=psqh->prev_frame;
return TRUE;
}
/* Allocate a frame of length dwLen at end-of-file, and store result in pfo.*
* *
* This function assumes that we have exclusive access to the Squish *
* base. */
static unsigned near _SquishGetFrameEOF(HAREA ha, FOFS *pfo, dword dwLen)
{
char nul=0;
long ofs;
assert(Sqd->fHaveExclusive);
/* Find the last byte that we will have to write for this frame, to *
* ensure that we have enough disk space to write this message. */
ofs=Sqd->foEnd + (long)Sqd->cbSqhdr + (long)dwLen - 1L;
/* Now try to write it, just to make sure... */
if (lseek(Sqd->sfd, ofs, SEEK_SET) != ofs ||
write(Sqd->sfd, &nul, 1) != 1)
{
msgapierr=MERR_NODS;
return FALSE;
}
/* We got it! So, update the frame offset, and modify the end-of-file *
* offset appropriately. */
*pfo=Sqd->foEnd;
Sqd->foEnd=ofs+1;
return TRUE;
}
/* This function searches the free chain to find a message of at least the *
* specified size. If that fails, we allocate a new frame at EOF. *
* *
* This function assumes that we have exclusive access to the Squish base. */
static unsigned near _SquishGetNewFrame(HMSG hmsg, dword dwLen, FOFS *pfoNew,
dword *pdwFrameLen)
{
SQHDR sqh;
FOFS fo;
assert(HSqd->fHaveExclusive);
/* Assume we got a new frame */
*pdwFrameLen=0L;
/* Check the free chain */
if (!_SquishProbeFreeChain(hmsg->ha, dwLen, &fo, &sqh, pdwFrameLen))
return FALSE;
/* If we got a frame from the free chain, remove it */
if (fo)
{
if (!_SquishRemoveFreeChain(hmsg->ha, fo, &sqh))
return FALSE;
*pfoNew=fo;
return TRUE;
}
/* Nothing in the free chain, so we will add a new frame at EOF, and *
* make it as long as necessary. */
*pdwFrameLen=0;
return _SquishGetFrameEOF(hmsg->ha, pfoNew, dwLen);
}
/* Given some blank space at offset hmsg->foWrite, we are to create a new *
* message frame there and link it into the message chain. If hmsg->foRead *
* is blank, just append the message to the end of the chain. However, *
* if foRead is NOT blank, we should set the new frame so that it will *
* appear between hmsg->sqhRead.prev and hmsg->sqhRead.next, as we are *
* overwriting an old message. *
* *
* At exit, the header that we just created will be left in hmsg->sqhWrite. *
* *
* This function assumes that we have exclusive access to the Squish base. */
static unsigned near _SquishLinkMessageFrame(HMSG hmsg, dword dwTotal,
dword dwCtrlLen, dword dwFrameLen)
{
assert(HSqd->fHaveExclusive);
assert(dwFrameLen==0 || dwFrameLen >= dwTotal);
/* Fill out default values for the frame header */
hmsg->sqhWrite.id=SQHDRID;
hmsg->sqhWrite.frame_length=dwFrameLen ? dwFrameLen : dwTotal;
hmsg->sqhWrite.msg_length=dwTotal;
hmsg->sqhWrite.clen=dwCtrlLen;
hmsg->sqhWrite.frame_type=FRAME_NORMAL;
hmsg->sqhWrite.rsvd=0;
/* If we have to link it into the middle of the base */
if (hmsg->foRead)
{
/* Set the links for our own frame */
hmsg->sqhWrite.prev_frame=hmsg->sqhRead.prev_frame;
hmsg->sqhWrite.next_frame=hmsg->sqhRead.next_frame;
/* Fix the link for the message after us, if any */
if (hmsg->sqhWrite.next_frame != NULL_FRAME)
{
if (!_SquishSetFramePrev(hmsg->ha, hmsg->sqhWrite.next_frame,
hmsg->foWrite))
{
return FALSE;
}
}
}
else
{
/* Append this frame at the end of the list */
hmsg->sqhWrite.prev_frame=HSqd->foLast;
hmsg->sqhWrite.next_frame=NULL_FRAME;
}
/* Set the links for the message before us */
if (hmsg->sqhWrite.prev_frame != NULL_FRAME)
{
if (!_SquishSetFrameNext(hmsg->ha, hmsg->sqhWrite.prev_frame,
hmsg->foWrite))
{
return FALSE;
}
}
/* If this has just become the head of this list, fix pointers... */
if (hmsg->sqhWrite.prev_frame==NULL_FRAME)
{
/* Sanity check: if we are becoming the beginning frame, we must *
* have either replaced the first message, or we are simply creating *
* the first message in a Squish base. */
assert(hmsg->foRead==HSqd->foFirst || HSqd->foFirst==NULL_FRAME);
HSqd->foFirst=hmsg->foWrite;
}
/* If this has just become the tail of the list, fix pointers... */
if (hmsg->sqhWrite.next_frame==NULL_FRAME)
{
/* Sanity check: if we are becoming the EOF frame, we must have *
* either added a new message, or replaced the old end-of-file message */
if (hmsg->foRead)
assert(hmsg->foRead==HSqd->foLast);
HSqd->foLast=hmsg->foWrite;
}
/* If we wrote the message before or after the lastread msg, update ptrs */
if (hmsg->dwMsg==hmsg->ha->cur_msg)
HSqd->foCur=hmsg->foWrite;
else if (hmsg->dwMsg==hmsg->ha->cur_msg+1)
HSqd->foNext=hmsg->foWrite;
else if (hmsg->dwMsg==hmsg->ha->cur_msg-1)
HSqd->foPrev=hmsg->foWrite;
/* Now update the frame for the message that we just wrote */
return _SquishWriteHdr(hmsg->ha, hmsg->foWrite, &hmsg->sqhWrite);
}
/* Find a frame within the Squish file for writing this message, then *
* allocate it. *
* *
* This function assumes that we have exclusive access to the Squish base. */
static unsigned near _SquishGetWriteFrame(HMSG hmsg, dword dwTxtTotal,
dword dwCtrlLen)
{
dword dwTotal=(dword)XMSG_SIZE+dwTxtTotal+dwCtrlLen;
dword dwFrameLen=0;
assert(HSqd->fHaveExclusive);
/* If we're writing over an existing message, verify that the *
* total and control lengths are not more than what we have already. */
if (hmsg->wMode==MOPEN_RW || hmsg->wMode==MOPEN_WRITE)
{
if (dwTotal > hmsg->sqhRead.msg_length)
{
msgapierr=MERR_TOOBIG;
return FALSE;
}
/* Copy the read-mode parameters, since we are now writing over this *
* message at the specified offset. */
hmsg->foWrite=hmsg->foRead;
hmsg->sqhWrite=hmsg->sqhRead;
}
else if (hmsg->wMode==MOPEN_CREATE)
{
/* First, if we are replacing an existing message, release its frame *
* to the free chain. */
if (hmsg->foRead)
{
if (! _SquishInsertFreeChain(hmsg->ha, hmsg->foRead, &hmsg->sqhRead))
return FALSE;
}
/* We are creating a new message, so we just have to find a frame *
* big enough to hold this message. */
if (! _SquishGetNewFrame(hmsg, dwTotal, &hmsg->foWrite, &dwFrameLen))
{
/* That failed, so we can't write the message. However, if we were *
* trying to replace an existing message, we have added that message *
* to the free chain, but we have NOT linked the other messages *
* to skip over it. The only recourse is to do the linking and *
* remove it from the index file (effectively deleting that message) */
if (hmsg->foRead)
{
/* Link the old messages over this one */
(void)_SquishSetFrameNext(hmsg->ha, hmsg->sqhRead.prev_frame,
hmsg->sqhRead.next_frame);
(void)_SquishSetFramePrev(hmsg->ha, hmsg->sqhRead.next_frame,
hmsg->sqhRead.prev_frame);
/* Now remove the old one from the index */
(void)_SquishRemoveIndexEntry(HSqd->hix, hmsg->dwMsg, NULL,
&hmsg->sqhRead, TRUE);
}
hmsg->foWrite=NULL_FRAME;
return FALSE;
}
/* Now link this new message frame into our list of messages to write */
if (!_SquishLinkMessageFrame(hmsg, dwTotal, dwCtrlLen, dwFrameLen))
{
hmsg->foWrite=NULL_FRAME;
return FALSE;
}
}
hmsg->dwWritePos=0L;
return TRUE;
}
/* Write the XMSG header to the Squish file */
static unsigned near _SquishWriteXmsg(HMSG hmsg, PXMSG pxm, dword *pdwOfs)
{
/* XMSG xmsg; */
#define xmsg (*pxm)
long ofs=hmsg->foWrite + HSqd->cbSqhdr;
/* If we don't know our UMSGID, retrieve it from the index file */
if (!hmsg->uidUs)
{
SQIDX sqi;
/*if (_SquishReadIndexRecord(hmsg->ha, hmsg->dwMsg, &sqi))*/
if (SidxGet(HSqd->hix, hmsg->dwMsg, &sqi))
hmsg->uidUs=sqi.umsgid;
}
/* Make local copy of XMSG struct */
/* OG: Wozu ? */
/* xmsg=*pxm; */
/* OG: Changes to make Squish 1.11 Y2K - experimental
Some stupid programs don't fill out the 'FTSC-Date' Field
*/
if (xmsg.date_written.date.yr > 19 ||
xmsg.__ftsc_date[0] == 0)
MsgCvtFTSCDateToBinary((char*)(xmsg.__ftsc_date), (union stamp_combo *)&xmsg.date_written);
/* KLUDGE: Store the UMSGID in the message header so that SQFIX can *
* use it to restore the index file, if necessary. However, if the *
* umsgid is not known, make sure that the MSGUID bit is not set. */
if (!hmsg->uidUs)
{
xmsg.attr &= ~MSGUID;
xmsg.umsgid=(UMSGID)0L;
}
else
{
xmsg.attr |= MSGUID;
xmsg.umsgid=hmsg->uidUs;
}
/* Write the message to disk */
if (ofs != (long)*pdwOfs)
if (lseek(HSqd->sfd, ofs, SEEK_SET) != ofs)
{
msgapierr=MERR_NODS;
return FALSE;
}
if (write_xmsg(HSqd->sfd, pxm) != 1)
{
msgapierr=MERR_NODS;
return FALSE;
}
*pdwOfs = (dword)ofs + (dword)XMSG_SIZE;
return TRUE;
#undef xmsg
}
/* Write the control information to the Squish file */
static unsigned near _SquishWriteCtrl(HMSG hmsg, byte *szCtrl,
dword dwCtrlLen, dword *pdwOfs)
{
long ofs;
/* We can only write control information on the first pass */
if (hmsg->fWritten)
return TRUE;
/* Make sure that the control information is not longer than
* what we wrote the first time, if we're updating a message.
*/
if (dwCtrlLen > hmsg->sqhWrite.clen)
dwCtrlLen=hmsg->sqhWrite.clen;
/* Make sure that we don't try to do a write with len==0 */
if (!dwCtrlLen)
return TRUE;
/* Now seek to the appropriate offset */
ofs=hmsg->foWrite + HSqd->cbSqhdr + XMSG_SIZE;
/* Write the control information at the appropriate offset */
if (ofs != (long)*pdwOfs)
if (lseek(HSqd->sfd, ofs, SEEK_SET) != ofs)
{
msgapierr=MERR_NODS;
return FALSE;
}
if (write(HSqd->sfd, (char *)szCtrl, (unsigned)dwCtrlLen) != (int)dwCtrlLen)
{
msgapierr=MERR_NODS;
return FALSE;
}
*pdwOfs=(dword)ofs + dwCtrlLen;
return TRUE;
}
/* Now write the message body, appending if necessary */
static unsigned near _SquishWriteTxt(HMSG hmsg, unsigned fAppend,
byte *szTxt, dword dwTxtLen,
dword *pdwOfs)
{
dword dwMaxWrite;
long ofs;
/* Figure out where to start writing text */
ofs=hmsg->foWrite + (long)HSqd->cbSqhdr + (long)XMSG_SIZE
+ (long)hmsg->sqhWrite.clen;
/* Figure out how much we can write, at most */
dwMaxWrite=hmsg->sqhWrite.msg_length - XMSG_SIZE - hmsg->sqhWrite.clen;
/* If we're appending to existing text, make sure that we adjust properly */
if (fAppend)
{
ofs += (long)hmsg->dwWritePos;
dwMaxWrite -= hmsg->dwWritePos;
}
dwMaxWrite=min(dwMaxWrite, dwTxtLen);
/* Now seek to the right spot and write the message text */
if (*pdwOfs != (dword)ofs)
if (lseek(HSqd->sfd, ofs, SEEK_SET) != ofs)
{
msgapierr=MERR_NODS;
return FALSE;
}
if (write(HSqd->sfd, (char *)szTxt, (unsigned)dwMaxWrite) != (int)dwMaxWrite)
{
msgapierr=MERR_NODS;
return FALSE;
}
*pdwOfs = (dword)ofs + dwMaxWrite;
/* Update the pointer in case we append to this msg in the future */
hmsg->dwWritePos += dwMaxWrite;
return TRUE;
}
/* Update the index at offset hmsg->dwMsg with the information given in *
* in the XMSG structure. */
static unsigned near _SquishUpdateIndex(HMSG hmsg, PXMSG pxm)
{
SQIDX sqi;
if (!SidxGet(HSqd->hix, hmsg->dwMsg, &sqi))
return FALSE;
/* Update this with the position of the message and the contents *
* of the 'To:' field. */
sqi.ofs=hmsg->foWrite;
sqi.hash=SquishHash(pxm->to);
/* If the message has been read, set the high bit of the hash */
if (pxm->attr & MSGREAD)
sqi.hash |= IDXE_MSGREAD;
return (unsigned)SidxPut(HSqd->hix, hmsg->dwMsg, &sqi);
}
/* Write a message to a Squish base */
sword _XPENTRY apiSquishWriteMsg(HMSG hmsg, word fAppend, PXMSG pxm,
byte *szTxt, dword dwTxtLen,
dword dwTxtTotal,
dword dwCtrlLen, byte *szCtrl)
{
dword dwOfs=(dword)-1L;
/* Make sure that we have appropriate access to this message */
if (MsgInvalidHmsg(hmsg) || !_SquishWriteMode(hmsg))
return -1;
/* Make sure that szTxt and szCtrl are consistent */
if (!dwTxtLen)
szTxt=NULL;
if (!dwCtrlLen)
szCtrl=NULL;
/* If we need to get a frame offset, allocate it here... */
if (!hmsg->foWrite)
{
unsigned rc;
/* We need to have an XMSG on the first write to any message */
if (!pxm)
{
msgapierr=MERR_BADA;
return -1;
}
if (! _SquishExclusiveBegin(hmsg->ha))
{
return -1;
}
rc=_SquishGetWriteFrame(hmsg, dwTxtTotal, dwCtrlLen);
if (! _SquishExclusiveEnd(hmsg->ha) || !rc)
{
return -1;
}
}
assert(hmsg->foWrite);
/* Now write the various bits of the message */
if (pxm)
if (!_SquishWriteXmsg(hmsg, pxm, &dwOfs))
{
return -1;
}
if (szCtrl)
if (!_SquishWriteCtrl(hmsg, szCtrl, dwCtrlLen, &dwOfs))
{
return -1;
}
if (szTxt)
if (!_SquishWriteTxt(hmsg, fAppend, szTxt, dwTxtLen, &dwOfs))
{
return -1;
}
hmsg->fWritten=TRUE;
/* If this was our first write to this message, update the index entry *
* appropriately. */
if (pxm)
if (! _SquishUpdateIndex(hmsg, pxm))
{
return -1;
}
return 0;
}
|