1 /* smblib.c */
2
3 /* Synchronet message base (SMB) library routines */
4
5 /* $Id: smblib.cpp,v 1.7 2011/02/17 11:18:16 stas_degteff Exp $ */
6
7 /****************************************************************************
8 * @format.tab-size 4 (Plain Text/Source Code File Header) *
9 * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10 * *
11 * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
12 * *
13 * This library is free software; you can redistribute it and/or *
14 * modify it under the terms of the GNU Lesser General Public License *
15 * as published by the Free Software Foundation; either version 2 *
16 * of the License, or (at your option) any later version. *
17 * See the GNU Lesser General Public License for more details: lgpl.txt or *
18 * http://www.fsf.org/copyleft/lesser.html *
19 * *
20 * Anonymous FTP access to the most recent released source is available at *
21 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22 * *
23 * Anonymous CVS access to the development source and modification history *
24 * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
26 * (just hit return, no password is necessary) *
27 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
28 * *
29 * For Synchronet coding style and modification guidelines, see *
30 * http://www.synchro.net/source.html *
31 * *
32 * You are encouraged to submit any modifications (preferably in Unix diff *
33 * format) via e-mail to mods@synchro.net *
34 * *
35 * Note: If this box doesn't appear square, then you need to fix your tabs. *
36 ****************************************************************************/
37
38 #if defined __WATCOMC__ || defined __TURBOC__
39 #include <mem.h>
40 #else
41 #include <memory.h>
42 #endif
43
44 #ifdef __WATCOMC__
45 #include <dos.h>
46 #elif defined __TURBOC__
47 #include <dir.h>
48 #endif
49
50 /* ANSI C Library headers */
51
52 #ifdef HAVE_MALLOC_H
53 #include <malloc.h>
54 #endif
55
56 #include <time.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64
65 /* SMB-specific headers */
66 #include "smblib.h"
67 #include <gtimall.h>
68 #include <gfilutil.h>
69
70 /* Use smb_ver() and smb_lib_ver() to obtain these values */
71 #define SMBLIB_VERSION "2.16" /* SMB library version */
72 #define SMB_VERSION 0x0121 /* SMB format version */
73 /* High byte major, low byte minor */
74
75 #define U_MODE 777 /* permitions for the new files (real: U_MODE XOR UMASK) */
76 /* This is required for sopen(,,,) */
77
78 #ifndef __gtimall_h
gtime(time32_t * timep)79 time32_t gtime(time32_t *timep)
80 {
81 time32_t temp = (time32_t)time(NULL);
82 return timep ? *timep = temp : temp;
83 }
84 #endif //#ifndef __gtimall_h
85
smb_ver(void)86 int SMBCALL smb_ver(void)
87 {
88 return(SMB_VERSION);
89 }
90
smb_lib_ver(void)91 char* SMBCALL smb_lib_ver(void)
92 {
93 return(SMBLIB_VERSION);
94 }
95
96 /****************************************************************************/
97 /* Open a message base of name 'smb->file' */
98 /* Opens files for READing messages or updating message indices only */
99 /****************************************************************************/
smb_open(smb_t * smb)100 int SMBCALL smb_open(smb_t* smb)
101 {
102 int file;
103 char str[128];
104 smbhdr_t hdr;
105
106 /* Set default values, if uninitialized */
107 if(!smb->retry_time)
108 smb->retry_time=10; /* seconds */
109 if(!smb->retry_delay
110 || smb->retry_delay>(smb->retry_time*100)) /* at least ten retries */
111 smb->retry_delay=250; /* milliseconds */
112 smb->shd_fp=smb->sdt_fp=smb->sid_fp=NULL;
113 smb->last_error[0]=0;
114 sprintf(str,"%s.shd",smb->file);
115 if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,U_MODE))==-1) {
116 sprintf(smb->last_error,"%d opening %s",errno,str);
117 return(2);
118 }
119
120 if((smb->shd_fp=fdopen(file,"r+b"))==NULL) {
121 sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
122 close(file);
123 return(4);
124 }
125
126 if(filelength(file)>=sizeof(smbhdr_t)) {
127 setvbuf(smb->shd_fp,smb->shd_buf,_IONBF,SHD_BLOCK_LEN);
128 if(smb_locksmbhdr(smb)!=0) {
129 smb_close(smb);
130 /* smb_lockmsghdr set last_error */
131 return(-1);
132 }
133 memset(&hdr,0,sizeof(smbhdr_t));
134 if(fread(&hdr,sizeof(smbhdr_t),1,smb->shd_fp)!=1) {
135 sprintf(smb->last_error,"reading header");
136 smb_close(smb);
137 return(-10);
138 }
139 if(memcmp(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID)) {
140 sprintf(smb->last_error,"corrupt SMB header ID: %.*s",LEN_HEADER_ID,hdr.id);
141 smb_close(smb);
142 return(-2);
143 }
144 if(hdr.version<0x110) { /* Compatibility check */
145 sprintf(smb->last_error,"insufficient header version: %X",hdr.version);
146 smb_close(smb);
147 return(-3);
148 }
149 if(fread(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp)
150 !=sizeof(smbstatus_t)) {
151 sprintf(smb->last_error,"failed to read status");
152 smb_close(smb);
153 return(-4);
154 }
155 smb_unlocksmbhdr(smb);
156 rewind(smb->shd_fp);
157 }
158
159 setvbuf(smb->shd_fp,smb->shd_buf,_IOFBF,SHD_BLOCK_LEN);
160
161 sprintf(str,"%s.sdt",smb->file);
162 if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,U_MODE))==-1) {
163 sprintf(smb->last_error,"%d opening %s",errno,str);
164 smb_close(smb);
165 return(1);
166 }
167
168 if((smb->sdt_fp=fdopen(file,"r+b"))==NULL) {
169 sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
170 close(file);
171 smb_close(smb);
172 return(5);
173 }
174
175 setvbuf(smb->sdt_fp,NULL,_IOFBF,2*1024);
176
177 sprintf(str,"%s.sid",smb->file);
178 if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,U_MODE))==-1) {
179 sprintf(smb->last_error,"%d opening %s",errno,str);
180 smb_close(smb);
181 return(3);
182 }
183
184 if((smb->sid_fp=fdopen(file,"r+b"))==NULL) {
185 sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
186 close(file);
187 smb_close(smb);
188 return(6);
189 }
190
191 setvbuf(smb->sid_fp,NULL,_IOFBF,2*1024);
192
193 return(0);
194 }
195
196 /****************************************************************************/
197 /* Closes the currently open message base */
198 /****************************************************************************/
smb_close(smb_t * smb)199 void SMBCALL smb_close(smb_t* smb)
200 {
201 if(smb->shd_fp!=NULL) {
202 smb_unlocksmbhdr(smb); /* In case it's been locked */
203 fclose(smb->shd_fp);
204 }
205 if(smb->sid_fp!=NULL)
206 fclose(smb->sid_fp);
207 if(smb->sdt_fp!=NULL)
208 fclose(smb->sdt_fp);
209 smb->sid_fp=smb->shd_fp=smb->sdt_fp=NULL;
210 }
211
212 /****************************************************************************/
213 /* Opens the data block allocation table message base 'smb->file' */
214 /* Retrys for retry_time number of seconds */
215 /* Return 0 on success, non-zero otherwise */
216 /****************************************************************************/
smb_open_da(smb_t * smb)217 int SMBCALL smb_open_da(smb_t* smb)
218 {
219 int file;
220 char str[128];
221 time32_t start = 0;
222
223 sprintf(str,"%s.sda",smb->file);
224 while(1) {
225 if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,U_MODE))!=-1)
226 break;
227 if(errno!=EACCES && errno!=EAGAIN) {
228 sprintf(smb->last_error,"%d opening %s",errno,str);
229 return(-1);
230 }
231 if(!start)
232 start = gtime(NULL);
233 else
234 if(gtime(NULL)-start >= smb->retry_time) {
235 sprintf(smb->last_error,"timeout opening %s (retry_time=%d)"
236 ,str,smb->retry_time);
237 return(-2);
238 }
239 usleep(smb->retry_delay);
240 }
241 if((smb->sda_fp=fdopen(file,"r+b"))==NULL) {
242 sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
243 close(file);
244 return(-3);
245 }
246 setvbuf(smb->sda_fp,NULL,_IOFBF,2*1024);
247 return(0);
248 }
249
smb_close_da(smb_t * smb)250 void SMBCALL smb_close_da(smb_t* smb)
251 {
252 if(smb->sda_fp!=NULL)
253 fclose(smb->sda_fp);
254 smb->sda_fp=NULL;
255 }
256
257 /****************************************************************************/
258 /* Opens the header block allocation table for message base 'smb.file' */
259 /* Retrys for smb.retry_time number of seconds */
260 /* Return 0 on success, non-zero otherwise */
261 /****************************************************************************/
smb_open_ha(smb_t * smb)262 int SMBCALL smb_open_ha(smb_t* smb)
263 {
264 int file;
265 char str[128];
266 time32_t start = 0;
267
268 sprintf(str,"%s.sha",smb->file);
269 while(1) {
270 if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,U_MODE))!=-1)
271 break;
272 if(errno!=EACCES && errno!=EAGAIN) {
273 sprintf(smb->last_error,"%d opening %s",errno,str);
274 return(-1);
275 }
276 if(!start)
277 start = gtime(NULL);
278 else
279 if(gtime(NULL)-start >= smb->retry_time) {
280 sprintf(smb->last_error,"timeout opening %s (retry_time=%d)"
281 ,str,smb->retry_time);
282 return(-2);
283 }
284 usleep(smb->retry_delay);
285 }
286 if((smb->sha_fp=fdopen(file,"r+b"))==NULL) {
287 sprintf(smb->last_error,"%d fdopening %s (%d)",errno,str,file);
288 close(file);
289 return(-3);
290 }
291 setvbuf(smb->sha_fp,NULL,_IOFBF,2*1024);
292 return(0);
293 }
294
smb_close_ha(smb_t * smb)295 void SMBCALL smb_close_ha(smb_t* smb)
296 {
297 if(smb->sha_fp!=NULL)
298 fclose(smb->sha_fp);
299 smb->sha_fp=NULL;
300 }
301
302 /****************************************************************************/
303 /* If the parameter 'push' is non-zero, this function stores the currently */
304 /* open message base to the "virtual" smb stack. Up to SMB_STACK_LEN */
305 /* message bases may be stored (defined in SMBDEFS.H). */
306 /* The parameter 'op' is the operation to perform on the stack. Either */
307 /* SMB_STACK_PUSH, SMB_STACK_POP, or SMB_STACK_XCHNG */
308 /* If the operation is SMB_STACK_POP, this function restores a message base */
309 /* previously saved with a SMB_STACK_PUSH call to this same function. */
310 /* If the operation is SMB_STACK_XCHNG, then the current message base is */
311 /* exchanged with the message base on the top of the stack (most recently */
312 /* pushed. */
313 /* If the current message base is not open, the SMB_STACK_PUSH and */
314 /* SMB_STACK_XCHNG operations do nothing */
315 /* Returns 0 on success, non-zero if stack full. */
316 /* If operation is SMB_STACK_POP or SMB_STACK_XCHNG, it always returns 0. */
317 /****************************************************************************/
smb_stack(smb_t * smb,int op)318 int SMBCALL smb_stack(smb_t* smb, int op)
319 {
320 static smb_t stack[SMB_STACK_LEN];
321 static int stack_idx;
322 smb_t tmp_smb;
323
324 if(op==SMB_STACK_PUSH) {
325 if(stack_idx>=SMB_STACK_LEN) {
326 sprintf(smb->last_error,"SMB stack overflow");
327 return(1);
328 }
329 if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL)
330 return(0); /* Msg base not open */
331 memcpy(&stack[stack_idx],smb,sizeof(smb_t));
332 stack_idx++;
333 return(0);
334 }
335 /* pop or xchng */
336 if(!stack_idx) /* Nothing on the stack, so do nothing */
337 return(0);
338 if(op==SMB_STACK_XCHNG) {
339 if(smb->shd_fp==NULL)
340 return(0);
341 memcpy(&tmp_smb,smb,sizeof(smb_t));
342 }
343
344 stack_idx--;
345 memcpy(smb,&stack[stack_idx],sizeof(smb_t));
346 if(op==SMB_STACK_XCHNG) {
347 memcpy(&stack[stack_idx],&tmp_smb,sizeof(smb_t));
348 stack_idx++;
349 }
350 return(0);
351 }
352
353 /****************************************************************************/
354 /* Truncates header file */
355 /* Retrys for smb.retry_time number of seconds */
356 /* Return 0 on success, non-zero otherwise */
357 /****************************************************************************/
smb_trunchdr(smb_t * smb)358 int SMBCALL smb_trunchdr(smb_t* smb)
359 {
360 time32_t start = 0;
361
362 if(smb->shd_fp==NULL) {
363 sprintf(smb->last_error,"msgbase not open");
364 return(SMB_ERR_NOT_OPEN);
365 }
366 rewind(smb->shd_fp);
367 while(1) {
368 if(!chsize(fileno(smb->shd_fp),0L))
369 break;
370 if(errno!=EACCES && errno!=EAGAIN) {
371 sprintf(smb->last_error,"%d changing header file size",errno);
372 return(-1);
373 }
374 if(!start)
375 start = gtime(NULL);
376 else
377 if(gtime(NULL)-start >= smb->retry_time) { /* Time-out */
378 sprintf(smb->last_error,"timeout changing header file size (retry_time=%d)"
379 ,smb->retry_time);
380 return(-2);
381 }
382 usleep(smb->retry_delay);
383 }
384 return(0);
385 }
386
387 /*********************************/
388 /* Message Base Header Functions */
389 /*********************************/
390
391 /****************************************************************************/
392 /* Attempts for smb.retry_time number of seconds to lock the msg base hdr */
393 /****************************************************************************/
smb_locksmbhdr(smb_t * smb)394 int SMBCALL smb_locksmbhdr(smb_t* smb)
395 {
396 time32_t start = 0;
397
398 if(smb->shd_fp==NULL) {
399 sprintf(smb->last_error,"msgbase not open");
400 return(SMB_ERR_NOT_OPEN);
401 }
402 while(1) {
403 if(lock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))==0) {
404 smb->locked=1; /* TRUE */
405 return(0);
406 }
407 if(!start)
408 start = gtime(NULL);
409 else
410 if(gtime(NULL)-start >= smb->retry_time)
411 break;
412 /* In case we've already locked it */
413 if(unlock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))==0)
414 smb->locked=0; /* FALSE */
415 usleep(smb->retry_delay);
416 }
417 sprintf(smb->last_error,"timeout locking header");
418 return(-1);
419 }
420
421 /****************************************************************************/
422 /* Read the SMB header from the header file and place into smb.status */
423 /****************************************************************************/
smb_getstatus(smb_t * smb)424 int SMBCALL smb_getstatus(smb_t* smb)
425 {
426 int i;
427
428 if(smb->shd_fp==NULL) {
429 sprintf(smb->last_error,"msgbase not open");
430 return(SMB_ERR_NOT_OPEN);
431 }
432 setvbuf(smb->shd_fp,smb->shd_buf,_IONBF,SHD_BLOCK_LEN);
433 clearerr(smb->shd_fp);
434 fseek(smb->shd_fp,sizeof(smbhdr_t),SEEK_SET);
435 i=fread(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
436 setvbuf(smb->shd_fp,smb->shd_buf,_IOFBF,SHD_BLOCK_LEN);
437 if(i==sizeof(smbstatus_t))
438 return(0);
439 sprintf(smb->last_error,"read %d instead of %d",i,(int)sizeof(smbstatus_t));
440 return(1);
441 }
442
443 /****************************************************************************/
444 /* Writes message base header */
445 /****************************************************************************/
smb_putstatus(smb_t * smb)446 int SMBCALL smb_putstatus(smb_t* smb)
447 {
448 int i;
449
450 if(smb->shd_fp==NULL) {
451 sprintf(smb->last_error,"msgbase not open");
452 return(SMB_ERR_NOT_OPEN);
453 }
454 clearerr(smb->shd_fp);
455 fseek(smb->shd_fp,sizeof(smbhdr_t),SEEK_SET);
456 i=fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
457 fflush(smb->shd_fp);
458 if(i==sizeof(smbstatus_t))
459 return(0);
460 sprintf(smb->last_error,"wrote %d instead of %d",i,(int)sizeof(smbstatus_t));
461 return(1);
462 }
463
464 /****************************************************************************/
465 /* Unlocks previously locks message base header */
466 /****************************************************************************/
smb_unlocksmbhdr(smb_t * smb)467 int SMBCALL smb_unlocksmbhdr(smb_t* smb)
468 {
469 int result;
470
471 if(smb->shd_fp==NULL) {
472 sprintf(smb->last_error,"msgbase not open");
473 return(SMB_ERR_NOT_OPEN);
474 }
475 result = unlock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t));
476 if(result==0)
477 smb->locked=0; /* FALSE */
478 return(result);
479 }
480
481 /********************************/
482 /* Individual Message Functions */
483 /********************************/
484
485 /****************************************************************************/
486 /* Attempts for smb.retry_time number of seconds to lock the hdr for 'msg' */
487 /****************************************************************************/
smb_lockmsghdr(smb_t * smb,smbmsg_t * msg)488 int SMBCALL smb_lockmsghdr(smb_t* smb, smbmsg_t* msg)
489 {
490 time32_t start = 0;
491
492 if(smb->shd_fp==NULL) {
493 sprintf(smb->last_error,"msgbase not open");
494 return(SMB_ERR_NOT_OPEN);
495 }
496 while(1) {
497 if(!lock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t)))
498 return(0);
499 if(!start)
500 start = gtime(NULL);
501 else
502 if(gtime(NULL)-start >= smb->retry_time)
503 break;
504 /* In case we've already locked it */
505 unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t));
506 usleep(smb->retry_delay);
507 }
508 sprintf(smb->last_error,"timeout locking header");
509 return(-1);
510 }
511
512 /****************************************************************************/
513 /* Fills msg->idx with message index based on msg->hdr.number */
514 /* OR if msg->hdr.number is 0, based on msg->offset (record offset). */
515 /* if msg.hdr.number does not equal 0, then msg->offset is filled too. */
516 /* Either msg->hdr.number or msg->offset must be initialized before */
517 /* calling this function */
518 /* Returns 1 if message number wasn't found, 0 if it was */
519 /****************************************************************************/
smb_getmsgidx(smb_t * smb,smbmsg_t * msg)520 int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
521 {
522 idxrec_t idx;
523 uint32_t l,length,total,bot,top;
524
525 if(smb->sid_fp==NULL) {
526 sprintf(smb->last_error,"index not open");
527 return(SMB_ERR_NOT_OPEN);
528 }
529 clearerr(smb->sid_fp);
530 if(!msg->hdr.number) {
531 fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET);
532 if(!fread(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
533 sprintf(smb->last_error,"reading index");
534 return(1);
535 }
536 return(0);
537 }
538
539 length=filelength(fileno(smb->sid_fp));
540 if(!length) {
541 sprintf(smb->last_error,"invalid index file length: %d",length);
542 return(1);
543 }
544 total=length/sizeof(idxrec_t);
545 if(!total) {
546 sprintf(smb->last_error,"invalid index file length: %d",length);
547 return(1);
548 }
549
550 bot=0;
551 top=total;
552 l=total/2; /* Start at middle index */
553 while(1) {
554 fseek(smb->sid_fp,l*sizeof(idxrec_t),SEEK_SET);
555 if(!fread(&idx,sizeof(idxrec_t),1,smb->sid_fp)) {
556 sprintf(smb->last_error,"reading index");
557 return(1);
558 }
559 if(bot==top-1 && idx.number!=msg->hdr.number) {
560 sprintf(smb->last_error,"msg %d not found",msg->hdr.number);
561 return(1);
562 }
563 if(idx.number>msg->hdr.number) {
564 top=l;
565 l=bot+((top-bot)/2);
566 continue;
567 }
568 if(idx.number<msg->hdr.number) {
569 bot=l;
570 l=top-((top-bot)/2);
571 continue;
572 }
573 break;
574 }
575 msg->idx=idx;
576 msg->offset=l;
577 return(0);
578 }
579
580 /****************************************************************************/
581 /* Reads the first index record in the open message base */
582 /****************************************************************************/
smb_getfirstidx(smb_t * smb,idxrec_t * idx)583 int SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx)
584 {
585 if(smb->sid_fp==NULL) {
586 sprintf(smb->last_error,"index not open");
587 return(SMB_ERR_NOT_OPEN);
588 }
589 clearerr(smb->sid_fp);
590 fseek(smb->sid_fp,0,SEEK_SET);
591 if(!fread(idx,sizeof(idxrec_t),1,smb->sid_fp)) {
592 sprintf(smb->last_error,"reading index");
593 return(-2);
594 }
595 return(0);
596 }
597
598 /****************************************************************************/
599 /* Reads the last index record in the open message base */
600 /****************************************************************************/
smb_getlastidx(smb_t * smb,idxrec_t * idx)601 int SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx)
602 {
603 int32_t length;
604
605 if(smb->sid_fp==NULL) {
606 sprintf(smb->last_error,"index not open");
607 return(SMB_ERR_NOT_OPEN);
608 }
609 clearerr(smb->sid_fp);
610 length=filelength(fileno(smb->sid_fp));
611 if(length<sizeof(idxrec_t)) {
612 sprintf(smb->last_error,"invalid index file length: %d",length);
613 return(-1);
614 }
615 fseek(smb->sid_fp,length-sizeof(idxrec_t),SEEK_SET);
616 if(!fread(idx,sizeof(idxrec_t),1,smb->sid_fp)) {
617 sprintf(smb->last_error,"reading index");
618 return(-2);
619 }
620 return(0);
621 }
622
623 /****************************************************************************/
624 /* Figures out the total length of the header record for 'msg' */
625 /* Returns length */
626 /****************************************************************************/
smb_getmsghdrlen(smbmsg_t * msg)627 uint SMBCALL smb_getmsghdrlen(smbmsg_t* msg)
628 {
629 int i;
630
631 /* fixed portion */
632 msg->hdr.length=sizeof(msghdr_t);
633 /* data fields */
634 msg->hdr.length+=msg->hdr.total_dfields*sizeof(dfield_t);
635 /* header fields */
636 for(i=0;i<msg->total_hfields;i++) {
637 msg->hdr.length+=sizeof(hfield_t);
638 msg->hdr.length+=msg->hfield[i].length;
639 }
640 return(msg->hdr.length);
641 }
642
643 /****************************************************************************/
644 /* Figures out the total length of the data buffer for 'msg' */
645 /* Returns length */
646 /****************************************************************************/
smb_getmsgdatlen(smbmsg_t * msg)647 uint32_t SMBCALL smb_getmsgdatlen(smbmsg_t* msg)
648 {
649 int i;
650 uint32_t length=0L;
651
652 for(i=0;i<msg->hdr.total_dfields;i++)
653 length+=msg->dfield[i].length;
654 return(length);
655 }
656
657 /****************************************************************************/
658 /* Read header information into 'msg' structure */
659 /* msg->idx.offset must be set before calling this function */
660 /* Must call smb_freemsgmem() to free memory allocated for var len strs */
661 /* Returns 0 on success, non-zero if error */
662 /****************************************************************************/
smb_getmsghdr(smb_t * smb,smbmsg_t * msg)663 int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
664 {
665 hfield_t *vp;
666 void **vpp;
667 uint16_t i;
668 uint32_t l, offset;
669 idxrec_t idx;
670
671 if(smb->shd_fp==NULL) {
672 sprintf(smb->last_error,"msgbase not open");
673 return(SMB_ERR_NOT_OPEN);
674 }
675 rewind(smb->shd_fp);
676 fseek(smb->shd_fp,msg->idx.offset,SEEK_SET);
677 idx=msg->idx;
678 offset=msg->offset;
679 memset(msg,0,sizeof(smbmsg_t));
680 msg->idx=idx;
681 msg->offset=offset;
682 if(!fread(&msg->hdr,sizeof(msghdr_t),1,smb->shd_fp)) {
683 sprintf(smb->last_error,"reading msg header");
684 return(-1);
685 }
686 if(memcmp(msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID)) {
687 sprintf(smb->last_error,"corrupt message header ID: %.*s",LEN_HEADER_ID,msg->hdr.id);
688 return(-2);
689 }
690 if(msg->hdr.version<0x110) {
691 sprintf(smb->last_error,"insufficient header version: %X",msg->hdr.version);
692 return(-9);
693 }
694 l=sizeof(msghdr_t);
695 if(msg->hdr.total_dfields && (msg->dfield
696 =(dfield_t *)MALLOC(sizeof(dfield_t)*msg->hdr.total_dfields))==NULL) {
697 smb_freemsgmem(msg);
698 sprintf(smb->last_error,"malloc failure of %d bytes for %d data fields"
699 ,(int)sizeof(dfield_t)*msg->hdr.total_dfields, msg->hdr.total_dfields);
700 return(-3);
701 }
702 i=0;
703 while(i<msg->hdr.total_dfields && l<msg->hdr.length) {
704 if(!fread(&msg->dfield[i],sizeof(dfield_t),1,smb->shd_fp)) {
705 smb_freemsgmem(msg);
706 sprintf(smb->last_error,"reading data field %d",i);
707 return(-4);
708 }
709 i++;
710 l+=sizeof(dfield_t);
711 }
712 if(i<msg->hdr.total_dfields) {
713 smb_freemsgmem(msg);
714 sprintf(smb->last_error,"insufficient data fields read (%d instead of %d)"
715 ,i,msg->hdr.total_dfields);
716 return(-8);
717 }
718 while(l<msg->hdr.length) {
719 i=msg->total_hfields;
720 if((vpp=(void* *)REALLOC(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL) {
721 smb_freemsgmem(msg);
722 sprintf(smb->last_error
723 ,"realloc failure of %d bytes for header field data"
724 ,(int)sizeof(void*)*(i+1));
725 return(-3);
726 }
727 msg->hfield_dat=vpp;
728 if((vp=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL) {
729 smb_freemsgmem(msg);
730 sprintf(smb->last_error
731 ,"realloc failure of %d bytes for header fields"
732 ,(int)sizeof(hfield_t)*(i+1));
733 return(-3);
734 }
735 msg->hfield=vp;
736 msg->total_hfields++;
737 if(!fread(&msg->hfield[i],sizeof(hfield_t),1,smb->shd_fp)) {
738 smb_freemsgmem(msg);
739 sprintf(smb->last_error,"reading header field");
740 return(-5);
741 }
742 l+=sizeof(hfield_t);
743 if((msg->hfield_dat[i]=(char*)MALLOC(msg->hfield[i].length+1))
744 ==NULL) { /* Allocate 1 extra for NULL terminator */
745 sprintf(smb->last_error
746 ,"malloc failure of %d bytes for header field %d"
747 ,msg->hfield[i].length+1, i);
748 smb_freemsgmem(msg); /* or 0 length field */
749 return(-3);
750 }
751 memset(msg->hfield_dat[i],0,msg->hfield[i].length+1); /* init to NULL */
752 if(msg->hfield[i].length
753 && !fread(msg->hfield_dat[i],msg->hfield[i].length,1,smb->shd_fp)) {
754 smb_freemsgmem(msg);
755 sprintf(smb->last_error,"reading header field data");
756 return(-6);
757 }
758 switch(msg->hfield[i].type) { /* convenience variables */
759 case SENDER:
760 if(!msg->from) {
761 msg->from=(char *)msg->hfield_dat[i];
762 break;
763 }
764 case FORWARDED: /* fall through */
765 msg->forwarded=1;
766 break;
767 case SENDERAGENT:
768 if(!msg->forwarded)
769 msg->from_agent=*(uint16_t *)msg->hfield_dat[i];
770 break;
771 case SENDEREXT:
772 if(!msg->forwarded)
773 msg->from_ext=(char *)msg->hfield_dat[i];
774 break;
775 case SENDERNETTYPE:
776 if(!msg->forwarded)
777 msg->from_net.type=*(uint16_t *)msg->hfield_dat[i];
778 break;
779 case SENDERNETADDR:
780 if(!msg->forwarded)
781 msg->from_net.addr=(char *)msg->hfield_dat[i];
782 break;
783 case REPLYTO:
784 msg->replyto=(char *)msg->hfield_dat[i];
785 break;
786 case REPLYTOEXT:
787 msg->replyto_ext=(char *)msg->hfield_dat[i];
788 break;
789 case REPLYTOAGENT:
790 msg->replyto_agent=*(uint16_t *)msg->hfield_dat[i];
791 break;
792 case REPLYTONETTYPE:
793 msg->replyto_net.type=*(uint16_t *)msg->hfield_dat[i];
794 break;
795 case REPLYTONETADDR:
796 msg->replyto_net.addr=(char *)msg->hfield_dat[i];
797 break;
798 case RECIPIENT:
799 msg->to=(char *)msg->hfield_dat[i];
800 break;
801 case RECIPIENTEXT:
802 msg->to_ext=(char *)msg->hfield_dat[i];
803 break;
804 case RECIPIENTAGENT:
805 msg->to_agent=*(uint16_t *)msg->hfield_dat[i];
806 break;
807 case RECIPIENTNETTYPE:
808 msg->to_net.type=*(uint16_t *)msg->hfield_dat[i];
809 break;
810 case RECIPIENTNETADDR:
811 msg->to_net.addr=(char *)msg->hfield_dat[i];
812 break;
813 case SUBJECT:
814 msg->subj=(char *)msg->hfield_dat[i];
815 break;
816 case RFC822MSGID:
817 msg->id=(char *)msg->hfield_dat[i];
818 break;
819 case RFC822REPLYID:
820 msg->reply_id=(char *)msg->hfield_dat[i];
821 break;
822 case USENETPATH:
823 msg->path=(char *)msg->hfield_dat[i];
824 break;
825 case USENETNEWSGROUPS:
826 msg->newsgroups=(char *)msg->hfield_dat[i];
827 break;
828 case FIDOMSGID:
829 msg->ftn_msgid=(char *)msg->hfield_dat[i];
830 break;
831 case FIDOREPLYID:
832 msg->ftn_reply=(char *)msg->hfield_dat[i];
833 break;
834 case FIDOAREA:
835 msg->ftn_area=(char *)msg->hfield_dat[i];
836 break;
837 case FIDOPID:
838 msg->ftn_pid=(char *)msg->hfield_dat[i];
839 break;
840 case FIDOFLAGS:
841 msg->ftn_flags=(char *)msg->hfield_dat[i];
842 break;
843
844 }
845 l+=msg->hfield[i].length;
846 }
847
848 if(!msg->from || !msg->to || !msg->subj) {
849 sprintf(smb->last_error,"missing required header field (from/to/subj)");
850 smb_freemsgmem(msg);
851 return(-7);
852 }
853 return(0);
854 }
855
856 /****************************************************************************/
857 /* Frees memory allocated for 'msg' */
858 /****************************************************************************/
smb_freemsgmem(smbmsg_t * msg)859 void SMBCALL smb_freemsgmem(smbmsg_t* msg)
860 {
861 uint16_t i;
862
863 if(msg->dfield) {
864 FREE(msg->dfield);
865 msg->dfield=NULL;
866 }
867 for(i=0;i<msg->total_hfields;i++)
868 if(msg->hfield_dat[i]) {
869 FREE(msg->hfield_dat[i]);
870 msg->hfield_dat[i]=NULL;
871 }
872 msg->total_hfields=0;
873 if(msg->hfield) {
874 FREE(msg->hfield);
875 msg->hfield=NULL;
876 }
877 if(msg->hfield_dat) {
878 FREE(msg->hfield_dat);
879 msg->hfield_dat=NULL;
880 }
881 }
882
883 /****************************************************************************/
884 /* Copies memory allocated for 'srcmsg' to 'msg' */
885 /****************************************************************************/
smb_copymsgmem(smbmsg_t * msg,smbmsg_t * srcmsg)886 int SMBCALL smb_copymsgmem(smbmsg_t* msg, smbmsg_t* srcmsg)
887 {
888 int i;
889
890 memcpy(msg,srcmsg,sizeof(smbmsg_t));
891
892 /* data field types/lengths */
893 if((msg->dfield=(dfield_t *)MALLOC(msg->hdr.total_dfields*sizeof(dfield_t)))==NULL)
894 return(1);
895 memcpy(msg->dfield,srcmsg->dfield,msg->hdr.total_dfields*sizeof(dfield_t));
896
897 /* header field types/lengths */
898 if((msg->hfield=(hfield_t *)MALLOC(msg->total_hfields*sizeof(hfield_t)))==NULL)
899 return(2);
900 memcpy(msg->hfield,srcmsg->hfield,msg->total_hfields*sizeof(hfield_t));
901
902 /* header field data */
903 if((msg->hfield_dat=(void* *)MALLOC(msg->total_hfields*sizeof(void*)))==NULL)
904 return(3);
905
906 for(i=0;i<msg->total_hfields;i++) {
907 if((msg->hfield_dat[i]=(char*)MALLOC(msg->hfield[i].length))==NULL)
908 return(4);
909 memcpy(msg->hfield_dat[i],srcmsg->hfield_dat[i],msg->hfield[i].length);
910 }
911
912 return(0);
913 }
914
915 /****************************************************************************/
916 /* Unlocks header for 'msg' */
917 /****************************************************************************/
smb_unlockmsghdr(smb_t * smb,smbmsg_t * msg)918 int SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
919 {
920 if(smb->shd_fp==NULL) {
921 sprintf(smb->last_error,"msgbase not open");
922 return(SMB_ERR_NOT_OPEN);
923 }
924 return(unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t)));
925 }
926
927
928 /****************************************************************************/
929 /* Adds a header field to the 'msg' structure (in memory only) */
930 /****************************************************************************/
smb_hfield(smbmsg_t * msg,uint16_t type,size_t length,void * data)931 int SMBCALL smb_hfield(smbmsg_t* msg, uint16_t type, size_t length, void* data)
932 {
933 hfield_t* vp;
934 void* *vpp;
935 int i;
936
937 i=msg->total_hfields;
938 if((vp=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL)
939 return(1);
940
941 msg->hfield=vp;
942 if((vpp=(void* *)REALLOC(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL)
943 return(2);
944
945 msg->hfield_dat=vpp;
946 msg->total_hfields++;
947 msg->hfield[i].type=type;
948 msg->hfield[i].length=length;
949 if(length) {
950 if((msg->hfield_dat[i]=(void* )MALLOC(length))==NULL)
951 return(4);
952 memcpy(msg->hfield_dat[i],data,length);
953 }
954 else
955 msg->hfield_dat[i]=NULL;
956 return(0);
957 }
958
959 /****************************************************************************/
960 /* Searches for a specific header field (by type) and returns it */
961 /****************************************************************************/
smb_get_hfield(smbmsg_t * msg,uint16_t type,hfield_t * hfield)962 void* SMBCALL smb_get_hfield(smbmsg_t* msg, uint16_t type, hfield_t* hfield)
963 {
964 int i;
965
966 for(i=0;i<msg->total_hfields;i++)
967 if(msg->hfield[i].type == type) {
968 if(hfield != NULL)
969 hfield = &msg->hfield[i];
970 return(msg->hfield_dat[i]);
971 }
972
973 return(NULL);
974 }
975
976 /****************************************************************************/
977 /* Adds a data field to the 'msg' structure (in memory only) */
978 /* Automatically figures out the offset into the data buffer from existing */
979 /* dfield lengths */
980 /****************************************************************************/
smb_dfield(smbmsg_t * msg,uint16_t type,uint32_t length)981 int SMBCALL smb_dfield(smbmsg_t* msg, uint16_t type, uint32_t length)
982 {
983 dfield_t* vp;
984 int i,j;
985
986 i=msg->hdr.total_dfields;
987 if((vp=(dfield_t *)REALLOC(msg->dfield,sizeof(dfield_t)*(i+1)))==NULL)
988 return(1);
989
990 msg->dfield=vp;
991 msg->hdr.total_dfields++;
992 msg->dfield[i].type=type;
993 msg->dfield[i].length=length;
994 for(j=msg->dfield[i].offset=0;j<i;j++)
995 msg->dfield[i].offset+=msg->dfield[j].length;
996 return(0);
997 }
998
999 /****************************************************************************/
1000 /* Checks CRC history file for duplicate crc. If found, returns 1. */
1001 /* If no dupe, adds to CRC history and returns 0, or negative if error. */
1002 /****************************************************************************/
smb_addcrc(smb_t * smb,uint32_t crc)1003 int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
1004 {
1005 char str[128];
1006 int file;
1007 int32_t length;
1008 uint32_t l, *buf;
1009 time32_t start = 0;
1010
1011 if(!smb->status.max_crcs)
1012 return(0);
1013
1014 sprintf(str,"%s.sch",smb->file);
1015 while(1) {
1016 if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,U_MODE))!=-1)
1017 break;
1018 if(errno!=EACCES && errno!=EAGAIN) {
1019 sprintf(smb->last_error,"%d opening %s", errno, str);
1020 return(-1);
1021 }
1022 if(!start)
1023 start = gtime(NULL);
1024 else
1025 if(gtime(NULL)-start >= smb->retry_time) {
1026 sprintf(smb->last_error,"timeout opening %s (retry_time=%d)"
1027 ,str,smb->retry_time);
1028 return(-2);
1029 }
1030 usleep(smb->retry_delay);
1031 }
1032
1033 length=filelength(file);
1034 if(length<0L) {
1035 close(file);
1036 sprintf(smb->last_error,"invalid file length: %d", length);
1037 return(-4);
1038 }
1039 if((buf=(uint32_t*)MALLOC(smb->status.max_crcs*4))==NULL) {
1040 close(file);
1041 sprintf(smb->last_error
1042 ,"malloc failure of %d bytes"
1043 ,smb->status.max_crcs*4);
1044 return(-3);
1045 }
1046 if((uint32_t)length>=smb->status.max_crcs*4L) { /* Reached or exceeds max crcs */
1047 read(file,buf,smb->status.max_crcs*4);
1048 for(l=0;l<smb->status.max_crcs;l++)
1049 if(crc==buf[l])
1050 break;
1051 if(l<smb->status.max_crcs) { /* Dupe CRC found */
1052 close(file);
1053 FREE(buf);
1054 sprintf(smb->last_error
1055 ,"duplicate message detected");
1056 return(1);
1057 }
1058 chsize(file,0L); /* truncate it */
1059 lseek(file,0L,SEEK_SET);
1060 write(file,buf+4,(smb->status.max_crcs-1)*4);
1061 }
1062
1063 else if(length/4) { /* Less than max crcs */
1064 read(file,buf,length);
1065 for(l=0;l<(uint32_t)(length/4);l++)
1066 if(crc==buf[l])
1067 break;
1068 if(l<(uint32_t)(length/4L)) { /* Dupe CRC found */
1069 close(file);
1070 FREE(buf);
1071 sprintf(smb->last_error
1072 ,"duplicate message detected");
1073 return(1);
1074 }
1075 }
1076
1077 lseek(file,0L,SEEK_END);
1078 write(file,&crc,sizeof(crc)); /* Write to the end */
1079 FREE(buf);
1080 close(file);
1081 return(0);
1082 }
1083
1084 /****************************************************************************/
1085 /* Creates a new message header record in the header file. */
1086 /* If storage is SMB_SELFPACK, self-packing conservative allocation is used */
1087 /* If storage is SMB_FASTALLOC, fast allocation is used */
1088 /* If storage is SMB_HYPERALLOC, no allocation tables are used (fastest) */
1089 /* This function will UN-lock the SMB header */
1090 /****************************************************************************/
smb_addmsghdr(smb_t * smb,smbmsg_t * msg,int storage)1091 int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
1092 {
1093 int i;
1094 int32_t l;
1095
1096 if(!smb->locked && smb_locksmbhdr(smb))
1097 return(1);
1098 if(smb_getstatus(smb)) {
1099 smb_unlocksmbhdr(smb);
1100 return(2);
1101 }
1102
1103 if(storage!=SMB_HYPERALLOC && (i=smb_open_ha(smb))!=0) {
1104 smb_unlocksmbhdr(smb);
1105 return(i);
1106 }
1107
1108 msg->hdr.length=smb_getmsghdrlen(msg);
1109 if(storage==SMB_HYPERALLOC)
1110 l=smb_hallochdr(smb);
1111 else if(storage==SMB_FASTALLOC)
1112 l=smb_fallochdr(smb,msg->hdr.length);
1113 else
1114 l=smb_allochdr(smb,msg->hdr.length);
1115 if(storage!=SMB_HYPERALLOC)
1116 smb_close_ha(smb);
1117 if(l==-1L) {
1118 smb_unlocksmbhdr(smb);
1119 return(-1);
1120 }
1121
1122 msg->idx.number=msg->hdr.number=smb->status.last_msg+1;
1123 msg->idx.offset=smb->status.header_offset+l;
1124 msg->idx.time=msg->hdr.when_imported.time;
1125 msg->idx.attr=msg->hdr.attr;
1126 msg->offset=smb->status.total_msgs;
1127 i=smb_putmsg(smb,msg);
1128 if(i==0) { /* success */
1129 smb->status.last_msg++;
1130 smb->status.total_msgs++;
1131 smb_putstatus(smb);
1132 }
1133 smb_unlocksmbhdr(smb);
1134 return(i);
1135 }
1136
1137 /****************************************************************************/
1138 /* Writes both header and index information for msg 'msg' */
1139 /****************************************************************************/
smb_putmsg(smb_t * smb,smbmsg_t * msg)1140 int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg)
1141 {
1142 int i;
1143
1144 i=smb_putmsghdr(smb,msg);
1145 if(i)
1146 return(i);
1147 return(smb_putmsgidx(smb,msg));
1148 }
1149
1150 /****************************************************************************/
1151 /* Writes index information for 'msg' */
1152 /* msg->idx */
1153 /* and msg->offset must be set prior to calling to this function */
1154 /* Returns 0 if everything ok */
1155 /****************************************************************************/
smb_putmsgidx(smb_t * smb,smbmsg_t * msg)1156 int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
1157 {
1158 if(smb->sid_fp==NULL) {
1159 sprintf(smb->last_error,"index not open");
1160 return(SMB_ERR_NOT_OPEN);
1161 }
1162 clearerr(smb->sid_fp);
1163 fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET);
1164 if(!fwrite(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
1165 sprintf(smb->last_error,"writing index");
1166 return(1);
1167 }
1168 fflush(smb->sid_fp);
1169 return(0);
1170 }
1171
1172 /****************************************************************************/
1173 /* Writes header information for 'msg' */
1174 /* msg->hdr.length */
1175 /* msg->idx.offset */
1176 /* and msg->offset must be set prior to calling to this function */
1177 /* Returns 0 if everything ok */
1178 /****************************************************************************/
smb_putmsghdr(smb_t * smb,smbmsg_t * msg)1179 int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
1180 {
1181 uint16_t i;
1182 uint32_t l;
1183
1184 if(smb->shd_fp==NULL) {
1185 sprintf(smb->last_error,"msgbase not open");
1186 return(SMB_ERR_NOT_OPEN);
1187 }
1188 if(msg->idx.offset<sizeof(smbhdr_t)+sizeof(smbstatus_t)
1189 || msg->idx.offset<smb->status.header_offset) {
1190 sprintf(smb->last_error,"invalid header offset: %d",msg->idx.offset);
1191 return(-7);
1192 }
1193 clearerr(smb->shd_fp);
1194 if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET)) {
1195 sprintf(smb->last_error,"seeking to %d in index",msg->idx.offset);
1196 return(-1);
1197 }
1198
1199 /**********************************/
1200 /* Set the message header ID here */
1201 /**********************************/
1202 memcpy(&msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID);
1203
1204 /************************************************/
1205 /* Write the fixed portion of the header record */
1206 /************************************************/
1207 if(!fwrite(&msg->hdr,sizeof(msghdr_t),1,smb->shd_fp)) {
1208 sprintf(smb->last_error,"writing fixed portion of header record");
1209 return(-2);
1210 }
1211
1212 /************************************************/
1213 /* Write the data fields (each is fixed length) */
1214 /************************************************/
1215 for(i=0;i<msg->hdr.total_dfields;i++)
1216 if(!fwrite(&msg->dfield[i],sizeof(dfield_t),1,smb->shd_fp)) {
1217 sprintf(smb->last_error,"writing data field");
1218 return(-3);
1219 }
1220
1221 /*******************************************/
1222 /* Write the variable length header fields */
1223 /*******************************************/
1224 for(i=0;i<msg->total_hfields;i++) {
1225 if(!fwrite(&msg->hfield[i],sizeof(hfield_t),1,smb->shd_fp)) {
1226 sprintf(smb->last_error,"writing header field");
1227 return(-4);
1228 }
1229 if(msg->hfield[i].length /* more then 0 bytes int32_t */
1230 && !fwrite(msg->hfield_dat[i],msg->hfield[i].length,1,smb->shd_fp)) {
1231 sprintf(smb->last_error,"writing header field data");
1232 return(-5);
1233 }
1234 }
1235
1236 l=smb_getmsghdrlen(msg);
1237 while(l%SHD_BLOCK_LEN) {
1238 if(fputc(0,smb->shd_fp)==EOF) {
1239 sprintf(smb->last_error,"padding header block");
1240 return(-6); /* pad block with NULL */
1241 }
1242 l++;
1243 }
1244 fflush(smb->shd_fp);
1245 return(0);
1246 }
1247
1248 /****************************************************************************/
1249 /* Creates a sub-board's initial header file */
1250 /* Truncates and deletes other associated SMB files */
1251 /****************************************************************************/
smb_create(smb_t * smb)1252 int SMBCALL smb_create(smb_t* smb)
1253 {
1254 char str[128];
1255 smbhdr_t hdr;
1256
1257 if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL) {
1258 sprintf(smb->last_error,"msgbase not open");
1259 return(SMB_ERR_NOT_OPEN);
1260 }
1261 if(filelength(fileno(smb->shd_fp))>=sizeof(smbhdr_t)+sizeof(smbstatus_t)
1262 && smb_locksmbhdr(smb)) /* header exists, so lock it */
1263 return(1);
1264 memset(&hdr,0,sizeof(smbhdr_t));
1265 memcpy(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID);
1266 hdr.version=SMB_VERSION;
1267 hdr.length=sizeof(smbhdr_t)+sizeof(smbstatus_t);
1268 smb->status.last_msg=smb->status.total_msgs=0;
1269 smb->status.header_offset=sizeof(smbhdr_t)+sizeof(smbstatus_t);
1270 rewind(smb->shd_fp);
1271 fwrite(&hdr,1,sizeof(smbhdr_t),smb->shd_fp);
1272 fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
1273 rewind(smb->shd_fp);
1274 chsize(fileno(smb->shd_fp),sizeof(smbhdr_t)+sizeof(smbstatus_t));
1275 fflush(smb->shd_fp);
1276
1277 rewind(smb->sdt_fp);
1278 chsize(fileno(smb->sdt_fp),0L);
1279 rewind(smb->sid_fp);
1280 chsize(fileno(smb->sid_fp),0L);
1281
1282 sprintf(str,"%s.sda",smb->file);
1283 remove(str); /* if it exists, delete it */
1284 sprintf(str,"%s.sha",smb->file);
1285 remove(str); /* if it exists, delete it */
1286 sprintf(str,"%s.sch",smb->file);
1287 remove(str);
1288 smb_unlocksmbhdr(smb);
1289 return(0);
1290 }
1291
1292 /****************************************************************************/
1293 /* Returns number of data blocks required to store "length" amount of data */
1294 /****************************************************************************/
smb_datblocks(uint32_t length)1295 uint32_t SMBCALL smb_datblocks(uint32_t length)
1296 {
1297 uint32_t blocks;
1298
1299 blocks=length/SDT_BLOCK_LEN;
1300 if(length%SDT_BLOCK_LEN)
1301 blocks++;
1302 return(blocks);
1303 }
1304
1305 /****************************************************************************/
1306 /* Returns number of header blocks required to store "length" size header */
1307 /****************************************************************************/
smb_hdrblocks(uint32_t length)1308 uint32_t SMBCALL smb_hdrblocks(uint32_t length)
1309 {
1310 uint32_t blocks;
1311
1312 blocks=length/SHD_BLOCK_LEN;
1313 if(length%SHD_BLOCK_LEN)
1314 blocks++;
1315 return(blocks);
1316 }
1317
1318 /****************************************************************************/
1319 /* Finds unused space in data file based on block allocation table and */
1320 /* marks space as used in allocation table. */
1321 /* File must be opened read/write DENY ALL */
1322 /* Returns offset to beginning of data (in bytes, not blocks) */
1323 /* Assumes smb_open_da() has been called */
1324 /* smb_close_da() should be called after */
1325 /* Returns negative on error */
1326 /****************************************************************************/
smb_allocdat(smb_t * smb,uint32_t length,uint16_t headers)1327 int32_t SMBCALL smb_allocdat(smb_t* smb, uint32_t length, uint16_t headers)
1328 {
1329 uint16_t i, j;
1330 uint32_t l, blocks, offset = 0;
1331
1332 if(smb->sda_fp==NULL) {
1333 sprintf(smb->last_error,"msgbase not open");
1334 return(SMB_ERR_NOT_OPEN);
1335 }
1336 blocks=smb_datblocks(length);
1337 j=0; /* j is consecutive unused block counter */
1338 fflush(smb->sda_fp);
1339 rewind(smb->sda_fp);
1340 while(!feof(smb->sda_fp)) {
1341 if(!fread(&i,2,1,smb->sda_fp))
1342 break;
1343 offset+=SDT_BLOCK_LEN;
1344 if(!i) j++;
1345 else j=0;
1346 if(j==blocks) {
1347 offset-=(blocks*SDT_BLOCK_LEN);
1348 break;
1349 }
1350 }
1351 clearerr(smb->sda_fp);
1352 fseek(smb->sda_fp,(offset/SDT_BLOCK_LEN)*2L,SEEK_SET);
1353 for(l=0;l<blocks;l++)
1354 if(!fwrite(&headers,2,1,smb->sda_fp)) {
1355 sprintf(smb->last_error,"writing allocation bytes");
1356 return(-1);
1357 }
1358 fflush(smb->sda_fp);
1359 return(offset);
1360 }
1361
1362 /****************************************************************************/
1363 /* Allocates space for data, but doesn't search for unused blocks */
1364 /* Returns negative on error */
1365 /****************************************************************************/
smb_fallocdat(smb_t * smb,uint32_t length,uint16_t headers)1366 int32_t SMBCALL smb_fallocdat(smb_t* smb, uint32_t length, uint16_t headers)
1367 {
1368 uint32_t l,blocks,offset;
1369
1370 if(smb->sda_fp==NULL) {
1371 sprintf(smb->last_error,"msgbase not open");
1372 return(SMB_ERR_NOT_OPEN);
1373 }
1374 fflush(smb->sda_fp);
1375 clearerr(smb->sda_fp);
1376 blocks=smb_datblocks(length);
1377 fseek(smb->sda_fp,0L,SEEK_END);
1378 offset=(ftell(smb->sda_fp)/2L)*SDT_BLOCK_LEN;
1379 for(l=0;l<blocks;l++)
1380 if(!fwrite(&headers,2,1,smb->sda_fp))
1381 break;
1382 fflush(smb->sda_fp);
1383 if(l<blocks) {
1384 sprintf(smb->last_error,"writing allocation bytes");
1385 return(-1L);
1386 }
1387 return(offset);
1388 }
1389
1390 /****************************************************************************/
1391 /* De-allocates space for data */
1392 /* Returns non-zero on error */
1393 /****************************************************************************/
smb_freemsgdat(smb_t * smb,uint32_t offset,uint32_t length,uint16_t headers)1394 int SMBCALL smb_freemsgdat(smb_t* smb, uint32_t offset, uint32_t length, uint16_t headers)
1395 {
1396 int da_opened = 0;
1397 int retval = 0;
1398 uint16_t i;
1399 uint32_t l, blocks;
1400
1401 if(smb->status.attr&SMB_HYPERALLOC) /* do nothing */
1402 return(0);
1403
1404 blocks=smb_datblocks(length);
1405
1406 if(smb->sda_fp==NULL) {
1407 if((i=smb_open_da(smb))!=0)
1408 return(i);
1409 da_opened=1;
1410 }
1411
1412 clearerr(smb->sda_fp);
1413 for(l=0;l<blocks;l++) {
1414 if(fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*2L,SEEK_SET)) {
1415 sprintf(smb->last_error
1416 ,"seeking to %ld of allocation file"
1417 ,((offset/SDT_BLOCK_LEN)+l)*2L);
1418 retval=1;
1419 break;
1420 }
1421 if(!fread(&i,2,1,smb->sda_fp)) {
1422 sprintf(smb->last_error,"reading allocation bytes");
1423 retval=2;
1424 break;
1425 }
1426 if(!headers || headers>i)
1427 i=0; /* don't want to go negative */
1428 else
1429 i-=headers;
1430 if(fseek(smb->sda_fp,-2L,SEEK_CUR)) {
1431 sprintf(smb->last_error,"seeking backwards 2 bytes in allocation file");
1432 retval=3;
1433 break;
1434 }
1435 if(!fwrite(&i,2,1,smb->sda_fp)) {
1436 sprintf(smb->last_error,"writing allocation bytes");
1437 retval=4;
1438 break;
1439 }
1440 }
1441 fflush(smb->sda_fp);
1442 if(da_opened)
1443 smb_close_da(smb);
1444 return(retval);
1445 }
1446
1447 /****************************************************************************/
1448 /* Adds to data allocation records for blocks starting at 'offset' */
1449 /* Returns non-zero on error */
1450 /****************************************************************************/
smb_incdat(smb_t * smb,uint32_t offset,uint32_t length,uint16_t headers)1451 int SMBCALL smb_incdat(smb_t* smb, uint32_t offset, uint32_t length, uint16_t headers)
1452 {
1453 uint16_t i;
1454 uint32_t l, blocks;
1455
1456 if(smb->sda_fp==NULL) {
1457 sprintf(smb->last_error,"msgbase not open");
1458 return(SMB_ERR_NOT_OPEN);
1459 }
1460 clearerr(smb->sda_fp);
1461 blocks=smb_datblocks(length);
1462 for(l=0;l<blocks;l++) {
1463 fseek(smb->sda_fp,((offset/SDT_BLOCK_LEN)+l)*2L,SEEK_SET);
1464 if(!fread(&i,2,1,smb->sda_fp)) {
1465 sprintf(smb->last_error,"reading allocation record");
1466 return(1);
1467 }
1468 i+=headers;
1469 fseek(smb->sda_fp,-2L,SEEK_CUR);
1470 if(!fwrite(&i,2,1,smb->sda_fp)) {
1471 sprintf(smb->last_error,"writing allocation record");
1472 return(2);
1473 }
1474 }
1475 fflush(smb->sda_fp);
1476 return(0);
1477 }
1478
1479 /****************************************************************************/
1480 /* De-allocates blocks for header record */
1481 /* Returns non-zero on error */
1482 /****************************************************************************/
smb_freemsghdr(smb_t * smb,uint32_t offset,uint32_t length)1483 int SMBCALL smb_freemsghdr(smb_t* smb, uint32_t offset, uint32_t length)
1484 {
1485 uint8_t c = 0;
1486 uint32_t l,blocks;
1487
1488 if(smb->sha_fp==NULL) {
1489 sprintf(smb->last_error,"msgbase not open");
1490 return(SMB_ERR_NOT_OPEN);
1491 }
1492 clearerr(smb->sha_fp);
1493 blocks=smb_hdrblocks(length);
1494 fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET);
1495 for(l=0;l<blocks;l++)
1496 if(!fwrite(&c,1,1,smb->sha_fp)) {
1497 sprintf(smb->last_error,"writing allocation record");
1498 return(1);
1499 }
1500 fflush(smb->sha_fp);
1501 return(0);
1502 }
1503
1504 /****************************************************************************/
1505 /* Frees all allocated header and data blocks for 'msg' */
1506 /****************************************************************************/
smb_freemsg(smb_t * smb,smbmsg_t * msg)1507 int SMBCALL smb_freemsg(smb_t* smb, smbmsg_t* msg)
1508 {
1509 int i;
1510 uint16_t x;
1511
1512 if(smb->status.attr&SMB_HYPERALLOC) /* Nothing to do */
1513 return(0);
1514
1515 for(x=0;x<msg->hdr.total_dfields;x++) {
1516 if((i=smb_freemsgdat(smb,msg->hdr.offset+msg->dfield[x].offset
1517 ,msg->dfield[x].length,1))!=0)
1518 return(i);
1519 }
1520 return(smb_freemsghdr(smb,msg->idx.offset-smb->status.header_offset
1521 ,msg->hdr.length));
1522 }
1523
1524 /****************************************************************************/
1525 /* Finds unused space in header file based on block allocation table and */
1526 /* marks space as used in allocation table. */
1527 /* File must be opened read/write DENY ALL */
1528 /* Returns offset to beginning of header (in bytes, not blocks) */
1529 /* Assumes smb_open_ha() has been called */
1530 /* smb_close_ha() should be called after */
1531 /* Returns -1L on error */
1532 /****************************************************************************/
smb_allochdr(smb_t * smb,uint32_t length)1533 int32_t SMBCALL smb_allochdr(smb_t* smb, uint32_t length)
1534 {
1535 uint8_t c;
1536 uint16_t i;
1537 uint32_t l, blocks, offset = 0;
1538
1539 if(smb->sha_fp==NULL) {
1540 sprintf(smb->last_error,"msgbase not open");
1541 return(SMB_ERR_NOT_OPEN);
1542 }
1543 blocks=smb_hdrblocks(length);
1544 i=0; /* i is consecutive unused block counter */
1545 fflush(smb->sha_fp);
1546 rewind(smb->sha_fp);
1547 while(!feof(smb->sha_fp)) {
1548 if(!fread(&c,1,1,smb->sha_fp))
1549 break;
1550 offset+=SHD_BLOCK_LEN;
1551 if(!c) i++;
1552 else i=0;
1553 if(i==blocks) {
1554 offset-=(blocks*SHD_BLOCK_LEN);
1555 break;
1556 }
1557 }
1558 clearerr(smb->sha_fp);
1559 fseek(smb->sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET);
1560 c=1;
1561 for(l=0;l<blocks;l++)
1562 if(!fwrite(&c,1,1,smb->sha_fp)) {
1563 sprintf(smb->last_error,"writing allocation record");
1564 return(-1L);
1565 }
1566 fflush(smb->sha_fp);
1567 return(offset);
1568 }
1569
1570 /****************************************************************************/
1571 /* Allocates space for index, but doesn't search for unused blocks */
1572 /* Returns -1L on error */
1573 /****************************************************************************/
smb_fallochdr(smb_t * smb,uint32_t length)1574 int32_t SMBCALL smb_fallochdr(smb_t* smb, uint32_t length)
1575 {
1576 uint8_t c = 1;
1577 uint32_t l,blocks,offset;
1578
1579 if(smb->sha_fp==NULL) {
1580 sprintf(smb->last_error,"msgbase not open");
1581 return(SMB_ERR_NOT_OPEN);
1582 }
1583 blocks=smb_hdrblocks(length);
1584 fflush(smb->sha_fp);
1585 clearerr(smb->sha_fp);
1586 fseek(smb->sha_fp,0L,SEEK_END);
1587 offset=ftell(smb->sha_fp)*SHD_BLOCK_LEN;
1588 for(l=0;l<blocks;l++)
1589 if(!fwrite(&c,1,1,smb->sha_fp)) {
1590 sprintf(smb->last_error,"writing allocation record");
1591 return(-1L);
1592 }
1593 fflush(smb->sha_fp);
1594 return(offset);
1595 }
1596
1597 /************************************************************************/
1598 /* Allocate header blocks using Hyper Allocation */
1599 /* this function should be most likely not be called from anywhere but */
1600 /* smb_addmsghdr() */
1601 /************************************************************************/
smb_hallochdr(smb_t * smb)1602 int32_t SMBCALL smb_hallochdr(smb_t* smb)
1603 {
1604 uint32_t l;
1605
1606 if(smb->shd_fp==NULL) {
1607 sprintf(smb->last_error,"msgbase not open");
1608 return(SMB_ERR_NOT_OPEN);
1609 }
1610 fflush(smb->shd_fp);
1611 fseek(smb->shd_fp,0L,SEEK_END);
1612 l=ftell(smb->shd_fp);
1613 if(l<smb->status.header_offset) /* Header file truncated?!? */
1614 return(smb->status.header_offset);
1615 while((l-smb->status.header_offset)%SHD_BLOCK_LEN) /* Even block boundry */
1616 l++;
1617 return(l-smb->status.header_offset);
1618 }
1619
1620 /************************************************************************/
1621 /* Allocate data blocks using Hyper Allocation */
1622 /* smb_locksmbhdr() should be called before this function and not */
1623 /* unlocked until all data fields for this message have been written */
1624 /* to the SDT file */
1625 /************************************************************************/
smb_hallocdat(smb_t * smb)1626 int32_t SMBCALL smb_hallocdat(smb_t* smb)
1627 {
1628 int32_t l;
1629
1630 if(smb->sdt_fp==NULL) {
1631 sprintf(smb->last_error,"msgbase not open");
1632 return(SMB_ERR_NOT_OPEN);
1633 }
1634 fflush(smb->sdt_fp);
1635 fseek(smb->sdt_fp,0L,SEEK_END);
1636 l=ftell(smb->sdt_fp);
1637 if(l<=0)
1638 return(l);
1639 while(l%SDT_BLOCK_LEN) /* Make sure even block boundry */
1640 l++;
1641 return(l);
1642 }
1643
1644
smb_feof(FILE * fp)1645 int SMBCALL smb_feof(FILE* fp)
1646 {
1647 return(feof(fp));
1648 }
1649
smb_ferror(FILE * fp)1650 int SMBCALL smb_ferror(FILE* fp)
1651 {
1652 return(ferror(fp));
1653 }
1654
smb_fflush(FILE * fp)1655 int SMBCALL smb_fflush(FILE* fp)
1656 {
1657 return(fflush(fp));
1658 }
1659
smb_fgetc(FILE * fp)1660 int SMBCALL smb_fgetc(FILE* fp)
1661 {
1662 return(fgetc(fp));
1663 }
1664
smb_fputc(int ch,FILE * fp)1665 int SMBCALL smb_fputc(int ch, FILE* fp)
1666 {
1667 return(fputc(ch,fp));
1668 }
1669
smb_fseek(FILE * fp,int32_t offset,int whence)1670 int SMBCALL smb_fseek(FILE* fp, int32_t offset, int whence)
1671 {
1672 return(fseek(fp,offset,whence));
1673 }
1674
smb_ftell(FILE * fp)1675 int32_t SMBCALL smb_ftell(FILE* fp)
1676 {
1677 return(ftell(fp));
1678 }
1679
smb_fgetlength(FILE * fp)1680 int32_t SMBCALL smb_fgetlength(FILE* fp)
1681 {
1682 return(filelength(fileno(fp)));
1683 }
1684
smb_fsetlength(FILE * fp,int32_t length)1685 int SMBCALL smb_fsetlength(FILE* fp, int32_t length)
1686 {
1687 return(chsize(fileno(fp),length));
1688 }
1689
smb_rewind(FILE * fp)1690 void SMBCALL smb_rewind(FILE* fp)
1691 {
1692 rewind(fp);
1693 }
1694
smb_clearerr(FILE * fp)1695 void SMBCALL smb_clearerr(FILE* fp)
1696 {
1697 clearerr(fp);
1698 }
1699
smb_fread(void HUGE16 * buf,int32_t bytes,FILE * fp)1700 int32_t SMBCALL smb_fread(void HUGE16* buf, int32_t bytes, FILE* fp)
1701 {
1702 #ifdef __FLAT__
1703 return(fread(buf,1,bytes,fp));
1704 #else
1705 int32_t count;
1706
1707 for(count=bytes;count>0x7fff;count-=0x7fff,(char*)buf+=0x7fff)
1708 if(fread((char*)buf,1,0x7fff,fp)!=0x7fff)
1709 return(bytes-count);
1710 if(fread((char*)buf,1,(size_t)count,fp)!=(size_t)count)
1711 return(bytes-count);
1712 return(bytes);
1713 #endif
1714 }
1715
smb_fwrite(void HUGE16 * buf,int32_t bytes,FILE * fp)1716 int32_t SMBCALL smb_fwrite(void HUGE16* buf, int32_t bytes, FILE* fp)
1717 {
1718 #ifdef __FLAT__
1719 return(fwrite(buf,1,bytes,fp));
1720 #else
1721 int32_t count;
1722
1723 for(count=bytes;count>0x7fff;count-=0x7fff,(char*)buf+=0x7fff)
1724 if(fwrite((char*)buf,1,0x7fff,fp)!=0x7fff)
1725 return(bytes-count);
1726 if(fwrite((char*)buf,1,(size_t)count,fp)!=(size_t)count)
1727 return(bytes-count);
1728 return(bytes);
1729 #endif
1730 }
1731
1732 /* End of SMBLIB.C */
1733