Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief UBF read/write function implementations
0003  *   Enduro Execution Library
0004  *
0005  * @file b_readwrite.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 #include <stdio.h>
0038 #include <stdlib.h>
0039 #include <string.h>
0040 #include <stdio.h>
0041 #include <stdlib.h>
0042 #include <memory.h>
0043 #include <errno.h>
0044 
0045 #include <ubf.h>
0046 #include <ubf_int.h>    /* Internal headers for UBF... */
0047 #include <fdatatype.h>
0048 #include <ferror.h>
0049 #include <fieldtable.h>
0050 #include <ndrstandard.h>
0051 #include <ndebug.h>
0052 #include <cf.h>
0053 /*---------------------------Externs------------------------------------*/
0054 /*---------------------------Macros-------------------------------------*/
0055 /*---------------------------Enums--------------------------------------*/
0056 /*---------------------------Typedefs-----------------------------------*/
0057 /*---------------------------Globals------------------------------------*/
0058 /*---------------------------Statics------------------------------------*/
0059 /*---------------------------Prototypes---------------------------------*/
0060 
0061 
0062 /**
0063  * Remove PTR from UBF, in recursive way
0064  * @param p_ub UBF buffer
0065  * @param maxlen max buffer size to be used for sub-buffers
0066  * @param did_mod did we modify something?
0067  * @return EXSUCCEED/EXFAIL
0068  */
0069 exprivate int strip_ptr(UBFH *p_ub, BFLDLEN maxlen, int *did_mod)
0070 {
0071     int ret = EXSUCCEED;
0072     int restart;
0073     int did_local_mod;
0074     UBFH *p_ub_tmp = NULL;
0075     int cnt, i;
0076     
0077     UBF_LOG(log_debug, "strip_ptr enter p_ub=%p maxlen=%d did_mode=%d",
0078             p_ub, maxlen, *did_mod);
0079     do
0080     {
0081         Bnext_state_t state;
0082         BFLDID bfldid=BBADFLDOCC;
0083         BFLDOCC occ;
0084         char *d_ptr;
0085         UBF_header_t *hdr = (UBF_header_t *)p_ub;
0086         BFLDID   *p_bfldid_start = &hdr->bfldid;
0087         int ftyp;
0088         
0089         restart=EXFALSE;
0090         state.p_cur_bfldid = (BFLDID *)(((char *)p_bfldid_start) + hdr->cache_ptr_off);
0091         state.cur_occ = 0;
0092         state.p_ub = p_ub;
0093         state.size = hdr->bytes_used;
0094 
0095         if (EXTRUE==(ret=ndrx_Bnext(&state, p_ub, &bfldid, &occ, NULL, NULL, &d_ptr)))
0096         {
0097             ftyp = bfldid >> EFFECTIVE_BITS;
0098             
0099             if (BFLD_PTR==ftyp)
0100             {
0101                 /* remove field... */
0102                 *did_mod=EXTRUE;
0103                 
0104                 UBF_LOG(log_debug, "Removing fldid=%d as ptr", bfldid);
0105                 if (EXSUCCEED!=Bdel(p_ub, bfldid, occ))
0106                 {
0107                     EXFAIL_OUT(ret);
0108                 }
0109                 restart=EXTRUE;
0110             }
0111             else 
0112             {
0113                 /* we are done */
0114                 ret=EXSUCCEED;
0115             }
0116         }
0117         
0118     } while (restart);
0119     
0120     /* If we have UBF buffer... fetch &  */
0121     cnt = 0;
0122     i = 0;
0123     do
0124     {
0125         Bnext_state_t state;
0126         BFLDID bfldid=BBADFLDOCC;
0127         BFLDOCC occ;
0128         char *d_ptr;
0129         UBF_header_t *hdr = (UBF_header_t *)p_ub;
0130         BFLDID   *p_bfldid_start = &hdr->bfldid;
0131         int ftyp;
0132         BFLDLEN blen;
0133         
0134         restart=EXFALSE;
0135         state.p_cur_bfldid = (BFLDID *)(((char *)p_bfldid_start) + hdr->cache_ubf_off);
0136         state.cur_occ = 0;
0137         state.p_ub = p_ub;
0138         state.size = hdr->bytes_used;
0139 
0140         UBF_LOG(log_debug, "Searching for sub-buffers, cnt=%d", cnt);
0141         for(i=0; (EXTRUE==(ret=ndrx_Bnext(&state, p_ub, &bfldid, &occ, NULL, NULL, &d_ptr))); i++)
0142         {
0143             ftyp = bfldid >> EFFECTIVE_BITS;
0144             
0145             if (BFLD_UBF==ftyp && i==cnt)
0146             {
0147                 if (NULL==p_ub_tmp)
0148                 {
0149                     p_ub_tmp = (UBFH *)NDRX_FPMALLOC(maxlen, 0);
0150                     
0151                     if (NULL==p_ub_tmp)
0152                     {
0153                         ndrx_Bset_error_fmt(BMALLOC, "%s: Failed to malloc %d bytes",
0154                                 __func__, maxlen);
0155                         EXFAIL_OUT(ret);
0156                     }
0157                 }
0158                 
0159                 if (EXSUCCEED!=Binit(p_ub_tmp, maxlen))
0160                 {
0161                     UBF_LOG(log_error, "Failed to init temp buffer!");
0162                     EXFAIL_OUT(ret);
0163                 }
0164                 
0165                 blen = maxlen;
0166                         
0167                 if (EXSUCCEED!=Bget(p_ub, bfldid, occ, (char *)p_ub_tmp, &blen))
0168                 {
0169                     UBF_LOG(log_error, "Failed to read sub-buffer %d occ %d",
0170                             bfldid, occ);
0171                     EXFAIL_OUT(ret);
0172                 }
0173                 
0174                 did_local_mod=EXFALSE;
0175                 
0176                 if (EXSUCCEED!=strip_ptr(p_ub_tmp, maxlen, &did_local_mod))
0177                 {
0178                     EXFAIL_OUT(ret);
0179                 }
0180                 
0181                 if (did_local_mod)
0182                 {
0183                     *did_mod=EXTRUE;
0184                     
0185                     /* Overwrite the field */
0186                     
0187                     if (EXSUCCEED!=Bchg(p_ub, bfldid, occ, (char *)p_ub_tmp, 0))
0188                     {
0189                         UBF_LOG(log_error, "Failed to update sub-buffer %d occ %d",
0190                                 bfldid, occ);
0191                         EXFAIL_OUT(ret);
0192                     }
0193                     
0194                 }
0195                 /* next time continue with cnt pos */
0196                 restart=EXTRUE;
0197                 cnt++;
0198                 break;
0199             }
0200             else if (BFLD_UBF!=ftyp)
0201             {
0202                 /* we are done */
0203                 ret=EXSUCCEED;
0204                 break;
0205             }
0206         }
0207         
0208     } while (restart);
0209 
0210 out:
0211     
0212     if (NULL!=p_ub_tmp)
0213     {
0214         NDRX_FPFREE(p_ub_tmp);
0215     }
0216     
0217     return ret;
0218 }
0219 
0220 /**
0221  * Internal version of buffer reader from stream. If \p p_readf is not present
0222  * then uses read from input file. If ptr is present, then data read is made
0223  * from callbacks.
0224  * @param p_ub UBF buffer
0225  * @param inf stream to read from 
0226  * @param [in] p_readf read callback function. for which `buffer' is where to
0227  *  put data read. `bufz' is buffer size and `dataptr1' is \p dataptr1 passed to
0228  *  function. Note that buffer must be filled filled with exact of requested
0229  *  bufsz. This is mandatory for first read as header of UBF of processed with
0230  *  single data read request. In case of error -1 shall be returned.
0231  * @param [in] dataptr1 data pointer passed down to read function \p p_readf 
0232  * @return SUCCEED/FAIL
0233  */
0234 expublic int ndrx_Bread  (UBFH * p_ub, FILE * inf,
0235         long (*p_readf)(char *buffer, long bufsz, void *dataptr1), void *dataptr1)
0236 {
0237     int ret=EXSUCCEED;
0238     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0239     UBF_header_t hdr_src;
0240     BFLDLEN dst_buf_len;
0241     BFLDLEN dst_buf_free;
0242     char *p = (char*)hdr;
0243     int read;
0244     int to_read;
0245 
0246     UBF_LOG(log_debug, "%s: enter", __func__);
0247 
0248     /* Reset dest buffer */    
0249     memset(&hdr_src, 0, sizeof(hdr_src));
0250     
0251     if (NULL!=p_readf)
0252     {
0253         read = (int) p_readf((char *)&hdr_src, sizeof(hdr_src), dataptr1);
0254     }
0255     else
0256     {
0257         /* Read the header from input file. */
0258         read=fread((char *)&hdr_src, 1, sizeof(hdr_src), inf);
0259     }
0260 
0261     /* Was header read OK? */
0262     if (sizeof(hdr_src)!=read)
0263     {
0264         ndrx_Bset_error_fmt(BEUNIX, "%s: Failed to read header from input "
0265                                     "file, unix err %d (read) vs %d (expected): [%s]",
0266                                     __func__, read, (int)sizeof(hdr_src),
0267                                     strerror(errno));
0268         EXFAIL_OUT(ret);
0269     }
0270 
0271     /* Check header */
0272     if (0!=strncmp(hdr_src.magic, UBF_MAGIC, UBF_MAGIC_SIZE))
0273     {
0274         ndrx_Bset_error_fmt(BNOTFLD, "%s: Source buffer not UBF!", __func__);
0275         EXFAIL_OUT(ret);
0276     }
0277 
0278     /*
0279      * Reset dest buffer.
0280      */
0281     dst_buf_len = hdr->buf_len;
0282     ret=Binit(p_ub, dst_buf_len);
0283     dst_buf_free = hdr->buf_len - hdr->bytes_used;
0284 
0285     /* Check dest buffer size. */
0286     if (dst_buf_free < hdr_src.bytes_used)
0287     {
0288         ndrx_Bset_error_fmt(BNOSPACE, "%s:No space in source buffer - free: %d "
0289                                     "bytes, requested: %d",
0290                                     __func__, dst_buf_free, hdr_src.bytes_used);
0291         EXFAIL_OUT(ret);
0292     }
0293 
0294     /* Now read the left bytes from the stream & prepare header*/
0295     to_read = hdr_src.bytes_used - read;
0296     p+=read;
0297     
0298     if (NULL!=p_readf)
0299     {
0300         read = (int) p_readf(p, to_read, dataptr1);
0301     }
0302     else
0303     {
0304         read=fread(p, 1, to_read, inf);
0305     }
0306 
0307     if (read!=to_read)
0308     {
0309         ndrx_Bset_error_fmt(BEUNIX, "%s:Failed to read buffer data from "
0310                                 " input file %d (read) vs %d (expected), unix err: [%s]",
0311                                 __func__,
0312                                 read, to_read,
0313                                 strerror(errno));
0314         EXFAIL_OUT(ret);
0315     }
0316     else
0317     {
0318         /* update header of dst */
0319         memcpy(hdr, &hdr_src, sizeof(hdr_src));
0320         hdr->buf_len = dst_buf_len;
0321     }
0322 
0323     /* Validate the buffer */
0324     if (EXSUCCEED!=(ret=validate_entry(p_ub, 0, 0, VALIDATE_MODE_NO_FLD)))
0325     {
0326         UBF_LOG(log_error, "Restored buffer is invalid!");
0327         ndrx_Bappend_error_msg("(restored buffer is invalid)");
0328         EXFAIL_OUT(ret);
0329     }
0330     else
0331     {
0332         UBF_DUMP(log_always, "_Bread: restored buffer data:", 
0333                 p_ub, hdr->bytes_used);
0334     }
0335     
0336     /* wipe out any BFLD_PTR fields, if not enabled... */
0337     if (!(ndrx_G_apiflags & NDRX_APIFLAGS_UBFPTRPARSE))
0338     {
0339         /* strip off BFLD_PTR in recursive way from the imported data...
0340          * New func: Find if any BFLD_PTR is used, remove the off.
0341          *  - return flag that buffer is changed
0342          * Search for any BFLD_UBF, if any found, read the buffer (to temp space)
0343          *  (one by one as sizes may change)
0344          * - call the new func.
0345          * - If changes has been detected, perform Bchg() over the current occurrence,
0346          * -- how about to loop next? Count the fields processed?
0347          */
0348         int did_mod = EXFALSE;
0349         if (EXSUCCEED!=strip_ptr(p_ub, Bused(p_ub), &did_mod))
0350         {
0351             EXFAIL_OUT(ret);
0352         }
0353         
0354         if (did_mod)
0355         {
0356             UBF_LOG(log_debug, "PTRs removed.");
0357         }
0358     }
0359     
0360 out:
0361     UBF_LOG(log_debug, "%s: return %d", __func__, ret);
0362     
0363     return ret;
0364 }
0365 
0366 /**
0367  * Internal version of buffer writer to stream
0368  * This will write only used area of the buffer to the stream.
0369  * Function accepts either output file pointer or callback function which writes
0370  * the buffer output.
0371  * @param p_ub UBF buffer
0372  * @param outf stream to write to 
0373  * @param [in] p_writef data output function. `buffer' contains the data to be written
0374  *  `bufz' contains number of bytes to be written. `dataptr1' is forwared from
0375  *  function original requests. Function must return number of bytes written.
0376  *  in non-error scenario all passed bytes to function must be written. In case
0377  *  of error -1 can be returned.
0378  * @param [in] dataptr1 is forwarded to \p p_writef
0379  * @return SUCCEED/FAIL
0380  */
0381 expublic int ndrx_Bwrite (UBFH *p_ub, FILE * outf,
0382         long (*p_writef)(char *buffer, long bufsz, void *dataptr1), void *dataptr1)
0383 {
0384     int ret=EXSUCCEED;
0385     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0386     int written;
0387 
0388     UBF_LOG(log_debug, "%s: enter", __func__);
0389 
0390     /* Dump the buffer, which is about to write */
0391 
0392     UBF_DUMP(log_always, "ndrx_Bwrite: buffer data:", p_ub, hdr->bytes_used);
0393     
0394     if (NULL!=p_writef)
0395     {
0396         written=(int)p_writef((char *)p_ub, hdr->bytes_used, dataptr1);
0397     }
0398     else
0399     {
0400         written=fwrite(p_ub, 1, hdr->bytes_used, outf);
0401     }
0402 
0403     if (written!=hdr->bytes_used)
0404     {
0405         /* we have error condition! */
0406         ndrx_Bset_error_fmt(BEUNIX, "%s:Write failed! Requested for write %d bytes, "
0407                             "but written %d. Unix error: [%s]",
0408                              __func__, hdr->bytes_used, written, strerror(errno));
0409         EXFAIL_OUT(ret);
0410     }
0411 
0412     /* Flush written data. */
0413     if (NULL==p_writef)
0414     {
0415         fflush(outf);
0416 
0417         if (ferror(outf))
0418         {
0419             ndrx_Bset_error_fmt(BEUNIX, "%s: On Write fflush failed, Unix error: [%s]",
0420                                 __func__, strerror(errno));
0421             EXFAIL_OUT(ret);
0422         }
0423     }
0424     
0425 out:
0426     
0427     UBF_LOG(log_debug, "%s: return %d", __func__, ret);
0428     
0429     return ret;
0430 }
0431 
0432 /* vim: set ts=4 sw=4 et smartindent: */