1 /***************************************************************************
2 * *
3 * Squish Developers Kit Source, Version 2.00 *
4 * Copyright 1989-1994 by SCI Communications. All rights reserved. *
5 * *
6 * USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE *
7 * SQUISH DEVELOPERS KIT LICENSING AGREEMENT IN SQDEV.PRN. IF YOU DO NOT *
8 * FIND THE TEXT OF THIS AGREEMENT IN THE AFOREMENTIONED FILE, OR IF YOU *
9 * DO NOT HAVE THIS FILE, YOU SHOULD IMMEDIATELY CONTACT THE AUTHOR AT *
10 * ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT SHOULD YOU PROCEED TO *
11 * USE THIS FILE WITHOUT HAVING ACCEPTED THE TERMS OF THE SQUISH *
12 * DEVELOPERS KIT LICENSING AGREEMENT, OR SUCH OTHER AGREEMENT AS YOU ARE *
13 * ABLE TO REACH WITH THE AUTHOR. *
14 * *
15 * You can contact the author at one of the address listed below: *
16 * *
17 * Scott Dudley FidoNet 1:249/106 *
18 * 777 Downing St. Internet sjd@f106.n249.z1.fidonet.org *
19 * Kingston, Ont. CompuServe >INTERNET:sjd@f106.n249.z1.fidonet.org *
20 * Canada K7M 5N3 BBS 1-613-634-3058, V.32bis *
21 * *
22 ***************************************************************************/
23 /*
24 #pragma off(unreferenced)
25 static char rcs_id[]="$Id$";
26 #pragma on(unreferenced)
27 */
28 #define MSGAPI_HANDLERS
29 #define MSGAPI_NO_OLD_TYPES
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <string.h>
37 #include <limits.h>
38
39 #include <huskylib/compiler.h>
40
41 #ifdef HAS_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #ifdef HAS_IO_H
45 # include <io.h>
46 #endif
47 #ifdef HAS_SHARE_H
48 #include <share.h>
49 #endif
50 #ifdef HAS_MALLOC_H
51 #include <malloc.h>
52 #endif
53
54 #include <huskylib/huskylib.h>
55
56 /* Swith for build DLL */
57 #define DLLEXPORT
58 #include <huskylib/huskyext.h>
59
60 #include "old_msg.h"
61 #include "msgapi.h"
62 #include "api_sq.h"
63 #include "api_sqp.h"
64 #include "apidebug.h"
65
66 #define HixSqd ((struct _sqdata *)(hix)->ha->apidata)
67
68
69 #ifdef __FLAT__
70 #define MORE_SPACE 256 /* Allow for up to 256 additions */
71 #define SEGMENT_SIZE (MAX_hSINT32/(hSINT32)SQIDX_SIZE)
72 #define SHIFT_SIZE 32768
73 #else
74 #define MORE_SPACE 16 /* Allow for up to 16 additions */
75 #define SEGMENT_SIZE (32767L/(hSINT32)SQIDX_SIZE)
76 #define SHIFT_SIZE 8192
77 #endif
78
79 #define fmemmove memmove
80
81 /* Open the index file and read the index for this area */
82
_SquishOpenIndex(HAREA ha)83 HIDX _SquishOpenIndex(HAREA ha)
84 {
85 HIDX hix;
86
87 hix=palloc(sizeof(*hix));
88 if (hix==NULL)
89 {
90 msgapierr=MERR_NOMEM;
91 return NULL;
92 }
93
94 /* Store the current area handle */
95
96 hix->id=ID_HIDX;
97 hix->ha=ha;
98 hix->lDeltaLo=-1;
99 hix->lDeltaHi=-1;
100 hix->cSeg=0;
101 hix->fBuffer=0;
102
103 return hix;
104 }
105
106
107 /* This function returns the size of the virtual index */
108
_SquishIndexSize(HIDX hix)109 dword _SquishIndexSize(HIDX hix)
110 {
111 dword lSize;
112 int i;
113
114 assert(hix->id==ID_HIDX);
115
116 if (!hix->fBuffer)
117 lSize=(dword)lseek(HixSqd->ifd, 0L, SEEK_END);
118 else
119 {
120 for (i=0, lSize=0; i < hix->cSeg; i++)
121 lSize += hix->pss[i].dwUsed * (dword)SQIDX_SIZE;
122 }
123
124 return lSize;
125 }
126
127
128
129 /* Start buffering reads/writes to the index file */
130
_SquishBeginBuffer(HIDX hix)131 int _SquishBeginBuffer(HIDX hix)
132 {
133 dword dwMsgs;
134 int i;
135
136 assert(hix->id==ID_HIDX);
137
138 /* Multiple buffers are ok, but we only need to do it once */
139
140 if (hix->fBuffer++ != 0)
141 return TRUE;
142
143 hix->cSeg=(int)(hix->ha->num_msg / SEGMENT_SIZE) + 1;
144
145 /* Allocate memory for the array of segments */
146
147 hix->pss=palloc(sizeof(SQIDXSEG) * (unsigned)hix->cSeg);
148 if (hix->pss==NULL)
149 {
150 msgapierr=MERR_NOMEM;
151 hix->fBuffer=0;
152 return FALSE;
153 }
154 dwMsgs=hix->ha->num_msg; /* Read all messages into memory */
155 /* Find out how many records are in the file */
156
157 hix->lAllocatedRecords=lseek(HixSqd->ifd, 0L, SEEK_END);
158 if (hix->lAllocatedRecords < 0)
159 {
160 msgapierr=MERR_BADF;
161 hix->fBuffer=0;
162 return FALSE;
163 }
164 /* Find out the number of records, not the number of bytes */
165
166 hix->lAllocatedRecords /= SQIDX_SIZE;
167
168
169 /* Read from head of index file */
170
171 (void)lseek(HixSqd->ifd, 0L, SEEK_SET);
172
173 /* Repeat for each segment in the index file */
174
175 for (i=0; i < hix->cSeg; i++)
176 {
177 dword dwSize=min(dwMsgs+MORE_SPACE, (long)SEGMENT_SIZE);
178
179 /* Try to allocate memory for this segment */
180
181 hix->pss[i].psqi=farpalloc((size_t)dwSize * (size_t)sizeof(SQIDX));
182 if (hix->pss[i].psqi==NULL)
183 {
184 while (i--)
185 farpfree(hix->pss[i].psqi);
186
187 pfree(hix->pss);
188
189 msgapierr=MERR_NOMEM;
190 hix->fBuffer=0;
191 return FALSE;
192 }
193
194 hix->pss[i].dwMax=dwSize;
195
196 /* Now read in the messages for this segment */
197
198 dwSize=min(dwMsgs, SEGMENT_SIZE);
199
200 if (read_sqidx(HixSqd->ifd, hix->pss[i].psqi, dwSize) != 1)
201 {
202
203 do
204 {
205 farpfree(hix->pss[i].psqi);
206 }
207 while (i--);
208
209 pfree(hix->pss);
210
211 msgapierr=MERR_BADF;
212 hix->fBuffer=0;
213 return FALSE;
214 }
215
216 /* Decrement the count for msgs in the next segment, if necessary */
217
218 if (dwSize != SEGMENT_SIZE)
219 dwMsgs=0;
220 else
221 dwMsgs -= SEGMENT_SIZE;
222
223
224 hix->pss[i].dwUsed=dwSize;
225 }
226
227 /* Now we have the whole file in memory */
228
229 return TRUE;
230 }
231
232
233 /* Return a pointer to the 'dwMsg'th message in the buffered index */
234
sidx(HIDX hix,dword dwMsg)235 static SQIDX far *sidx(HIDX hix, dword dwMsg)
236 {
237 dword dwStart=1L;
238 int i;
239
240 for (i=0; i < hix->cSeg; i++)
241 {
242 if (dwMsg >= dwStart && dwMsg < dwStart + hix->pss[i].dwUsed)
243 return hix->pss[i].psqi + (size_t)(dwMsg - dwStart);
244
245 dwStart += hix->pss[i].dwUsed;
246 }
247
248 return NULL;
249 }
250
251
252 /* Get an index from the virtual index file */
253
SidxGet(HIDX hix,dword dwMsg,SQIDX * psqi)254 int SidxGet(HIDX hix, dword dwMsg, SQIDX *psqi)
255 {
256 SQIDX far *psqiFound;
257
258 assert(hix->id==ID_HIDX);
259
260 if (!hix->fBuffer)
261 {
262 (void)lseek(HixSqd->ifd, (long)(dwMsg-1) * (long)SQIDX_SIZE, SEEK_SET);
263
264 if (read_sqidx(HixSqd->ifd, psqi, 1) != 1)
265 {
266 msgapierr=MERR_BADF;
267 return FALSE;
268 }
269
270 return TRUE;
271 }
272
273 psqiFound=sidx(hix, dwMsg);
274
275 if (!psqiFound)
276 return FALSE;
277
278 *psqi=*psqiFound;
279 return TRUE;
280 }
281
282
283
284
285 /* Add a new index record to the end of the array */
286
_SquishAppendIndexRecord(HIDX hix,SQIDX * psqi)287 static int near _SquishAppendIndexRecord(HIDX hix, SQIDX *psqi)
288 {
289 SQIDXSEG *pss;
290
291
292 /* If we need to expand the index file on disk, do so now */
293
294 if ((long)hix->ha->num_msg > hix->lAllocatedRecords)
295 {
296 long lSize;
297 SQIDX sqi;
298
299 /* Make room for up to 64 new records */
300
301 hix->lAllocatedRecords=hix->ha->num_msg+64;
302 lSize=(hix->lAllocatedRecords-1) * (long)SQIDX_SIZE;
303
304 sqi.ofs=0L;
305 sqi.umsgid=(UMSGID)-1L;
306 sqi.hash=(UMSGID)-1L;
307
308 /* Write a blank index entry at the appropriate location to fill *
309 * up the file. */
310
311 if (lseek(HixSqd->ifd, lSize, SEEK_SET) != lSize ||
312 write_sqidx(HixSqd->ifd, &sqi, 1) != 1)
313 {
314 msgapierr=MERR_NODS;
315 return FALSE;
316 }
317 }
318
319 /* If we already have some segments... */
320
321 if (hix->cSeg)
322 {
323 /* Add to an existing segment */
324
325 pss=hix->pss + hix->cSeg-1;
326
327 /* If the record fits within this segment, just append it. */
328
329 if (pss->dwUsed < pss->dwMax)
330 {
331 pss->psqi[(size_t)pss->dwUsed]=*psqi;
332 pss->dwUsed++;
333 return TRUE;
334 }
335
336 /* If we can expand this segment by reallocating memory... */
337
338 if (pss->dwMax < SEGMENT_SIZE)
339 {
340 SQIDX far *psqiNew;
341
342 assert(pss->dwMax >= pss->dwUsed);
343
344 /* Don't use realloc because we cannot afford to lose the info that we *
345 * already have! */
346
347 psqiNew=farpalloc(((size_t)pss->dwMax + MORE_SPACE) * SQIDX_SIZE);
348 if (psqiNew==NULL)
349 {
350 msgapierr=MERR_NOMEM;
351 return FALSE;
352 }
353
354 (void) fmemmove(psqiNew,
355 pss->psqi,
356 (size_t)pss->dwUsed * (size_t)SQIDX_SIZE);
357
358 psqiNew[(size_t)pss->dwUsed]=*psqi;
359
360 pss->dwUsed++;
361 pss->dwMax += MORE_SPACE;
362
363 farpfree(pss->psqi);
364 pss->psqi=psqiNew;
365 return TRUE;
366 }
367 }
368
369
370 /* If we arrived here, we either have no segments, or all of our *
371 * existing segments are full. To handle this, we need to reallocate *
372 * the array of pointers to segments and add a new one. */
373
374 pss=palloc(sizeof(SQIDXSEG) * (size_t)(hix->cSeg+1));
375 if (pss==NULL)
376 {
377 msgapierr=MERR_NOMEM;
378 return FALSE;
379 }
380
381 (void)memmove(pss, hix->pss, (size_t)hix->cSeg * sizeof(SQIDXSEG));
382 pfree(hix->pss);
383 hix->pss=pss;
384
385 /* Allocate memory for the new segment */
386
387 hix->pss[hix->cSeg].psqi=farpalloc(MORE_SPACE * SQIDX_SIZE);
388 if (hix->pss[hix->cSeg].psqi==NULL)
389 {
390 msgapierr=MERR_NOMEM;
391 return FALSE;
392 }
393
394 pss=hix->pss + hix->cSeg;
395
396 /* Add the specified record to our indices */
397
398 pss->dwUsed=1;
399 pss->dwMax=MORE_SPACE;
400 *pss->psqi=*psqi;
401
402 /* Increment the segment count */
403
404 hix->cSeg++;
405 return TRUE;
406 }
407
408
409 /* Store an index entry in the virtual index file */
410
SidxPut(HIDX hix,dword dwMsg,SQIDX * psqi)411 int SidxPut(HIDX hix, dword dwMsg, SQIDX *psqi)
412 {
413 SQIDX far *psqiFound;
414 int rc;
415
416 assert(hix->id==ID_HIDX);
417
418 if (!hix->fBuffer)
419 {
420 (void)lseek(HixSqd->ifd, (long)(dwMsg-1) * (long)SQIDX_SIZE, SEEK_SET);
421
422 if (write_sqidx(HixSqd->ifd, psqi, 1) != 1)
423 {
424 msgapierr=MERR_NODS;
425 return FALSE;
426 }
427
428 return TRUE;
429 }
430
431 /* If we can't find the appropriate index record */
432
433 psqiFound=sidx(hix, dwMsg);
434 if (psqiFound==NULL)
435 {
436 rc=FALSE;
437
438 /* If the index is out of range, only create a new record if it's *
439 * to be placed at EOF. */
440
441 if (dwMsg==hix->ha->num_msg+1)
442 rc=_SquishAppendIndexRecord(hix, psqi);
443 }
444 else
445 {
446 *psqiFound=*psqi;
447 rc=TRUE;
448 }
449
450 if (rc)
451 {
452 if (hix->lDeltaLo==-1 || hix->lDeltaLo > (long)dwMsg)
453 hix->lDeltaLo=(long)dwMsg;
454
455 if (hix->lDeltaHi==-1 || hix->lDeltaHi < (long)dwMsg)
456 hix->lDeltaHi=(long)dwMsg;
457 }
458
459 return rc;
460 }
461
462
463 /* Delete an entry from the index */
464
_SquishRemoveIndexEntry(HIDX hix,dword dwMsg,SQIDX * psqiOut,SQHDR * psqh,int fFixPointers)465 unsigned _SquishRemoveIndexEntry(HIDX hix, dword dwMsg, SQIDX *psqiOut,
466 SQHDR *psqh, int fFixPointers)
467 {
468 SQIDX sqi;
469 char *pcBuf;
470 int got, i;
471
472 assert(hix->id==ID_HIDX);
473
474 /* Create a blank record for writing at the end */
475
476 sqi.ofs=NULL_FRAME;
477 sqi.umsgid=(UMSGID)-1L;
478 sqi.hash=(dword)-1L;
479
480 if (hix->fBuffer)
481 {
482 dword dwStart=1L;
483
484 /* Find the segment containing the deleted message */
485
486 for (i=0; i < hix->cSeg; i++)
487 {
488 /* If it's in this segment */
489
490 if (dwMsg >= dwStart && dwMsg < dwStart + hix->pss[i].dwUsed)
491 {
492 int j=(int)(dwMsg-dwStart);
493 unsigned rc=TRUE;
494
495 /* If caller wants copy of deleted record */
496
497 if (psqiOut)
498 *psqiOut=hix->pss[i].psqi[j];
499
500 /* Shift the rest of the text over this segment */
501
502 (void)fmemmove(hix->pss[i].psqi+j, hix->pss[i].psqi+j+1,
503 (size_t)(hix->pss[i].dwUsed - (dword)j - (dword)1)
504 * (size_t)SQIDX_SIZE);
505
506 hix->pss[i].dwUsed--;
507
508 if (!_SquishAppendIndexRecord(hix, &sqi))
509 rc=FALSE;
510
511 if (hix->lDeltaLo==-1 || hix->lDeltaLo > (long)dwMsg)
512 hix->lDeltaLo=(long)dwMsg;
513
514 hix->lDeltaHi=(long)_SquishIndexSize(hix) / (long)SQIDX_SIZE;
515
516 if (fFixPointers && rc)
517 return _SquishFixMemoryPointers(hix->ha, dwMsg, psqh);
518 else
519 return rc;
520 }
521
522 dwStart += hix->pss[i].dwUsed;
523 }
524
525 /* Huh? Message not in index! */
526
527 return FALSE;
528 }
529
530
531 /* Else if it's not buffered: */
532
533
534 (void)lseek(HixSqd->ifd, (long)dwMsg * (long)SQIDX_SIZE, SEEK_SET);
535
536 pcBuf=palloc(SHIFT_SIZE);
537 if (pcBuf==NULL)
538 {
539 msgapierr=MERR_NOMEM;
540 return FALSE;
541 }
542
543 /* Only shifting - read_sqidx() is not required */
544 while ((got=read(HixSqd->ifd, pcBuf, SHIFT_SIZE)) > 0)
545 {
546 /* Skip back to one position before this index entry */
547
548 (void)lseek(HixSqd->ifd, -(long)got - SQIDX_SIZE, SEEK_CUR);
549
550 if (write(HixSqd->ifd, pcBuf, (unsigned)got) != got)
551 {
552 msgapierr=MERR_BADF;
553 return FALSE;
554 }
555
556 (void)lseek(HixSqd->ifd, (long)SQIDX_SIZE, SEEK_CUR);
557 }
558
559 pfree(pcBuf);
560
561 /* Now write the last entry to stomp over the index element that is at *
562 * the end of the file. */
563
564 (void)lseek(HixSqd->ifd, -(long)SQIDX_SIZE, SEEK_CUR);
565
566 if (write_sqidx(HixSqd->ifd, &sqi, 1) != 1)
567 {
568 msgapierr=MERR_BADF;
569 return FALSE;
570 }
571
572 if (fFixPointers)
573 return _SquishFixMemoryPointers(hix->ha, dwMsg, psqh);
574 else
575 return TRUE;
576 }
577
578
579
580 /* Close an index file handle */
581
_SquishCloseIndex(HIDX hix)582 unsigned _SquishCloseIndex(HIDX hix)
583 {
584 assert(hix->id==ID_HIDX);
585
586 while (hix->fBuffer)
587 if (!_SquishEndBuffer(hix))
588 return FALSE;
589
590 hix->id=0;
591
592 pfree(hix);
593
594 return TRUE;
595 }
596
597
598
599 /* Dump the index file buffer */
600
_SquishEndBuffer(HIDX hix)601 int _SquishEndBuffer(HIDX hix)
602 {
603 int i;
604 int rc=TRUE;
605 long lSize;
606
607 assert(hix->id==ID_HIDX);
608
609 if (hix->fBuffer==0)
610 return FALSE;
611
612 if (--hix->fBuffer != 0)
613 return TRUE;
614
615
616 /* Reduce the index file to the size that it really should be */
617
618 lSize=(long)hix->ha->num_msg * (long)SQIDX_SIZE;
619 setfsize(HixSqd->ifd, lSize);
620
621
622 /* If we need to rewrite the index */
623
624 if (hix->lDeltaLo != -1 && hix->lDeltaHi != -1)
625 {
626 dword dwStart=1;
627
628 (void) lseek(HixSqd->ifd,
629 (hix->lDeltaLo - 1L) * (long)SQIDX_SIZE,
630 SEEK_SET);
631
632 for (i=0; i < hix->cSeg; i++)
633 {
634 /* If this buffer is within the "delta" range */
635
636 if ((long)dwStart + (long)hix->pss[i].dwUsed > hix->lDeltaLo &&
637 (long)dwStart <= hix->lDeltaHi)
638 {
639 size_t j, size;
640
641 if ((long)dwStart > hix->lDeltaLo)
642 j=0;
643 else
644 j=(size_t)(hix->lDeltaLo-(long)dwStart);
645
646 if ((long)dwStart + (long)hix->pss[i].dwUsed > hix->lDeltaHi)
647 size = (size_t)(hix->lDeltaHi - (long)dwStart + 1L);
648 else
649 size = (size_t)(hix->pss[i].dwUsed);
650
651 size -= j;
652
653 if (rc)
654 {
655 if (write_sqidx(HixSqd->ifd, (hix->pss[i].psqi+j), size)
656 != 1)
657
658 {
659 msgapierr=MERR_NODS;
660 rc=FALSE;
661 }
662 }
663 }
664
665 dwStart += hix->pss[i].dwUsed;
666 }
667 }
668
669
670 /* Free the memory used by these segments */
671
672 for (i=0; i < hix->cSeg; i++)
673 farpfree(hix->pss[i].psqi);
674
675 pfree(hix->pss);
676 hix->cSeg=0;
677
678 return rc;
679 }
680
681 /* Free the index file buffer */
682
_SquishFreeBuffer(HIDX hix)683 int _SquishFreeBuffer(HIDX hix)
684 {
685 int i;
686 int rc=TRUE;
687
688 assert(hix->id==ID_HIDX);
689
690 if (hix->fBuffer==0)
691 return FALSE;
692
693 if (--hix->fBuffer != 0)
694 return TRUE;
695
696
697 /* Free the memory used by these segments */
698
699 for (i=0; i < hix->cSeg; i++)
700 farpfree(hix->pss[i].psqi);
701
702 pfree(hix->pss);
703 hix->cSeg=0;
704
705 return rc;
706 }
707
708