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 <errno.h>
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdlib.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 /* Read the base header from the beginning of the .sqd file */
67
_SquishReadBaseHeader(HAREA ha,SQBASE * psqb)68 unsigned _SquishReadBaseHeader(HAREA ha, SQBASE *psqb)
69 {
70 if (lseek(Sqd->sfd, 0L, SEEK_SET) != 0 ||
71 read_sqbase(Sqd->sfd, psqb) != 1)
72 {
73 if (errno==EACCES || errno==-1)
74 msgapierr=MERR_SHARE;
75 else
76 msgapierr=MERR_BADF;
77
78 return FALSE;
79 }
80
81 return TRUE;
82 }
83
84
85
86
87 /* Write the base header back to the beginning of the .sqd file */
88
_SquishWriteBaseHeader(HAREA ha,SQBASE * psqb)89 unsigned _SquishWriteBaseHeader(HAREA ha, SQBASE *psqb)
90 {
91 if (lseek(Sqd->sfd, 0L, SEEK_SET) != 0 ||
92 write_sqbase(Sqd->sfd, psqb) != 1)
93 {
94 msgapierr=MERR_NODS;
95 return FALSE;
96 }
97
98 return TRUE;
99 }
100
101
102
103 /* Release the specified frame to the free chain. The frame is *
104 * located at offset 'fo', and the header at that offset has *
105 * already been loaded into *psqh. This function does **not** *
106 * change the links of other messages that may point to this *
107 * message; it simply threads the current message into the free chain. *
108 * *
109 * This function assumes that we have exclusive access to the Squish base. */
110
_SquishInsertFreeChain(HAREA ha,FOFS fo,SQHDR * psqh)111 unsigned _SquishInsertFreeChain(HAREA ha, FOFS fo, SQHDR *psqh)
112 {
113 SQHDR sqh=*psqh;
114
115 assert(Sqd->fHaveExclusive);
116
117 sqh.id=SQHDRID;
118 sqh.frame_type=FRAME_FREE;
119 sqh.msg_length=sqh.clen=0L;
120
121 /* If we have no existing free frames, then this is easy */
122
123 if (Sqd->foLastFree==NULL_FRAME)
124 {
125 sqh.prev_frame=NULL_FRAME;
126 sqh.next_frame=NULL_FRAME;
127
128 /* Try to write this frame back to the file */
129
130 if (! _SquishWriteHdr(ha, fo, &sqh))
131 return FALSE;
132
133 Sqd->foFree=Sqd->foLastFree=fo;
134 return TRUE;
135 }
136
137
138 /* There is an existing frame, so we must append to the end of the *
139 * chain. */
140
141 sqh.prev_frame=Sqd->foLastFree;
142 sqh.next_frame=NULL_FRAME;
143
144
145 /* Update the last chain in the free list, pointing it to us */
146
147 if (!_SquishSetFrameNext(ha, sqh.prev_frame, fo))
148 return FALSE;
149
150
151 /* Try to write the current frame to disk */
152
153 if (_SquishWriteHdr(ha, fo, &sqh))
154 {
155 Sqd->foLastFree=fo;
156 return TRUE;
157 }
158 else
159 {
160 /* The write failed, so just hope that we can undo what we did *
161 * earlier. */
162
163 (void)_SquishSetFrameNext(ha, sqh.prev_frame, NULL_FRAME);
164 return FALSE;
165 }
166 }
167
168
169
170 /* Change the 'next' link of the foModify frame to the value foValue */
171
_SquishSetFrameNext(HAREA ha,FOFS foModify,FOFS foValue)172 unsigned _SquishSetFrameNext(HAREA ha, FOFS foModify, FOFS foValue)
173 {
174 SQHDR sqh;
175
176 if (!_SquishReadHdr(ha, foModify, &sqh))
177 return FALSE;
178
179 sqh.next_frame=foValue;
180
181 return _SquishWriteHdr(ha, foModify, &sqh);
182 }
183
184
185
186 /* Change the 'prior' link of the foModify frame to the value foValue */
187
_SquishSetFramePrev(HAREA ha,FOFS foModify,FOFS foValue)188 unsigned _SquishSetFramePrev(HAREA ha, FOFS foModify, FOFS foValue)
189 {
190 SQHDR sqh;
191
192 if (!_SquishReadHdr(ha, foModify, &sqh))
193 return FALSE;
194
195 sqh.prev_frame=foValue;
196
197 return _SquishWriteHdr(ha, foModify, &sqh);
198 }
199
200
201
202 /* This function ensures that the message handle is readable */
203
_SquishReadMode(HMSG hmsg)204 unsigned _SquishReadMode(HMSG hmsg)
205 {
206 if (hmsg->wMode != MOPEN_READ && hmsg->wMode != MOPEN_RW)
207 {
208 msgapierr=MERR_EACCES;
209 return FALSE;
210 }
211
212 return TRUE;
213 }
214
215
216
217 /* This function ensures that the message handle is writable */
218
_SquishWriteMode(HMSG hmsg)219 unsigned _SquishWriteMode(HMSG hmsg)
220 {
221 if (hmsg->wMode != MOPEN_CREATE && hmsg->wMode != MOPEN_WRITE &&
222 hmsg->wMode != MOPEN_RW)
223 {
224 msgapierr=MERR_EACCES;
225 return FALSE;
226 }
227
228 return TRUE;
229 }
230
231
232
233 /* Translate a message number into a frame offset for area 'ha' */
234
_SquishGetFrameOfs(HAREA ha,dword dwMsg)235 FOFS _SquishGetFrameOfs(HAREA ha, dword dwMsg)
236 {
237 SQIDX sqi;
238
239
240 msgapierr=MERR_NOENT;
241
242 /* Check for simple stuff that we can handle by following our own *
243 * linked list. */
244
245 if (dwMsg==ha->cur_msg)
246 return Sqd->foCur;
247 else if (dwMsg==ha->cur_msg-1)
248 return Sqd->foPrev;
249 else if (dwMsg==ha->cur_msg+1)
250 return Sqd->foNext;
251
252 /* We couldn't just follow the linked list, so we will have to consult *
253 * the Squish index file to find it. */
254
255 if (! SidxGet(Sqd->hix, dwMsg, &sqi))
256 return NULL_FRAME;
257
258 return sqi.ofs;
259 }
260
261
262 /* Read the Squish header 'psqh' from the specified frame offset */
263
_SquishReadHdr(HAREA ha,FOFS fo,SQHDR * psqh)264 unsigned _SquishReadHdr(HAREA ha, FOFS fo, SQHDR *psqh)
265 {
266 /* Ensure that we are reading a valid frame header */
267
268 if (fo < SQBASE_SIZE)
269 {
270 msgapierr=MERR_BADA;
271 return FALSE;
272 }
273
274 /* Seek and read the header */
275
276 if (fo >= Sqd->foEnd ||
277 lseek(Sqd->sfd, fo, SEEK_SET) != fo ||
278 read_sqhdr(Sqd->sfd, psqh) != 1 ||
279 psqh->id != SQHDRID)
280 {
281 msgapierr=MERR_BADF;
282 return FALSE;
283 }
284
285 return TRUE;
286 }
287
288
289
290 /* Write the Squish header 'psqh' to the specified frame offset */
291
_SquishWriteHdr(HAREA ha,FOFS fo,SQHDR * psqh)292 unsigned _SquishWriteHdr(HAREA ha, FOFS fo, SQHDR *psqh)
293 {
294 /* Make sure that we don't write over the file header */
295
296 if (fo < SQBASE_SIZE)
297 {
298 msgapierr=MERR_BADA;
299 return FALSE;
300 }
301
302 if (lseek(Sqd->sfd, fo, SEEK_SET) != fo ||
303 write_sqhdr(Sqd->sfd, psqh) != 1)
304 {
305 msgapierr=MERR_NODS;
306 return FALSE;
307 }
308
309 return TRUE;
310 }
311
312
313 /* This function fixes the in-memory pointers after message dwMsg was *
314 * removed from the index file. *
315 * *
316 * This function assumes that we have exclusive access to the Squish base. */
317
_SquishFixMemoryPointers(HAREA ha,dword dwMsg,SQHDR * psqh)318 unsigned _SquishFixMemoryPointers(HAREA ha, dword dwMsg, SQHDR *psqh)
319 {
320 assert(Sqd->fHaveExclusive);
321
322 /* Adjust the first/last message pointers */
323
324 if (dwMsg==1)
325 Sqd->foFirst=psqh->next_frame;
326
327 if (dwMsg==ha->num_msg)
328 Sqd->foLast=psqh->prev_frame;
329
330
331 /* Now fix up the in-memory version of the prior/next links */
332
333 if (dwMsg==ha->cur_msg+1)
334 Sqd->foNext=psqh->next_frame;
335
336 if (dwMsg==ha->cur_msg-1)
337 Sqd->foPrev=psqh->prev_frame;
338
339
340 /* If we killed the message that we are on, it's a special case */
341
342 if (dwMsg==ha->cur_msg)
343 {
344 SQHDR sqh;
345
346 /* Go to the header of the prior msg */
347
348 if (!_SquishReadHdr(ha, psqh->prev_frame, &sqh))
349 {
350 /* That does not exist, so go to msg 0 */
351
352 Sqd->foCur=Sqd->foPrev=NULL_FRAME;
353 Sqd->foNext=Sqd->foFirst;
354 ha->cur_msg=0;
355 }
356 else
357 {
358 /* Otherwise, adjust pointers appropriately */
359
360 Sqd->foCur=psqh->prev_frame;
361 Sqd->foPrev=sqh.prev_frame;
362 Sqd->foNext=sqh.next_frame;
363 ha->cur_msg--;
364 }
365 }
366 else
367 {
368 /* We didn't kill the current msg, so just decrement cur_msg if *
369 * we were higher than the deleted message. */
370
371 if (ha->cur_msg >= dwMsg)
372 ha->cur_msg--;
373 }
374
375
376 /* Adjust the message numbers appropriately */
377
378 ha->num_msg--;
379 ha->high_msg--;
380
381 if (ha->high_water >= dwMsg)
382 ha->high_water--;
383
384 return TRUE;
385 }
386
387
388
389
390
391 /* Write the index back to disk and free the associated memory */
392
_SquishFreeIndex(HAREA ha,dword dwMsg,SQIDX * psqi,dword dwIdxSize,unsigned fWrite)393 unsigned _SquishFreeIndex(HAREA ha, dword dwMsg, SQIDX *psqi,
394 dword dwIdxSize, unsigned fWrite)
395 {
396 unsigned rc=TRUE;
397 long ofs;
398
399 unused(dwIdxSize);
400
401 #ifdef __WATCOMC__
402 dwIdxSize=dwIdxSize; /* To prevent warning */
403 #endif
404
405 if (fWrite)
406 {
407 /* Seek to the offset of the message that we want to delete */
408
409 ofs=((long)dwMsg-1L) * (long)SQIDX_SIZE;
410
411 /* Write it back out to disk at the same position */
412
413 rc=(lseek(Sqd->ifd, ofs, SEEK_SET)==ofs &&
414 write_sqidx(Sqd->ifd, psqi, ((long)dwMsg-1L)) == 1);
415 }
416
417 pfree(psqi);
418
419 return rc;
420 }
421
422
423
424 #if 0
425 /* Read from the index file, starting at the dwMsg'th record */
426
427 SQIDX * _SquishAllocIndex(HAREA ha, dword dwMsg, dword *pdwIdxSize)
428 {
429 SQIDX *psqi;
430 dword dwIdxSize;
431 long ofs;
432
433 /* We only need enough memory to read in the index file from the point *
434 * that we are deleting a message. */
435
436 dwIdxSize = ((long)ha->num_msg - (long)dwMsg + 1L) * (long)sizeof(SQIDX);
437
438
439 /* Handle problems that we may have when working on a 16-bit platform */
440
441 if (dwIdxSize > 65000L)
442 {
443 }
444
445 /* Allocate memory for handling the index */
446
447 if ((psqi=palloc((size_t)dwIdxSize))==NULL)
448 {
449 msgapierr=MERR_NOMEM;
450 return NULL;
451 }
452
453
454 /* Seek to the offset of the message that we want to delete */
455
456 ofs=((long)dwMsg-1L) * (long)SQIDX_SIZE;
457
458
459 /* Now read it from disk */
460
461 if (lseek(Sqd->ifd, ofs, SEEK_SET) != ofs ||
462 read_sqidx(Sqd->ifd, psqi, ((long)ha->num_msg - (long)dwMsg + 1L)) != 1)
463 {
464 msgapierr=MERR_BADF;
465 pfree(psqi);
466 return NULL;
467 }
468
469 *pdwIdxSize=dwIdxSize;
470 return psqi;
471 }
472
473 /* This function removes the specified message number from the Squish index *
474 * file, moving the rest of the index file back over the message number to *
475 * fill in the gaps. *
476 * *
477 * This function also adjusts the message number pointers everywhere to *
478 * accomodate for the deletion of this message. *
479 * *
480 * This function assumes that we have exclusive access to the Squish base. */
481
482 unsigned _SquishRemoveIndex(HAREA ha, dword dwMsg, SQIDX *psqiOut, SQHDR *psqh)
483 {
484 dword dwIdxSize;
485 SQIDX *psqiLast;
486 SQIDX *psqi;
487 unsigned rc;
488
489 assert(Sqd->fHaveExclusive);
490
491 /* Read the index from disk */
492
493 if ((psqi=_SquishAllocIndex(ha, dwMsg, &dwIdxSize))==NULL)
494 return FALSE;
495
496
497 /* If the caller wants a copy of the record that we are deleting... */
498
499 if (psqiOut)
500 memmove(psqiOut, psqi, sizeof(SQIDX));
501
502
503 /* Shift everything over by one to accomodate for the deleted msg */
504
505 memmove(psqi, psqi+1, (size_t)dwIdxSize-sizeof(SQIDX));
506
507
508 /* Blank out the last index pointer in the file so that it is invalid */
509
510 psqiLast=psqi + (ha->num_msg - (long)dwMsg);
511
512 psqiLast->ofs=NULL_FRAME;
513 psqiLast->umsgid=(UMSGID)-1L;
514 psqiLast->hash=(dword)-1L;
515
516
517 /* Write it back to disk and free memory */
518
519 rc=_SquishFreeIndex(ha, dwMsg, psqi, dwIdxSize, TRUE);
520
521
522 /* If the delete succeeded, adjust the memory pointers */
523
524 if (rc)
525 rc=_SquishFixMemoryPointers(ha, dwMsg, psqh);
526
527 return rc;
528 }
529 #endif
530
531