LCOV - code coverage report
Current view: top level - ini - ini_fileobj.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 224 296 75.7 %
Date: 2014-04-01 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /*
       2             :     INI LIBRARY
       3             : 
       4             :     File context related functions
       5             : 
       6             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
       7             : 
       8             :     INI Library is free software: you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation, either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     INI Library is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU Lesser General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU Lesser General Public License
      19             :     along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : #include "config.h"
      22             : #include <errno.h>
      23             : #include <sys/types.h>
      24             : #include <sys/stat.h>
      25             : #include <fcntl.h>
      26             : #include <string.h>
      27             : #include <stdlib.h>
      28             : #include <iconv.h>
      29             : #include "trace.h"
      30             : #include "ini_defines.h"
      31             : #include "ini_configobj.h"
      32             : #include "ini_config_priv.h"
      33             : #include "path_utils.h"
      34             : 
      35             : #define ICONV_BUFFER    5000
      36             : 
      37             : #define BOM4_SIZE 4
      38             : #define BOM3_SIZE 3
      39             : #define BOM2_SIZE 2
      40             : 
      41             : enum index_utf_t {
      42             :     INDEX_UTF32BE = 0,
      43             :     INDEX_UTF32LE = 1,
      44             :     INDEX_UTF16BE = 2,
      45             :     INDEX_UTF16LE = 3,
      46             :     INDEX_UTF8 = 4
      47             : };
      48             : 
      49             : /* Close file but not destroy the object */
      50           1 : void ini_config_file_close(struct ini_cfgfile *file_ctx)
      51             : {
      52             :     TRACE_FLOW_ENTRY();
      53             : 
      54           1 :     if(file_ctx) {
      55           1 :         if(file_ctx->file) {
      56           1 :             fclose(file_ctx->file);
      57           1 :             file_ctx->file = NULL;
      58             :         }
      59             :     }
      60             : 
      61             :     TRACE_FLOW_EXIT();
      62           1 : }
      63             : 
      64             : /* Close file context and destroy the object */
      65         250 : void ini_config_file_destroy(struct ini_cfgfile *file_ctx)
      66             : {
      67             :     TRACE_FLOW_ENTRY();
      68             : 
      69         250 :     if(file_ctx) {
      70         250 :         free(file_ctx->filename);
      71         250 :         simplebuffer_free(file_ctx->file_data);
      72         250 :         if(file_ctx->file) fclose(file_ctx->file);
      73         250 :         free(file_ctx);
      74             :     }
      75             : 
      76             :     TRACE_FLOW_EXIT();
      77         250 : }
      78             : 
      79             : /* How much I plan to read? */
      80             : static size_t how_much_to_read(size_t left, size_t increment)
      81             : {
      82        3945 :     if(left > increment) return increment;
      83             :     else return left;
      84             : }
      85             : 
      86         245 : static enum index_utf_t check_bom(enum index_utf_t ind,
      87             :                                   unsigned char *buffer,
      88             :                                   size_t len,
      89             :                                   size_t *bom_shift)
      90             : {
      91             :     TRACE_FLOW_ENTRY();
      92             : 
      93         245 :     if (len >= BOM4_SIZE) {
      94         250 :         if ((buffer[0] == 0x00) &&
      95          18 :             (buffer[1] == 0x00) &&
      96          18 :             (buffer[2] == 0xFE) &&
      97           9 :             (buffer[3] == 0xFF)) {
      98             :                 TRACE_FLOW_RETURN(INDEX_UTF32BE);
      99           9 :                 *bom_shift = BOM4_SIZE;
     100           9 :                 return INDEX_UTF32BE;
     101             :         }
     102         259 :         else if ((buffer[0] == 0xFF) &&
     103          54 :                  (buffer[1] == 0xFE) &&
     104          36 :                  (buffer[2] == 0x00) &&
     105           9 :                  (buffer[3] == 0x00)) {
     106             :                 TRACE_FLOW_RETURN(INDEX_UTF32LE);
     107           9 :                 *bom_shift = BOM4_SIZE;
     108           9 :                 return INDEX_UTF32LE;
     109             :         }
     110             :     }
     111             : 
     112         227 :     if (len >= BOM3_SIZE) {
     113         232 :         if ((buffer[0] == 0xEF) &&
     114          18 :             (buffer[1] == 0xBB) &&
     115           9 :             (buffer[2] == 0xBF)) {
     116             :                 TRACE_FLOW_RETURN(INDEX_UTF8);
     117           9 :                 *bom_shift = BOM3_SIZE;
     118           9 :                 return INDEX_UTF8;
     119             :         }
     120             :     }
     121             : 
     122         218 :     if (len >= BOM2_SIZE) {
     123         223 :         if ((buffer[0] == 0xFE) &&
     124           9 :             (buffer[1] == 0xFF)) {
     125             :                 TRACE_FLOW_RETURN(INDEX_UTF16BE);
     126           9 :                 *bom_shift = BOM2_SIZE;
     127           9 :                 return INDEX_UTF16BE;
     128             :         }
     129         223 :         else if ((buffer[0] == 0xFF) &&
     130          18 :                  (buffer[1] == 0xFE)) {
     131             :                 TRACE_FLOW_RETURN(INDEX_UTF16LE);
     132          18 :                 *bom_shift = BOM2_SIZE;
     133          18 :                 return INDEX_UTF16LE;
     134             :         }
     135             :     }
     136             : 
     137             :     TRACE_FLOW_RETURN(ind);
     138             :     return ind;
     139             : }
     140             : 
     141        3945 : static int read_chunk(FILE *file, size_t left, size_t increment,
     142             :                       char *position, size_t *read_num)
     143             : {
     144        3945 :     int error = EOK;
     145        3945 :     size_t to_read = 0;
     146        3945 :     size_t read_cnt = 0;
     147             : 
     148             :     TRACE_FLOW_ENTRY();
     149             : 
     150        3945 :     to_read = how_much_to_read(left, increment);
     151             : 
     152             :     TRACE_INFO_NUMBER("About to read", to_read);
     153             : 
     154        3945 :     read_cnt = fread(position, to_read, 1, file);
     155             : 
     156             :     TRACE_INFO_NUMBER("Read", read_cnt * to_read);
     157             : 
     158        3945 :     if (read_cnt == 0) {
     159           0 :         error = ferror(file);
     160           0 :         if (error) {
     161             :             TRACE_ERROR_NUMBER("Failed to read data from file", error);
     162             :             return error;
     163             :         }
     164           0 :         error = feof(file);
     165           0 :         if(error) {
     166             :             TRACE_FLOW_EXIT();
     167             :             return EOK;
     168             :         }
     169             :         TRACE_ERROR_NUMBER("Failed to read data from file", EIO);
     170           0 :         return EIO;
     171             :     }
     172             : 
     173        3945 :     *read_num = to_read;
     174             : 
     175             :     TRACE_FLOW_EXIT();
     176        3945 :     return error;
     177             : }
     178             : 
     179             : /* Function useful for debugging */
     180             : /*
     181             : static void print_buffer(char *read_buffer, int len)
     182             : {
     183             :     int i;
     184             :     for (i=0; i < len; i++) {
     185             :         printf("%02X ", (unsigned char)read_buffer[i]);
     186             :     }
     187             :     printf("\n");
     188             : }
     189             : */
     190             : 
     191             : /* Internal initialization part */
     192        3945 : static int initialize_conv(unsigned char *read_buf,
     193             :                            size_t read_cnt,
     194             :                            int *initialized,
     195             :                            size_t *bom_shift,
     196             :                            iconv_t *conv)
     197             : {
     198        3945 :     int error = EOK;
     199        3945 :     enum index_utf_t ind = INDEX_UTF8;
     200        3945 :     const char *encodings[] = {  "UTF-32BE",
     201             :                                  "UTF-32LE",
     202             :                                  "UTF-16BE",
     203             :                                  "UTF-16LE",
     204             :                                  "UTF-8" };
     205             : 
     206             :     TRACE_FLOW_ENTRY();
     207             : 
     208        3945 :     if (*initialized == 0) {
     209             : 
     210             :         TRACE_INFO_STRING("Reading first time.","Checking BOM");
     211             : 
     212         245 :         ind = check_bom(ind,
     213             :                         (unsigned char *)read_buf,
     214             :                         read_cnt,
     215             :                         bom_shift);
     216             : 
     217             :         TRACE_INFO_STRING("Converting to", encodings[INDEX_UTF8]);
     218             :         TRACE_INFO_STRING("Converting from", encodings[ind]);
     219             : 
     220         245 :         errno = 0;
     221         245 :         *conv = iconv_open(encodings[INDEX_UTF8], encodings[ind]);
     222         245 :         if (*conv == (iconv_t) -1) {
     223           0 :             error = errno;
     224             :             TRACE_ERROR_NUMBER("Failed to create converter", error);
     225           0 :             return error;
     226             :         }
     227             : 
     228         245 :         *initialized = 1;
     229             :     }
     230        3700 :     else *bom_shift = 0;
     231             : 
     232             :     TRACE_FLOW_EXIT();
     233             :     return error;
     234             : 
     235             : }
     236             : 
     237             : /* Internal conversion part */
     238         245 : static int common_file_convert(FILE *file,
     239             :                                struct ini_cfgfile *file_ctx,
     240             :                                uint32_t size)
     241             : {
     242         245 :     int error = EOK;
     243         245 :     size_t read_cnt = 0;
     244         245 :     size_t total_read = 0;
     245         245 :     size_t in_buffer = 0;
     246         245 :     iconv_t conv = (iconv_t)-1;
     247         245 :     size_t conv_res = 0;
     248             :     char read_buf[ICONV_BUFFER+1];
     249             :     char result_buf[ICONV_BUFFER];
     250             :     char *src, *dest;
     251         245 :     size_t to_convert = 0;
     252         245 :     size_t room_left = 0;
     253         245 :     size_t bom_shift = 0;
     254         245 :     int initialized = 0;
     255             : 
     256             :     TRACE_FLOW_ENTRY();
     257             : 
     258             :     do {
     259             :         /* print_buffer(read_buf, ICONV_BUFFER); */
     260        3945 :         error = read_chunk(file,
     261             :                            size - total_read,
     262             :                            ICONV_BUFFER - in_buffer,
     263             :                            read_buf + in_buffer,
     264             :                            &read_cnt);
     265             :         /* print_buffer(read_buf, ICONV_BUFFER); */
     266        3945 :         if (error) {
     267           0 :             if (conv != (iconv_t) -1) iconv_close(conv);
     268             :             TRACE_ERROR_NUMBER("Failed to read chunk", error);
     269             :             return error;
     270             :         }
     271             : 
     272             :         /* Prepare source buffer for conversion */
     273        3945 :         src = read_buf;
     274        3945 :         to_convert = read_cnt + in_buffer;
     275        3945 :         in_buffer = 0;
     276             : 
     277             :         /* Do initialization if needed */
     278        3945 :         error = initialize_conv((unsigned char *)read_buf,
     279             :                                 read_cnt,
     280             :                                 &initialized,
     281             :                                 &bom_shift,
     282             :                                 &conv);
     283        3945 :         if (error) {
     284             :             TRACE_ERROR_NUMBER("Failed to initialize",
     285             :                                 error);
     286             :             return error;
     287             :         }
     288             : 
     289        3945 :         src += bom_shift;
     290        3945 :         to_convert -= bom_shift;
     291        3945 :         total_read += read_cnt;
     292             :         TRACE_INFO_NUMBER("Total read", total_read);
     293             : 
     294             :         do {
     295             :             /* Do conversion */
     296        3999 :             dest = result_buf;
     297        3999 :             room_left = ICONV_BUFFER;
     298             : 
     299             :             TRACE_INFO_NUMBER("To convert", to_convert);
     300             :             TRACE_INFO_NUMBER("Room left", room_left);
     301             :             TRACE_INFO_NUMBER("Total read", total_read);
     302             : 
     303        3999 :             errno = 0;
     304        3999 :             conv_res = iconv(conv, &src, &to_convert, &dest, &room_left);
     305        3999 :             if (conv_res == (size_t) -1) {
     306         238 :                 error = errno;
     307         238 :                 switch(error) {
     308             :                 case EILSEQ:
     309             :                     TRACE_ERROR_NUMBER("Invalid multibyte encoding", error);
     310           0 :                     iconv_close(conv);
     311             :                     return error;
     312             :                 case EINVAL:
     313             :                     /* We need to just read more if we can */
     314             :                     TRACE_INFO_NUMBER("Incomplete sequence len",
     315             :                                       src - read_buf);
     316             :                     TRACE_INFO_NUMBER("File size.", size);
     317         184 :                     if (total_read == size) {
     318             :                         /* Or return error if we can't */
     319             :                         TRACE_ERROR_NUMBER("Incomplete sequence", error);
     320           0 :                         iconv_close(conv);
     321             :                         return error;
     322             :                     }
     323         184 :                     memmove(read_buf, src, to_convert);
     324         184 :                     in_buffer = to_convert;
     325             :                     break;
     326             : 
     327             :                 case E2BIG:
     328             :                     TRACE_INFO_STRING("No room in the output buffer.", "");
     329          54 :                     error = simplebuffer_add_raw(file_ctx->file_data,
     330             :                                                  result_buf,
     331             :                                                  ICONV_BUFFER - room_left,
     332             :                                                  ICONV_BUFFER);
     333          54 :                     if (error) {
     334             :                         TRACE_ERROR_NUMBER("Failed to store converted bytes",
     335             :                                             error);
     336           0 :                         iconv_close(conv);
     337             :                         return error;
     338             :                     }
     339          54 :                     continue;
     340             :                 default:
     341             :                     TRACE_ERROR_NUMBER("Unexpected internal error",
     342             :                                         error);
     343           0 :                     iconv_close(conv);
     344             :                     return ENOTSUP;
     345             :                 }
     346             :             }
     347             :             /* The whole buffer was sucessfully converted */
     348        3945 :             error = simplebuffer_add_raw(file_ctx->file_data,
     349             :                                          result_buf,
     350             :                                          ICONV_BUFFER - room_left,
     351             :                                          ICONV_BUFFER);
     352        3945 :             if (error) {
     353             :                 TRACE_ERROR_NUMBER("Failed to store converted bytes",
     354             :                                     error);
     355           0 :                 iconv_close(conv);
     356             :                 return error;
     357             :             }
     358             : /*
     359             :             TRACE_INFO_STRING("Saved procesed portion.",
     360             :                         (char *)simplebuffer_get_vbuf(file_ctx->file_data));
     361             : */
     362             :             break;
     363             :         }
     364             :         while (1);
     365             :     }
     366        3945 :     while (total_read < size);
     367             : 
     368         245 :     iconv_close(conv);
     369             : 
     370             :     /* Open file */
     371             :     TRACE_INFO_STRING("File data",
     372             :                       (char *)simplebuffer_get_vbuf(file_ctx->file_data));
     373             :     TRACE_INFO_NUMBER("File len",
     374             :                       simplebuffer_get_len(file_ctx->file_data));
     375             :     TRACE_INFO_NUMBER("Size", size);
     376         245 :     errno = 0;
     377         245 :     file_ctx->file = fmemopen(simplebuffer_get_vbuf(file_ctx->file_data),
     378         245 :                               simplebuffer_get_len(file_ctx->file_data),
     379             :                               "r");
     380         245 :     if (!(file_ctx->file)) {
     381           0 :         error = errno;
     382             :         TRACE_ERROR_NUMBER("Failed to open file", error);
     383             :         return error;
     384             :     }
     385             : 
     386             :     TRACE_FLOW_EXIT();
     387             :     return EOK;
     388             : }
     389             : 
     390             : 
     391             : /* Internal common initialization part */
     392         250 : static int common_file_init(struct ini_cfgfile *file_ctx,
     393             :                             void *data_buf,
     394             :                             uint32_t data_len)
     395             : {
     396         250 :     int error = EOK;
     397         250 :     FILE *file = NULL;
     398         250 :     int stat_ret = 0;
     399         250 :     uint32_t size = 0;
     400         250 :     void *internal_data = NULL;
     401         250 :     uint32_t internal_len = 0;
     402         250 :     unsigned char alt_buffer[2] = {0, 0};
     403         250 :     uint32_t alt_buffer_len = 1;
     404             : 
     405             :     TRACE_FLOW_ENTRY();
     406             : 
     407         250 :     if (data_buf) {
     408             : 
     409          48 :         if(data_len) {
     410          44 :             internal_data = data_buf;
     411          44 :             internal_len = data_len;
     412             :         }
     413             :         else {
     414             :             /* If buffer is empty fmemopen will return an error.
     415             :              * This will prevent creation of adefault config object.
     416             :              * Instead we will use buffer that has at least one character. */
     417             :             internal_data = alt_buffer;
     418             :             internal_len = alt_buffer_len;
     419             :         }
     420             : 
     421             :         TRACE_INFO_NUMBER("Inside file_init len", internal_len);
     422             :         TRACE_INFO_STRING("Inside file_init data:", (char *)internal_data);
     423             : 
     424          48 :         file = fmemopen(internal_data, internal_len, "r");
     425          48 :         if (!file) {
     426           0 :             error = errno;
     427             :             TRACE_ERROR_NUMBER("Failed to memmap file", error);
     428           0 :             return error;
     429             :         }
     430             :         size = internal_len;
     431             :     }
     432             :     else {
     433             : 
     434             :         TRACE_INFO_STRING("File", file_ctx->filename);
     435             : 
     436             :         /* Open file to get its size */
     437         202 :         errno = 0;
     438         202 :         file = fopen(file_ctx->filename, "r");
     439         202 :         if (!file) {
     440           0 :             error = errno;
     441             :             TRACE_ERROR_NUMBER("Failed to open file", error);
     442           0 :             return error;
     443             :         }
     444             : 
     445             :         /* Get the size of the file */
     446         202 :         errno = 0;
     447         404 :         stat_ret = fstat(fileno(file), &(file_ctx->file_stats));
     448         202 :         if (stat_ret == -1) {
     449           0 :             error = errno;
     450           0 :             fclose(file);
     451             :             TRACE_ERROR_NUMBER("Failed to get file stats", error);
     452           0 :             return error;
     453             :         }
     454         202 :         size = file_ctx->file_stats.st_size;
     455             :     }
     456             : 
     457             :     /* Trick to overcome the fact that
     458             :      * fopen and fmemopen behave differently when file
     459             :      * is 0 length
     460             :      */
     461         250 :     if (size) {
     462         245 :         error = common_file_convert(file, file_ctx, size);
     463         245 :         if (error) {
     464             :             TRACE_ERROR_NUMBER("Failed to convert file",
     465             :                                 error);
     466           0 :             fclose(file);
     467           0 :             return error;
     468             :         }
     469             :     }
     470             :     else {
     471             : 
     472             :         TRACE_INFO_STRING("File is 0 length","");
     473           5 :         errno = 0;
     474             : 
     475           5 :         file_ctx->file = fdopen(fileno(file), "r");
     476           5 :         if (!(file_ctx->file)) {
     477           0 :             error = errno;
     478           0 :             fclose(file);
     479             :             TRACE_ERROR_NUMBER("Failed to fdopen file", error);
     480           0 :             return error;
     481             :         }
     482             :     }
     483             : 
     484         250 :     fclose(file);
     485             : 
     486             :     /* Collect stats */
     487         250 :     if (file_ctx->metadata_flags & INI_META_STATS) {
     488           4 :         file_ctx->stats_read = 1;
     489             :     }
     490             :     else {
     491         246 :         memset(&(file_ctx->file_stats), 0, sizeof(struct stat));
     492         246 :         file_ctx->stats_read = 0;
     493             :     }
     494             : 
     495             :     TRACE_FLOW_EXIT();
     496             :     return EOK;
     497             : }
     498             : 
     499             : /* Create a file object for parsing a config file */
     500         200 : int ini_config_file_open(const char *filename,
     501             :                          uint32_t metadata_flags,
     502             :                          struct ini_cfgfile **file_ctx)
     503             : {
     504         200 :     int error = EOK;
     505         200 :     struct ini_cfgfile *new_ctx = NULL;
     506             : 
     507             :     TRACE_FLOW_ENTRY();
     508             : 
     509         200 :     if ((!filename) || (!file_ctx)) {
     510             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     511             :         return EINVAL;
     512             :     }
     513             : 
     514             :     /* Allocate structure */
     515         200 :     new_ctx = malloc(sizeof(struct ini_cfgfile));
     516         200 :     if (!new_ctx) {
     517             :         TRACE_ERROR_NUMBER("Failed to allocate file ctx.", ENOMEM);
     518             :         return ENOMEM;
     519             :     }
     520             : 
     521         200 :     new_ctx->filename = NULL;
     522         200 :     new_ctx->file = NULL;
     523         200 :     new_ctx->file_data = NULL;
     524             : 
     525         200 :     error = simplebuffer_alloc(&(new_ctx->file_data));
     526         200 :     if (error) {
     527             :         TRACE_ERROR_NUMBER("Failed to allocate buffer ctx.", error);
     528           0 :         ini_config_file_destroy(new_ctx);
     529           0 :         return error;
     530             : 
     531             :     }
     532             : 
     533             :     /* Store flags */
     534         200 :     new_ctx->metadata_flags = metadata_flags;
     535             : 
     536             :     /* Construct the full file path */
     537         200 :     new_ctx->filename = malloc(PATH_MAX + 1);
     538         200 :     if (!(new_ctx->filename)) {
     539           0 :         ini_config_file_destroy(new_ctx);
     540             :         TRACE_ERROR_NUMBER("Failed to allocate memory for file path.", ENOMEM);
     541           0 :         return ENOMEM;
     542             :     }
     543             : 
     544             :     /* Construct path */
     545         200 :     error = make_normalized_absolute_path(new_ctx->filename,
     546             :                                           PATH_MAX,
     547             :                                           filename);
     548         200 :     if(error) {
     549             :         TRACE_ERROR_NUMBER("Failed to resolve path", error);
     550           0 :         ini_config_file_destroy(new_ctx);
     551           0 :         return error;
     552             :     }
     553             : 
     554             :     /* Do common init */
     555         200 :     error = common_file_init(new_ctx, NULL, 0);
     556         200 :     if(error) {
     557             :         TRACE_ERROR_NUMBER("Failed to do common init", error);
     558           0 :         ini_config_file_destroy(new_ctx);
     559           0 :         return error;
     560             :     }
     561             : 
     562         200 :     *file_ctx = new_ctx;
     563             :     TRACE_FLOW_EXIT();
     564         200 :     return error;
     565             : }
     566             : 
     567             : /* Create a file object from a memory buffer */
     568          48 : int ini_config_file_from_mem(void *data_buf,
     569             :                              uint32_t data_len,
     570             :                              struct ini_cfgfile **file_ctx)
     571             : {
     572          48 :     int error = EOK;
     573          48 :     struct ini_cfgfile *new_ctx = NULL;
     574             : 
     575             :     TRACE_FLOW_ENTRY();
     576             : 
     577          48 :     if ((!data_buf) || (!file_ctx)) {
     578             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     579             :         return EINVAL;
     580             :     }
     581             : 
     582             :     /* Allocate structure */
     583          48 :     new_ctx = malloc(sizeof(struct ini_cfgfile));
     584          48 :     if (!new_ctx) {
     585             :         TRACE_ERROR_NUMBER("Failed to allocate file ctx.", ENOMEM);
     586             :         return ENOMEM;
     587             :     }
     588             : 
     589          48 :     new_ctx->filename = NULL;
     590          48 :     new_ctx->file = NULL;
     591          48 :     new_ctx->file_data = NULL;
     592          48 :     new_ctx->metadata_flags = 0;
     593             : 
     594          48 :     error = simplebuffer_alloc(&(new_ctx->file_data));
     595          48 :     if (error) {
     596             :         TRACE_ERROR_NUMBER("Failed to allocate buffer ctx.", error);
     597           0 :         ini_config_file_destroy(new_ctx);
     598           0 :         return error;
     599             :     }
     600             : 
     601             :     /* Put an empty string into the file name */
     602          48 :     new_ctx->filename = strdup("");
     603          48 :     if (!(new_ctx->filename)) {
     604           0 :         ini_config_file_destroy(new_ctx);
     605             :         TRACE_ERROR_NUMBER("Failed to put empty string into filename.", ENOMEM);
     606           0 :         return ENOMEM;
     607             :     }
     608             : 
     609             :     /* Do common init */
     610          48 :     error = common_file_init(new_ctx, data_buf, data_len);
     611          48 :     if(error) {
     612             :         TRACE_ERROR_NUMBER("Failed to do common init", error);
     613           0 :         ini_config_file_destroy(new_ctx);
     614           0 :         return error;
     615             :     }
     616             : 
     617          48 :     *file_ctx = new_ctx;
     618             :     TRACE_FLOW_EXIT();
     619          48 :     return error;
     620             : }
     621             : 
     622             : 
     623             : 
     624             : /* Create a file object from existing one */
     625           2 : int ini_config_file_reopen(struct ini_cfgfile *file_ctx_in,
     626             :                            struct ini_cfgfile **file_ctx_out)
     627             : {
     628           2 :     int error = EOK;
     629           2 :     struct ini_cfgfile *new_ctx = NULL;
     630             : 
     631             :     TRACE_FLOW_ENTRY();
     632             : 
     633           2 :     if ((!file_ctx_in) || (!file_ctx_out)) {
     634             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     635             :         return EINVAL;
     636             :     }
     637             : 
     638             :     /* Allocate structure */
     639           2 :     new_ctx = malloc(sizeof(struct ini_cfgfile));
     640           2 :     if (!new_ctx) {
     641             :         TRACE_ERROR_NUMBER("Failed to allocate file ctx.", ENOMEM);
     642             :         return ENOMEM;
     643             :     }
     644             : 
     645           2 :     new_ctx->file = NULL;
     646           2 :     new_ctx->file_data = NULL;
     647           2 :     new_ctx->filename = NULL;
     648             : 
     649           2 :     error = simplebuffer_alloc(&(new_ctx->file_data));
     650           2 :     if (error) {
     651             :         TRACE_ERROR_NUMBER("Failed to allocate buffer ctx.", error);
     652           0 :         ini_config_file_destroy(new_ctx);
     653           0 :         return error;
     654             : 
     655             :     }
     656             : 
     657             :     /* Store flags */
     658           2 :     new_ctx->metadata_flags = file_ctx_in->metadata_flags;
     659             : 
     660             :     /* Copy full file path */
     661           2 :     errno = 0;
     662           2 :     new_ctx->filename = strndup(file_ctx_in->filename, PATH_MAX);
     663           2 :     if (!(new_ctx->filename)) {
     664           0 :         error = errno;
     665           0 :         ini_config_file_destroy(new_ctx);
     666             :         TRACE_ERROR_NUMBER("Failed to allocate memory for file path.", error);
     667           0 :         return error;
     668             :     }
     669             : 
     670             :     /* Do common init */
     671           2 :     error = common_file_init(new_ctx, NULL, 0);
     672           2 :     if(error) {
     673             :         TRACE_ERROR_NUMBER("Failed to do common init", error);
     674           0 :         ini_config_file_destroy(new_ctx);
     675           0 :         return error;
     676             :     }
     677             : 
     678           2 :     *file_ctx_out = new_ctx;
     679             :     TRACE_FLOW_EXIT();
     680           2 :     return error;
     681             : }
     682             : 
     683             : /* Get the fully resolved file name */
     684           0 : const char *ini_config_get_filename(struct ini_cfgfile *file_ctx)
     685             : {
     686             :     const char *ret;
     687             :     TRACE_FLOW_ENTRY();
     688             : 
     689           0 :     ret = file_ctx->filename;
     690             : 
     691             :     TRACE_FLOW_EXIT();
     692           0 :     return ret;
     693             : }
     694             : 
     695             : /* Get pointer to stat structure */
     696           2 : const struct stat *ini_config_get_stat(struct ini_cfgfile *file_ctx)
     697             : {
     698             :     const struct stat *ret;
     699             :     TRACE_FLOW_ENTRY();
     700             : 
     701           2 :     if (file_ctx->stats_read) ret = &(file_ctx->file_stats);
     702             :     else ret = NULL;
     703             : 
     704             :     TRACE_FLOW_EXIT();
     705           2 :     return ret;
     706             : }
     707             : 
     708             : 
     709             : /* Check access */
     710           4 : int ini_config_access_check(struct ini_cfgfile *file_ctx,
     711             :                             uint32_t flags,
     712             :                             uid_t uid,
     713             :                             gid_t gid,
     714             :                             mode_t mode,
     715             :                             mode_t mask)
     716             : {
     717             :     mode_t st_mode;
     718             : 
     719             :     TRACE_FLOW_ENTRY();
     720             : 
     721           4 :     flags &= INI_ACCESS_CHECK_MODE |
     722             :              INI_ACCESS_CHECK_GID |
     723             :              INI_ACCESS_CHECK_UID;
     724             : 
     725           4 :     if ((file_ctx == NULL) || (flags == 0)) {
     726             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     727             :         return EINVAL;
     728             :     }
     729             : 
     730           4 :     if (file_ctx->stats_read == 0) {
     731             :         TRACE_ERROR_NUMBER("Stats were not collected.", EINVAL);
     732             :         return EINVAL;
     733             :     }
     734             : 
     735             :     /* Check mode */
     736           3 :     if (flags & INI_ACCESS_CHECK_MODE) {
     737             : 
     738             :         TRACE_INFO_NUMBER("File mode as saved.",
     739             :                           file_ctx->file_stats.st_mode);
     740             : 
     741           3 :         st_mode = file_ctx->file_stats.st_mode;
     742           3 :         st_mode &= S_IRWXU | S_IRWXG | S_IRWXO;
     743             :         TRACE_INFO_NUMBER("File mode adjusted.", st_mode);
     744             : 
     745             :         TRACE_INFO_NUMBER("Mode as provided.", mode);
     746           3 :         mode &= S_IRWXU | S_IRWXG | S_IRWXO;
     747             :         TRACE_INFO_NUMBER("Mode adjusted.", mode);
     748             : 
     749             :         /* Adjust mask */
     750           3 :         if (mask == 0) mask = S_IRWXU | S_IRWXG | S_IRWXO;
     751           0 :         else mask &= S_IRWXU | S_IRWXG | S_IRWXO;
     752             : 
     753           3 :         if ((mode & mask) != (st_mode & mask)) {
     754             :             TRACE_INFO_NUMBER("File mode:", (mode & mask));
     755             :             TRACE_INFO_NUMBER("Mode adjusted.",
     756             :                               (st_mode & mask));
     757             :             TRACE_ERROR_NUMBER("Access denied.", EACCES);
     758             :             return EACCES;
     759             :         }
     760             :     }
     761             : 
     762             :     /* Check uid */
     763           2 :     if (flags & INI_ACCESS_CHECK_UID) {
     764           0 :         if (file_ctx->file_stats.st_uid != uid) {
     765             :             TRACE_ERROR_NUMBER("GID:", file_ctx->file_stats.st_uid);
     766             :             TRACE_ERROR_NUMBER("GID passed in.", uid);
     767             :             TRACE_ERROR_NUMBER("Access denied.", EACCES);
     768             :             return EACCES;
     769             :         }
     770             :     }
     771             : 
     772             :     /* Check gid */
     773           2 :     if (flags & INI_ACCESS_CHECK_GID) {
     774           0 :         if (file_ctx->file_stats.st_gid != gid) {
     775             :             TRACE_ERROR_NUMBER("GID:", file_ctx->file_stats.st_gid);
     776             :             TRACE_ERROR_NUMBER("GID passed in.", gid);
     777             :             TRACE_ERROR_NUMBER("Access denied.", EACCES);
     778             :             return EACCES;
     779             :         }
     780             :     }
     781             : 
     782             :     TRACE_FLOW_EXIT();
     783           2 :     return EOK;
     784             : 
     785             : }
     786             : 
     787             : /* Determines if two file contexts are different by comparing:
     788             :  * - time stamp
     789             :  * - device ID
     790             :  * - i-node
     791             :  */
     792           2 : int ini_config_changed(struct ini_cfgfile *file_ctx1,
     793             :                        struct ini_cfgfile *file_ctx2,
     794             :                        int *changed)
     795             : {
     796             :     TRACE_FLOW_ENTRY();
     797             : 
     798           4 :     if ((file_ctx1 == NULL) ||
     799           4 :         (file_ctx2 == NULL) ||
     800             :         (changed == NULL)) {
     801             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     802             :         return EINVAL;
     803             :     }
     804             : 
     805           4 :     if ((file_ctx1->stats_read == 0) ||
     806           2 :         (file_ctx2->stats_read == 0)) {
     807             :         TRACE_ERROR_NUMBER("Stats were not collected.", EINVAL);
     808             :         return EINVAL;
     809             :     }
     810             : 
     811           2 :     *changed = 0;
     812             : 
     813             :     /* Unfortunately the time is not granular enough
     814             :      * to detect the change if run during the unit test.
     815             :      * In future when a more granular version of stat
     816             :      * is available we should switch to it and update
     817             :      * the unit test.
     818             :      */
     819             : 
     820           4 :     if((file_ctx1->file_stats.st_mtime !=
     821           3 :         file_ctx2->file_stats.st_mtime) ||
     822           1 :        (file_ctx1->file_stats.st_dev !=
     823           2 :         file_ctx2->file_stats.st_dev) ||
     824           1 :        (file_ctx1->file_stats.st_ino !=
     825           1 :         file_ctx2->file_stats.st_ino)) {
     826             :         TRACE_INFO_STRING("File changed!", "");
     827           1 :         *changed = 1;
     828             :     }
     829             : 
     830             :     TRACE_FLOW_EXIT();
     831             :     return EOK;
     832             : }
     833             : 
     834             : /* Print the file object contents */
     835           0 : void ini_config_file_print(struct ini_cfgfile *file_ctx)
     836             : {
     837             :     TRACE_FLOW_ENTRY();
     838           0 :     if (file_ctx == NULL) {
     839           0 :         printf("No file object\n.");
     840             :     }
     841             :     else {
     842           0 :         printf("File name: %s\n", (file_ctx->filename) ? file_ctx->filename : "NULL");
     843           0 :         printf("File is %s\n", (file_ctx->file) ? "open" : "closed");
     844           0 :         printf("Metadata flags %u\n", file_ctx->metadata_flags);
     845           0 :         printf("Stats flag st_dev %li\n", file_ctx->file_stats.st_dev);
     846           0 :         printf("Stats flag st_ino %li\n", file_ctx->file_stats.st_ino);
     847           0 :         printf("Stats flag st_mode %u\n", file_ctx->file_stats.st_mode);
     848           0 :         printf("Stats flag st_nlink %li\n", file_ctx->file_stats.st_nlink);
     849           0 :         printf("Stats flag st_uid %u\n", file_ctx->file_stats.st_uid);
     850           0 :         printf("Stats flag st_gid %u\n", file_ctx->file_stats.st_gid);
     851           0 :         printf("Stats flag st_rdev %li\n", file_ctx->file_stats.st_rdev);
     852           0 :         printf("Stats flag st_size %lu\n", file_ctx->file_stats.st_size);
     853           0 :         printf("Stats flag st_blocks %li\n", file_ctx->file_stats.st_blocks);
     854           0 :         printf("Stats flag st_atime %ld\n", file_ctx->file_stats.st_atime);
     855           0 :         printf("Stats flag st_mtime %ld\n", file_ctx->file_stats.st_mtime);
     856           0 :         printf("Stats flag st_ctime %ld\n", file_ctx->file_stats.st_ctime);
     857             :     }
     858             :     TRACE_FLOW_EXIT();
     859           0 : }

Generated by: LCOV version 1.10