home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / BBS / SMB_111.ZIP / SMBLIB.C < prev    next >
C/C++ Source or Header  |  1994-05-17  |  31KB  |  1,027 lines

  1. /* SMBLIB.C */
  2.  
  3. #include "smblib.h"
  4.  
  5. /****************************************************************************/
  6. /* Open a message base of name 'smb_file'                                   */
  7. /* Opens files for READing messages or updating message indices only        */
  8. /****************************************************************************/
  9. int smb_open(int retry_time)
  10. {
  11.     int file;
  12.     char str[128];
  13.     smbhdr_t hdr;
  14.  
  15. sprintf(str,"%s.SHD",smb_file);
  16. if((file=open(str,O_RDWR|O_CREAT|O_BINARY|O_DENYNONE,S_IWRITE|S_IREAD))==-1
  17.     || (shd_fp=fdopen(file,"r+b"))==NULL) {
  18.     if(file!=-1)
  19.         close(file);
  20.     return(2); }
  21.  
  22. if(filelength(file)>=sizeof(smbhdr_t)) {
  23.     setvbuf(shd_fp,NULL,_IONBF,0);
  24.     if(smb_locksmbhdr(retry_time)) {
  25.         fclose(shd_fp);
  26.         return(-1); }
  27.     memset(&hdr,0,sizeof(smbhdr_t));
  28.     fread(&hdr,sizeof(smbhdr_t),1,shd_fp);
  29.     if(memcmp(hdr.id,"SMB\x1a",4)) {
  30.         fclose(shd_fp);
  31.         return(-2); }
  32.     if(hdr.version<0x110) {         /* Compatibility check */
  33.         fclose(shd_fp);
  34.         return(-3); }
  35.     smb_unlocksmbhdr();
  36.     rewind(shd_fp); }
  37.  
  38. setvbuf(shd_fp,NULL,_IOFBF,SHD_BLOCK_LEN);
  39.  
  40. sprintf(str,"%s.SDT",smb_file);
  41. if((file=open(str,O_RDWR|O_CREAT|O_BINARY|O_DENYNONE,S_IWRITE|S_IREAD))==-1
  42.     || (sdt_fp=fdopen(file,"r+b"))==NULL) {
  43.     if(file!=-1)
  44.         close(file);
  45.     fclose(shd_fp);
  46.     return(1); }
  47. setvbuf(sdt_fp,NULL,_IOFBF,2*1024);
  48.  
  49. sprintf(str,"%s.SID",smb_file);
  50. if((file=open(str,O_RDWR|O_CREAT|O_BINARY|O_DENYNONE,S_IWRITE|S_IREAD))==-1
  51.     || (sid_fp=fdopen(file,"r+b"))==NULL) {
  52.     if(file!=-1)
  53.         close(file);
  54.     fclose(sdt_fp);
  55.     fclose(shd_fp);
  56.     return(3); }
  57. setvbuf(sid_fp,NULL,_IOFBF,2*1024);
  58.  
  59. return(0);
  60. }
  61.  
  62. /****************************************************************************/
  63. /* Closes the currently open message base                                    */
  64. /****************************************************************************/
  65. void smb_close(void)
  66. {
  67. fclose(sid_fp);
  68. fclose(shd_fp);
  69. fclose(sdt_fp);
  70. sid_fp=shd_fp=sdt_fp=NULL;
  71. }
  72.  
  73. /****************************************************************************/
  74. /* Opens the data block allocation table message base 'smb_file'            */
  75. /* Retrys for retry_time number of seconds                                    */
  76. /* Return 0 on success, non-zero otherwise                                    */
  77. /****************************************************************************/
  78. int smb_open_da(int retry_time)
  79. {
  80.     int file;
  81.     char str[128];
  82.     long start;
  83.  
  84. start=time(NULL);
  85. sprintf(str,"%s.SDA",smb_file);
  86. while(1) {
  87.     if((file=open(str,O_RDWR|O_CREAT|O_BINARY|O_DENYALL,S_IWRITE|S_IREAD))!=-1)
  88.         break;
  89.     if(errno!=EACCES)
  90.         return(-1);
  91.     if(time(NULL)-start>=retry_time)
  92.         return(-2); }
  93. if((sda_fp=fdopen(file,"r+b"))==NULL)
  94.     return(-3);
  95. setvbuf(sda_fp,NULL,_IOFBF,2*1024);
  96. return(0);
  97. }
  98.  
  99. /****************************************************************************/
  100. /* Opens the header block allocation table for message base 'smb_file'      */
  101. /* Retrys for retry_time number of seconds                                    */
  102. /* Return 0 on success, non-zero otherwise                                    */
  103. /****************************************************************************/
  104. int smb_open_ha(int retry_time)
  105. {
  106.     int file;
  107.     char str[128];
  108.     long start;
  109.  
  110. start=time(NULL);
  111. sprintf(str,"%s.SHA",smb_file);
  112. while(1) {
  113.     if((file=open(str,O_RDWR|O_CREAT|O_BINARY|O_DENYALL,S_IWRITE|S_IREAD))!=-1)
  114.         break;
  115.     if(errno!=EACCES)
  116.         return(-1);
  117.     if(time(NULL)-start>=retry_time)
  118.         return(-2); }
  119. if((sha_fp=fdopen(file,"r+b"))==NULL)
  120.     return(-3);
  121. setvbuf(sha_fp,NULL,_IOFBF,2*1024);
  122. return(0);
  123. }
  124.  
  125. /****************************************************************************/
  126. /* If the parameter 'push' is non-zero, this function stores the currently  */
  127. /* open message base to the "virtual" smb stack. Up to SMB_STACK_LEN        */
  128. /* message bases may be stored (defined in SMBDEFS.H).                        */
  129. /* If the parameter 'push' is zero, this function restores a message base   */
  130. /* previously saved with this same function.                                */
  131. /* SMB_STACK_PUSH and SMB_STACK_POP are defined in SMBDEFS.H as 1 and 0     */
  132. /* and should be used for the argument for clearity in reading.             */
  133. /* If the current message base is not open, the push function does nothing. */
  134. /* Returns 0 on success, non-zero if stack full.                            */
  135. /* if 'push' is zero (SMB_STACK_POP), it always returns 0.                  */
  136. /****************************************************************************/
  137. int smb_stack(int push)
  138. {
  139.     static char stack_file[SMB_STACK_LEN][128];
  140.     static FILE *stack_sdt[SMB_STACK_LEN],
  141.                 *stack_shd[SMB_STACK_LEN],
  142.                 *stack_sid[SMB_STACK_LEN],
  143.                 *stack_sda[SMB_STACK_LEN],
  144.                 *stack_sha[SMB_STACK_LEN];
  145.     static int    stack_idx;
  146.  
  147. if(push) {
  148.     if(stack_idx>=SMB_STACK_LEN)
  149.         return(1);
  150.     if(!shd_fp) /* Message base not open */
  151.         return(0);
  152.     memcpy(stack_file[stack_idx],smb_file,128);
  153.     stack_sdt[stack_idx]=sdt_fp;
  154.     stack_shd[stack_idx]=shd_fp;
  155.     stack_sid[stack_idx]=sid_fp;
  156.     stack_sda[stack_idx]=sda_fp;
  157.     stack_sha[stack_idx]=sha_fp;
  158.     stack_idx++;
  159.     return(0); }
  160. /* pop */
  161. if(!stack_idx)    /* Nothing on the stack, so do nothing */
  162.     return(0);
  163. stack_idx--;
  164. memcpy(smb_file,stack_file[stack_idx],128);
  165. sdt_fp=stack_sdt[stack_idx];
  166. shd_fp=stack_shd[stack_idx];
  167. sid_fp=stack_sid[stack_idx];
  168. sda_fp=stack_sda[stack_idx];
  169. sha_fp=stack_sha[stack_idx];
  170. return(0);
  171. }
  172.  
  173. /****************************************************************************/
  174. /* Truncates header file                                                    */
  175. /* Retrys for retry_time number of seconds                                    */
  176. /* Return 0 on success, non-zero otherwise                                    */
  177. /****************************************************************************/
  178. int smb_trunchdr(int retry_time)
  179. {
  180.     long start;
  181.  
  182. start=time(NULL);
  183. rewind(shd_fp);
  184. while(1) {
  185.     if(!chsize(fileno(shd_fp),0L))
  186.         break;
  187.     if(errno!=EACCES)
  188.         return(-1);
  189.     if(time(NULL)-start>=retry_time)        /* Time-out */
  190.         return(-2); }
  191. return(0);
  192. }
  193.  
  194. /*********************************/
  195. /* Message Base Header Functions */
  196. /*********************************/
  197.  
  198. /****************************************************************************/
  199. /* Attempts for retry_time number of seconds to lock the message base hdr    */
  200. /****************************************************************************/
  201. int smb_locksmbhdr(int retry_time)
  202. {
  203.     ulong start;
  204.  
  205. start=time(NULL);
  206. while(1) {
  207.     if(!lock(fileno(shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t)))
  208.         return(0);
  209.     if(time(NULL)-start>=retry_time)
  210.         break; }
  211. return(-1);
  212. }
  213.  
  214. /****************************************************************************/
  215. /* Read the SMB header from the hader file and place into "status"          */
  216. /****************************************************************************/
  217. int smb_getstatus(smbstatus_t *status)
  218. {
  219.     char    str[128];
  220.     int     i;
  221.  
  222. setvbuf(shd_fp,NULL,_IONBF,0);
  223. clearerr(shd_fp);
  224. fseek(shd_fp,sizeof(smbhdr_t),SEEK_SET);
  225. i=fread(status,1,sizeof(smbstatus_t),shd_fp);
  226. setvbuf(shd_fp,NULL,_IOFBF,SHD_BLOCK_LEN);
  227. if(i==sizeof(smbstatus_t))
  228.     return(0);
  229. return(1);
  230. }
  231.  
  232. /****************************************************************************/
  233. /* Writes message base header                                                */
  234. /****************************************************************************/
  235. int smb_putstatus(smbstatus_t status)
  236. {
  237.     int i;
  238.  
  239. clearerr(shd_fp);
  240. fseek(shd_fp,sizeof(smbhdr_t),SEEK_SET);
  241. i=fwrite(&status,1,sizeof(smbstatus_t),shd_fp);
  242. fflush(shd_fp);
  243. if(i==sizeof(smbstatus_t))
  244.     return(0);
  245. return(1);
  246. }
  247.  
  248. /****************************************************************************/
  249. /* Unlocks previously locks message base header                             */
  250. /****************************************************************************/
  251. int smb_unlocksmbhdr()
  252. {
  253. return(unlock(fileno(shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t)));
  254. }
  255.  
  256. /********************************/
  257. /* Individual Message Functions */
  258. /********************************/
  259.  
  260. /****************************************************************************/
  261. /* Attempts for retry_time number of seconds to lock the header for 'msg'   */
  262. /****************************************************************************/
  263. int smb_lockmsghdr(smbmsg_t msg, int retry_time)
  264. {
  265.     ulong start;
  266.  
  267. start=time(NULL);
  268. while(1) {
  269.     if(!lock(fileno(shd_fp),msg.idx.offset,sizeof(msghdr_t)))
  270.         return(0);
  271.     if(time(NULL)-start>=retry_time)
  272.         break; }
  273. return(-1);
  274. }
  275.  
  276. /****************************************************************************/
  277. /* Fills msg->idx with message index based on msg->hdr.number                */
  278. /* OR if msg->hdr.number is 0, based on msg->offset (physical offset).        */
  279. /* if msg.hdr.number does not equal 0, then msg->offset is filled too.        */
  280. /* Either msg->hdr.number or msg->offset must be initialized before         */
  281. /* calling this function                                                    */
  282. /* Returns 1 if message number wasn't found, 0 if it was                    */
  283. /****************************************************************************/
  284. int smb_getmsgidx(smbmsg_t *msg)
  285. {
  286.     idxrec_t idx;
  287.     ulong     l,length,total,bot,top;
  288.  
  289. clearerr(sid_fp);
  290. if(!msg->hdr.number) {
  291.     fseek(sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET);
  292.     if(!fread(&msg->idx,sizeof(idxrec_t),1,sid_fp))
  293.         return(1);
  294.     return(0); }
  295.  
  296. length=filelength(fileno(sid_fp));
  297. if(!length)
  298.     return(1);
  299. total=length/sizeof(idxrec_t);
  300. if(!total)
  301.     return(1);
  302.  
  303. bot=0;
  304. top=total;
  305. l=total/2; /* Start at middle index */
  306. while(1) {
  307.     fseek(sid_fp,l*sizeof(idxrec_t),SEEK_SET);
  308.     if(!fread(&idx,sizeof(idxrec_t),1,sid_fp))
  309.         return(1);
  310.     if(bot==top-1 && idx.number!=msg->hdr.number)
  311.         return(1);
  312.     if(idx.number>msg->hdr.number) {
  313.         top=l;
  314.         l=bot+((top-bot)/2);
  315.         continue; }
  316.     if(idx.number<msg->hdr.number) {
  317.         bot=l;
  318.         l=top-((top-bot)/2);
  319.         continue; }
  320.     break; }
  321. msg->idx=idx;
  322. msg->offset=l;
  323. return(0);
  324. }
  325.  
  326. /****************************************************************************/
  327. /* Reads the last index record in the open message base                     */
  328. /****************************************************************************/
  329. int smb_getlastidx(idxrec_t *idx)
  330. {
  331.     long length;
  332.  
  333. clearerr(sid_fp);
  334. length=filelength(fileno(sid_fp));
  335. if(length<sizeof(idxrec_t))
  336.     return(-1);
  337. fseek(sid_fp,length-sizeof(idxrec_t),SEEK_SET);
  338. if(!fread(idx,sizeof(idxrec_t),1,sid_fp))
  339.     return(-2);
  340. return(0);
  341. }
  342.  
  343. /****************************************************************************/
  344. /* Figures out the total length of the header record for 'msg'              */
  345. /* Returns length                                                            */
  346. /****************************************************************************/
  347. int smb_getmsghdrlen(smbmsg_t msg)
  348. {
  349.     int i;
  350.  
  351. /* fixed portion */
  352. msg.hdr.length=sizeof(msghdr_t);
  353. /* data fields */
  354. msg.hdr.length+=msg.hdr.total_dfields*sizeof(dfield_t);
  355. /* header fields */
  356. for(i=0;i<msg.total_hfields;i++) {
  357.     msg.hdr.length+=sizeof(hfield_t);
  358.     msg.hdr.length+=msg.hfield[i].length; }
  359. return(msg.hdr.length);
  360. }
  361.  
  362. /****************************************************************************/
  363. /* Figures out the total length of the data buffer for 'msg'                */
  364. /* Returns length                                                            */
  365. /****************************************************************************/
  366. long smb_getmsgdatlen(smbmsg_t msg)
  367. {
  368.     int i;
  369.     ulong length=0L;
  370.  
  371. for(i=0;i<msg.hdr.total_dfields;i++)
  372.     length+=msg.dfield[i].length;
  373. return(length);
  374. }
  375.  
  376. /****************************************************************************/
  377. /* Read header information into 'msg' structure                             */
  378. /* msg->idx.offset must be set before calling this function                 */
  379. /* Must call smb_freemsgmem() to free memory allocated for var len strs     */
  380. /* Returns 0 on success, non-zero if error                                    */
  381. /****************************************************************************/
  382. int smb_getmsghdr(smbmsg_t *msg)
  383. {
  384.     ushort    i;
  385.     int     forwarded=0;
  386.     ulong    l,offset;
  387.     idxrec_t idx;
  388.  
  389. rewind(shd_fp);     // was clearerr()
  390. fseek(shd_fp,msg->idx.offset,SEEK_SET);
  391. idx=msg->idx;
  392. offset=msg->offset;
  393. memset(msg,0,sizeof(smbmsg_t));
  394. msg->idx=idx;
  395. msg->offset=offset;
  396. if(!fread(&msg->hdr,sizeof(msghdr_t),1,shd_fp))
  397.     return(-1);
  398. if(memcmp(msg->hdr.id,"SHD\x1a",4))
  399.     return(-2);
  400. if(msg->hdr.version<0x110)
  401.     return(-9);
  402. l=sizeof(msghdr_t);
  403. if(msg->hdr.total_dfields && (msg->dfield
  404.     =(dfield_t *)MALLOC(sizeof(dfield_t)*msg->hdr.total_dfields))==NULL) {
  405.     smb_freemsgmem(*msg);
  406.     return(-3); }
  407. i=0;
  408. while(i<msg->hdr.total_dfields && l<msg->hdr.length) {
  409.     if(!fread(&msg->dfield[i],sizeof(dfield_t),1,shd_fp)) {
  410.         smb_freemsgmem(*msg);
  411.         return(-4); }
  412.     i++;
  413.     l+=sizeof(dfield_t); }
  414. if(i<msg->hdr.total_dfields) {
  415.     smb_freemsgmem(*msg);
  416.     return(-8); }
  417.  
  418. while(l<msg->hdr.length) {
  419.     i=msg->total_hfields;
  420.     if((msg->hfield_dat=(void **)REALLOC(msg->hfield_dat,sizeof(void *)*(i+1)))
  421.         ==NULL) {
  422.         smb_freemsgmem(*msg);
  423.         return(-3); }
  424.     if((msg->hfield=(hfield_t *)REALLOC(msg->hfield
  425.         ,sizeof(hfield_t)*(i+1)))==NULL) {
  426.         smb_freemsgmem(*msg);
  427.         return(-3); }
  428.     msg->total_hfields++;
  429.     if(!fread(&msg->hfield[i],sizeof(hfield_t),1,shd_fp)) {
  430.         smb_freemsgmem(*msg);
  431.         return(-5); }
  432.     l+=sizeof(hfield_t);
  433.     if((msg->hfield_dat[i]=(char *)MALLOC(msg->hfield[i].length+1))
  434.         ==NULL) {            /* Allocate 1 extra for NULL terminator */
  435.         smb_freemsgmem(*msg);  /* or 0 length field */
  436.         return(-3); }
  437.     memset(msg->hfield_dat[i],0,msg->hfield[i].length+1);  /* init to NULL */
  438.     if(msg->hfield[i].length
  439.         && !fread(msg->hfield_dat[i],msg->hfield[i].length,1,shd_fp)) {
  440.         smb_freemsgmem(*msg);
  441.         return(-6); }
  442.  
  443.     switch(msg->hfield[i].type) {    /* convenience variables */
  444.         case SENDER:
  445.             if(!msg->from) {
  446.                 msg->from=msg->hfield_dat[i];
  447.                 break; }
  448.         case FORWARDED:     /* fall through */
  449.             forwarded=1;
  450.             break;
  451.         case SENDERAGENT:
  452.             if(!forwarded)
  453.                 msg->from_agent=*(ushort *)msg->hfield_dat[i];
  454.             break;
  455.         case SENDEREXT:
  456.             if(!forwarded)
  457.                 msg->from_ext=msg->hfield_dat[i];
  458.             break;
  459.         case SENDERNETTYPE:
  460.             if(!forwarded)
  461.                 msg->from_net.type=*(ushort *)msg->hfield_dat[i];
  462.             break;
  463.         case SENDERNETADDR:
  464.             if(!forwarded)
  465.                 msg->from_net.addr=msg->hfield_dat[i];
  466.             break;
  467.         case REPLYTO:
  468.             msg->replyto=msg->hfield_dat[i];
  469.             break;
  470.         case REPLYTOEXT:
  471.             msg->replyto_ext=msg->hfield_dat[i];
  472.             break;
  473.         case REPLYTOAGENT:
  474.             msg->replyto_agent=*(ushort *)msg->hfield_dat[i];
  475.             break;
  476.         case REPLYTONETTYPE:
  477.             msg->replyto_net.type=*(ushort *)msg->hfield_dat[i];
  478.             break;
  479.         case REPLYTONETADDR:
  480.             msg->replyto_net.addr=msg->hfield_dat[i];
  481.             break;
  482.         case RECIPIENT:
  483.             msg->to=msg->hfield_dat[i];
  484.             break;
  485.         case RECIPIENTEXT:
  486.             msg->to_ext=msg->hfield_dat[i];
  487.             break;
  488.         case RECIPIENTAGENT:
  489.             msg->to_agent=*(ushort *)msg->hfield_dat[i];
  490.             break;
  491.         case RECIPIENTNETTYPE:
  492.             msg->to_net.type=*(ushort *)msg->hfield_dat[i];
  493.             break;
  494.         case RECIPIENTNETADDR:
  495.             msg->to_net.addr=msg->hfield_dat[i];
  496.             break;
  497.         case SUBJECT:
  498.             msg->subj=msg->hfield_dat[i];
  499.             break; }
  500.     l+=msg->hfield[i].length; }
  501.  
  502. if(!msg->from || !msg->to || !msg->subj) {
  503.     smb_freemsgmem(*msg);
  504.     return(-7); }
  505. return(0);
  506. }
  507.  
  508. /****************************************************************************/
  509. /* Frees memory allocated for 'msg'                                         */
  510. /****************************************************************************/
  511. void smb_freemsgmem(smbmsg_t msg)
  512. {
  513.     ushort    i;
  514.  
  515. if(msg.dfield)
  516.     FREE(msg.dfield);
  517. for(i=0;i<msg.total_hfields;i++)
  518.     if(msg.hfield_dat[i])
  519.         FREE(msg.hfield_dat[i]);
  520. if(msg.hfield)
  521.     FREE(msg.hfield);
  522. if(msg.hfield_dat)
  523.     FREE(msg.hfield_dat);
  524. }
  525.  
  526. /****************************************************************************/
  527. /* Unlocks header for 'msg'                                                 */
  528. /****************************************************************************/
  529. int smb_unlockmsghdr(smbmsg_t msg)
  530. {
  531. return(unlock(fileno(shd_fp),msg.idx.offset,sizeof(msghdr_t)));
  532. }
  533.  
  534.  
  535. /****************************************************************************/
  536. /* Adds an header field to the 'msg' structure (in memory only)             */
  537. /****************************************************************************/
  538. int smb_hfield(smbmsg_t *msg, ushort type, ushort length, void *data)
  539. {
  540.     int i;
  541.  
  542. i=msg->total_hfields;
  543. if((msg->hfield=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))
  544.     ==NULL)
  545.     return(1);
  546. if((msg->hfield_dat=(void **)REALLOC(msg->hfield_dat,sizeof(void *)*(i+1)))
  547.     ==NULL)
  548.     return(2);
  549. msg->total_hfields++;
  550. msg->hfield[i].type=type;
  551. msg->hfield[i].length=length;
  552. if(length) {
  553.     if((msg->hfield_dat[i]=(void *)MALLOC(length))==NULL)
  554.         return(4);
  555.     memcpy(msg->hfield_dat[i],data,length); }
  556. else
  557.     msg->hfield_dat[i]=NULL;
  558. return(0);
  559. }
  560.  
  561. /****************************************************************************/
  562. /* Adds a data field to the 'msg' structure (in memory only)                */
  563. /* Automatically figures out the offset into the data buffer from existing    */
  564. /* dfield lengths                                                            */
  565. /****************************************************************************/
  566. int smb_dfield(smbmsg_t *msg, ushort type, ulong length)
  567. {
  568.     int i,j;
  569.  
  570. i=msg->hdr.total_dfields;
  571. if((msg->dfield=(dfield_t *)REALLOC(msg->dfield,sizeof(dfield_t)*(i+1)))
  572.     ==NULL)
  573.     return(1);
  574. msg->hdr.total_dfields++;
  575. msg->dfield[i].type=type;
  576. msg->dfield[i].length=length;
  577. for(j=msg->dfield[i].offset=0;j<i;j++)
  578.     msg->dfield[i].offset+=msg->dfield[j].length;
  579. return(0);
  580. }
  581.  
  582. /****************************************************************************/
  583. /* Checks CRC history file for duplicate crc. If found, returns 1.            */
  584. /* If no dupe, adds to CRC history and returns 0, or negative if error.     */
  585. /****************************************************************************/
  586. int smb_addcrc(ulong max_crcs, ulong crc, int retry_time)
  587. {
  588.     char    str[128];
  589.     int     file;
  590.     long    length;
  591.     ulong    l,*buf;
  592.     time_t    start;
  593.  
  594. if(!max_crcs)
  595.     return(0);
  596. start=time(NULL);
  597. sprintf(str,"%s.SCH",smb_file);
  598. while(1) {
  599.     if((file=open(str,O_RDWR|O_CREAT|O_BINARY|O_DENYALL,S_IWRITE|S_IREAD))!=-1)
  600.         break;
  601.     if(errno!=EACCES)
  602.         return(-1);
  603.     if(time(NULL)-start>=retry_time)
  604.         return(-2); }
  605. length=filelength(file);
  606. if(length<0L) {
  607.     close(file);
  608.     return(-4); }
  609. if((buf=(ulong *)MALLOC(max_crcs*4))==NULL) {
  610.     close(file);
  611.     return(-3); }
  612. if(length>=max_crcs*4) {            /* Reached or exceeds max crcs */
  613.     read(file,buf,max_crcs*4);
  614.     for(l=0;l<max_crcs;l++)
  615.         if(crc==buf[l])
  616.             break;
  617.     if(l<max_crcs) {                /* Dupe CRC found */
  618.         close(file);
  619.         FREE(buf);
  620.         return(1); }
  621.     chsize(file,0L);                /* truncate it */
  622.     lseek(file,0L,SEEK_SET);
  623.     write(file,buf+4,(max_crcs-1)*4); }
  624.  
  625. else if(length/4) {                         /* Less than max crcs */
  626.     read(file,buf,length);
  627.     for(l=0;l<length/4;l++)
  628.         if(crc==buf[l])
  629.             break;
  630.     if(l<length/4) {                    /* Dupe CRC found */
  631.         close(file);
  632.         FREE(buf);
  633.         return(1); } }
  634.  
  635. lseek(file,0L,SEEK_END);
  636. write(file,&crc,4);                /* Write to the end */
  637. FREE(buf);
  638. close(file);
  639. return(0);
  640. }
  641.  
  642.  
  643. /****************************************************************************/
  644. /* Creates a new message header record in the header file.                    */
  645. /* If 'fast' is non-zero, fast index allocation will be used.               */
  646. /****************************************************************************/
  647. int smb_addmsghdr(smbmsg_t *msg, smbstatus_t *status, int fast, int retry_time)
  648. {
  649.     int i;
  650.     long l;
  651.  
  652. if(smb_locksmbhdr(retry_time))
  653.     return(1);
  654. if(smb_getstatus(status))
  655.     return(2);
  656.  
  657. if((i=smb_open_ha(retry_time))!=0)
  658.     return(i);
  659.  
  660. msg->hdr.length=smb_getmsghdrlen(*msg);
  661. if(fast)
  662.     l=smb_fallochdr(msg->hdr.length);
  663. else
  664.     l=smb_allochdr(msg->hdr.length);
  665. if(l==-1L) {
  666.     smb_unlocksmbhdr();
  667.     fclose(sha_fp);
  668.     return(-1); }
  669.  
  670. status->last_msg++;
  671. msg->idx.number=msg->hdr.number=status->last_msg;
  672. msg->idx.offset=status->header_offset+l;
  673. msg->idx.time=msg->hdr.when_imported.time;
  674. msg->idx.attr=msg->hdr.attr;
  675. msg->offset=status->total_msgs;
  676. status->total_msgs++;
  677. smb_putstatus(*status);
  678.  
  679. fclose(sha_fp);
  680. i=smb_putmsg(*msg);
  681. smb_unlocksmbhdr();
  682. return(i);
  683. }
  684.  
  685. /****************************************************************************/
  686. /* Writes both header and index information for msg 'msg'                   */
  687. /****************************************************************************/
  688. int smb_putmsg(smbmsg_t msg)
  689. {
  690.     int i;
  691.  
  692. i=smb_putmsghdr(msg);
  693. if(i)
  694.     return(i);
  695. return(smb_putmsgidx(msg));
  696. }
  697.  
  698. /****************************************************************************/
  699. /* Writes index information for 'msg'                                       */
  700. /* msg.idx                                                                    */
  701. /* and msg.offset must be set prior to calling to this function             */
  702. /* Returns 0 if everything ok                                               */
  703. /****************************************************************************/
  704. int smb_putmsgidx(smbmsg_t msg)
  705. {
  706.  
  707. clearerr(sid_fp);
  708. fseek(sid_fp,msg.offset*sizeof(idxrec_t),SEEK_SET);
  709. if(!fwrite(&msg.idx,sizeof(idxrec_t),1,sid_fp))
  710.     return(1);
  711. fflush(sid_fp);
  712. return(0);
  713. }
  714.  
  715. /****************************************************************************/
  716. /* Writes header information for 'msg'                                      */
  717. /* msg.hdr.length                                                           */
  718. /* msg.idx.offset                                                           */
  719. /* and msg.offset must be set prior to calling to this function             */
  720. /* Returns 0 if everything ok                                               */
  721. /****************************************************************************/
  722. int smb_putmsghdr(smbmsg_t msg)
  723. {
  724.     ushort    i;
  725.     ulong    l;
  726.  
  727. clearerr(shd_fp);
  728. if(fseek(shd_fp,msg.idx.offset,SEEK_SET))
  729.     return(-1);
  730.  
  731. /************************************************/
  732. /* Write the fixed portion of the header record */
  733. /************************************************/
  734. if(!fwrite(&msg.hdr,sizeof(msghdr_t),1,shd_fp))
  735.     return(-2);
  736.  
  737. /************************************************/
  738. /* Write the data fields (each is fixed length) */
  739. /************************************************/
  740. for(i=0;i<msg.hdr.total_dfields;i++)
  741.     if(!fwrite(&msg.dfield[i],sizeof(dfield_t),1,shd_fp))
  742.         return(-3);
  743.  
  744. /*******************************************/
  745. /* Write the variable length header fields */
  746. /*******************************************/
  747. for(i=0;i<msg.total_hfields;i++) {
  748.     if(!fwrite(&msg.hfield[i],sizeof(hfield_t),1,shd_fp))
  749.         return(-4);
  750.     if(!fwrite(msg.hfield_dat[i],msg.hfield[i].length,1,shd_fp))
  751.         return(-5); }
  752.  
  753. l=smb_getmsghdrlen(msg);
  754. while(l%SHD_BLOCK_LEN) {
  755.     if(fputc(0,shd_fp)==EOF)
  756.         return(-6);                /* pad block with NULL */
  757.     l++; }
  758. fflush(shd_fp);
  759. return(0);
  760. }
  761.  
  762. /****************************************************************************/
  763. /* Creates a sub-board's initial header file                                */
  764. /* Truncates and deletes other associated SMB files                         */
  765. /****************************************************************************/
  766. int smb_create(ulong max_crcs, ulong max_msgs, ushort max_age, int retry_time)
  767. {
  768.     char        str[128];
  769.     smbhdr_t    hdr;
  770.     smbstatus_t status;
  771.  
  772. if(filelength(fileno(shd_fp))>=sizeof(smbhdr_t)+sizeof(smbstatus_t)
  773.     && smb_locksmbhdr(retry_time))    /* header exists, so lock it */
  774.     return(1);
  775. memset(&hdr,0,sizeof(smbhdr_t));
  776. memset(&status,0,sizeof(smbstatus_t));
  777. memcpy(hdr.id,"SMB\x1a",4);     // <S> <M> <B> <^Z>
  778. hdr.version=SMB_VERSION;
  779. hdr.length=sizeof(smbhdr_t)+sizeof(smbstatus_t);
  780. status.last_msg=status.total_msgs=0;
  781. status.header_offset=sizeof(smbhdr_t)+sizeof(smbstatus_t);
  782. status.max_crcs=max_crcs;
  783. status.max_msgs=max_msgs;
  784. status.max_age=max_age;
  785. rewind(shd_fp);
  786. fwrite(&hdr,1,sizeof(smbhdr_t),shd_fp);
  787. fwrite(&status,1,sizeof(smbstatus_t),shd_fp);
  788. rewind(shd_fp);
  789. chsize(fileno(shd_fp),sizeof(smbhdr_t)+sizeof(smbstatus_t));
  790. fflush(shd_fp);
  791.  
  792. rewind(sdt_fp);
  793. chsize(fileno(sdt_fp),0L);
  794. rewind(sid_fp);
  795. chsize(fileno(sid_fp),0L);
  796.  
  797. sprintf(str,"%s.SDA",smb_file);
  798. remove(str);                        /* if it exists, delete it */
  799. sprintf(str,"%s.SHA",smb_file);
  800. remove(str);                        /* if it exists, delete it */
  801. sprintf(str,"%s.SCH",smb_file);
  802. remove(str);
  803. smb_unlocksmbhdr();
  804. return(0);
  805. }
  806.  
  807. /****************************************************************************/
  808. /* Returns number of data blocks required to store "length" amount of data  */
  809. /****************************************************************************/
  810. long smb_datblocks(ulong length)
  811. {
  812.     ulong blocks;
  813.  
  814. blocks=length/SDT_BLOCK_LEN;
  815. if(length%SDT_BLOCK_LEN)
  816.     blocks++;
  817. return(blocks);
  818. }
  819.  
  820. /****************************************************************************/
  821. /* Returns number of header blocks required to store "length" size header   */
  822. /****************************************************************************/
  823. long smb_hdrblocks(ulong length)
  824. {
  825.     ulong blocks;
  826.  
  827. blocks=length/SHD_BLOCK_LEN;
  828. if(length%SHD_BLOCK_LEN)
  829.     blocks++;
  830. return(blocks);
  831. }
  832.  
  833. /****************************************************************************/
  834. /* Finds unused space in data file based on block allocation table and        */
  835. /* marks space as used in allocation table.                                 */
  836. /* File must be opened read/write DENY ALL                                    */
  837. /* Returns offset to beginning of data (in bytes, not blocks)                */
  838. /* Assumes smb_open_da() has been called                                    */
  839. /* fclose(sda_fp) should be called after                                    */
  840. /* Returns negative on error                                                */
  841. /****************************************************************************/
  842. long smb_allocdat(ulong length, ushort headers)
  843. {
  844.     ushort  i,j;
  845.     ulong    l,blocks,offset=0L;
  846.  
  847. blocks=smb_datblocks(length);
  848. j=0;    /* j is consecutive unused block counter */
  849. rewind(sda_fp);
  850. while(!feof(sda_fp)) {
  851.     if(!fread(&i,2,1,sda_fp))
  852.         break;
  853.     offset+=SDT_BLOCK_LEN;
  854.     if(!i) j++;
  855.     else   j=0;
  856.     if(j==blocks) {
  857.         offset-=(blocks*SDT_BLOCK_LEN);
  858.         break; } }
  859. clearerr(sda_fp);
  860. fseek(sda_fp,(offset/SDT_BLOCK_LEN)*2L,SEEK_SET);
  861. for(l=0;l<blocks;l++)
  862.     if(!fwrite(&headers,2,1,sda_fp))
  863.         return(-1);
  864. return(offset);
  865. }
  866.  
  867. /****************************************************************************/
  868. /* Allocates space for data, but doesn't search for unused blocks           */
  869. /* Returns negative on error                                                */
  870. /****************************************************************************/
  871. long smb_fallocdat(ulong length, ushort headers)
  872. {
  873.     ulong    l,blocks,offset=0L;
  874.  
  875. clearerr(sda_fp);
  876. blocks=smb_datblocks(length);
  877. fseek(sda_fp,0L,SEEK_END);
  878. offset=(ftell(sda_fp)/2L)*SDT_BLOCK_LEN;
  879. for(l=0;l<blocks;l++)
  880.     if(!fwrite(&headers,2,1,sda_fp))
  881.         break;
  882. if(l<blocks)
  883.     return(-1L);
  884. return(offset);
  885. }
  886.  
  887. /****************************************************************************/
  888. /* De-allocates space for data                                                */
  889. /* Returns non-zero on error                                                */
  890. /****************************************************************************/
  891. int smb_freemsgdat(ulong offset, ulong length, ushort headers)
  892. {
  893.     ushort    i;
  894.     ulong    l,blocks;
  895.  
  896. blocks=smb_datblocks(length);
  897.  
  898. clearerr(sda_fp);
  899. for(l=0;l<blocks;l++) {
  900.     if(fseek(sda_fp,((offset/SDT_BLOCK_LEN)+l)*2L,SEEK_SET))
  901.         return(1);
  902.     if(!fread(&i,2,1,sda_fp))
  903.         return(2);
  904.     if(headers>i)
  905.         i=0;            /* don't want to go negative */
  906.     else
  907.         i-=headers;
  908.     if(fseek(sda_fp,-2L,SEEK_CUR))
  909.         return(3);
  910.     if(!fwrite(&i,2,1,sda_fp))
  911.         return(4); }
  912. return(0);
  913. }
  914.  
  915. /****************************************************************************/
  916. /* Adds to data allocation records for blocks starting at 'offset'          */
  917. /* Returns non-zero on error                                                */
  918. /****************************************************************************/
  919. int smb_incdat(ulong offset, ulong length, ushort headers)
  920. {
  921.     ushort    i;
  922.     ulong    l,blocks;
  923.  
  924. clearerr(sda_fp);
  925. blocks=smb_datblocks(length);
  926. for(l=0;l<blocks;l++) {
  927.     fseek(sda_fp,((offset/SDT_BLOCK_LEN)+l)*2L,SEEK_SET);
  928.     if(!fread(&i,2,1,sda_fp))
  929.         return(1);
  930.     i+=headers;
  931.     fseek(sda_fp,-2L,SEEK_CUR);
  932.     if(!fwrite(&i,2,1,sda_fp))
  933.         return(2); }
  934. return(0);
  935. }
  936.  
  937. /****************************************************************************/
  938. /* De-allocates blocks for header record                                    */
  939. /* Returns non-zero on error                                                */
  940. /****************************************************************************/
  941. int smb_freemsghdr(ulong offset, ulong length)
  942. {
  943.     uchar    c=0;
  944.     ulong    l,blocks;
  945.  
  946. clearerr(sha_fp);
  947. blocks=smb_hdrblocks(length);
  948. fseek(sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET);
  949. for(l=0;l<blocks;l++)
  950.     if(!fwrite(&c,1,1,sha_fp))
  951.         return(1);
  952. return(0);
  953. }
  954.  
  955. /****************************************************************************/
  956. /* Frees all allocated header and data blocks for 'msg'                     */
  957. /****************************************************************************/
  958. int smb_freemsg(smbmsg_t msg, smbstatus_t status)
  959. {
  960.     int     i;
  961.     ushort    x;
  962.  
  963. for(x=0;x<msg.hdr.total_dfields;x++) {
  964.     if((i=smb_freemsgdat(msg.hdr.offset+msg.dfield[x].offset
  965.         ,msg.dfield[x].length,1))!=0)
  966.         return(i); }
  967. return(smb_freemsghdr(msg.idx.offset-status.header_offset,msg.hdr.length));
  968. }
  969.  
  970. /****************************************************************************/
  971. /* Finds unused space in header file based on block allocation table and    */
  972. /* marks space as used in allocation table.                                 */
  973. /* File must be opened read/write DENY ALL                                    */
  974. /* Returns offset to beginning of header (in bytes, not blocks)             */
  975. /* Assumes smb_open_ha() has been called                                    */
  976. /* fclose(sha_fp) should be called after                                    */
  977. /* Returns -1L on error                                                     */
  978. /****************************************************************************/
  979. long smb_allochdr(ulong length)
  980. {
  981.     uchar    c;
  982.     ushort    i;
  983.     ulong    l,blocks,offset=0;
  984.  
  985. blocks=smb_hdrblocks(length);
  986. i=0;    /* i is consecutive unused block counter */
  987. rewind(sha_fp);
  988. while(!feof(sha_fp)) {
  989.     if(!fread(&c,1,1,sha_fp))
  990.         break;
  991.     offset+=SHD_BLOCK_LEN;
  992.     if(!c) i++;
  993.     else   i=0;
  994.     if(i==blocks) {
  995.         offset-=(blocks*SHD_BLOCK_LEN);
  996.         break; } }
  997. clearerr(sha_fp);
  998. fseek(sha_fp,offset/SHD_BLOCK_LEN,SEEK_SET);
  999. c=1;
  1000. for(l=0;l<blocks;l++)
  1001.     if(!fwrite(&c,1,1,sha_fp))
  1002.         return(-1L);
  1003. return(offset);
  1004. }
  1005.  
  1006. /****************************************************************************/
  1007. /* Allocates space for index, but doesn't search for unused blocks          */
  1008. /* Returns -1L on error                                                     */
  1009. /****************************************************************************/
  1010. long smb_fallochdr(ulong length)
  1011. {
  1012.     uchar    c=1;
  1013.     ulong    l,blocks,offset=0L;
  1014.  
  1015. blocks=smb_hdrblocks(length);
  1016. clearerr(sha_fp);
  1017. fseek(sha_fp,0L,SEEK_END);
  1018. offset=ftell(sha_fp)*SHD_BLOCK_LEN;
  1019. for(l=0;l<blocks;l++)
  1020.     if(!fwrite(&c,1,1,sha_fp))
  1021.         return(-1L);
  1022. return(offset);
  1023. }
  1024.  
  1025.  
  1026. /* End of SMBLIB.C */
  1027.