On (17/03/14 22:00), Lukas Slebodnik wrote: >On (08/03/14 19:11), Dmitri Pal wrote: >>Hello, >> >>The following patches address the request to be able to read config >>data from a memory buffer rather than a file. >>Ticket: https://fedorahosted.org/sssd/ticket/2267 >> >>It also addresses a build problem that I found on my system and fixes >>a tight loop in parsing when we ignore errors and file is empty. >> >> >>-- >>Thank you, >>Dmitri Pal >> >>Sr. Engineering Manager for IdM portfolio >>Red Hat Inc. >> >> >>------------------------------- >>Looking to carve out IT costs? >>www.redhat.com/carveoutcosts/ >> >> >> > >>From 30a92ababaa9148a7354ebf52bf318d37b5451d2 Mon Sep 17 00:00:00 2001 >>From: Dmitri Pal <d...@redhat.com> >>Date: Sat, 8 Mar 2014 19:00:57 -0500 >>Subject: [PATCH 2/4] [INI] New entry to read data from mem >> >>The commit adds a new entry point to read configuration >>data from a memory buffer instead of file. >>--- >> ini/ini_configobj.h | 25 ++++++ >> ini/ini_fileobj.c | 204 >> +++++++++++++++++++++++++++++++++++++------------ >> ini/libini_config.sym | 1 + >> 3 files changed, 182 insertions(+), 48 deletions(-) >> >>diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h >>index 9a4eb58..4ef98dc 100644 >>--- a/ini/ini_configobj.h >>+++ b/ini/ini_configobj.h >>@@ -483,6 +483,31 @@ int ini_config_file_open(const char *filename, >> struct ini_cfgfile **file_ctx); >> >> /** >>+ * @brief Create a configuration file object using memory buffer. >>+ * >>+ * Create a file object for parsing a configuration file. >>+ * Configuration will use provided memory instead of the actual file. >>+ * >>+ * A "configuration file object" is different from >>+ * a "configuration object". The former stores metadata >>+ * about a file the configuration data is read from, >>+ * while the latter holds the configuration itself. >>+ * >>+ * @param[in] data_buf In memory configuration data. >>+ * Needs to be NULL terminated. > ^^^^^^^^^^^^^^^^ > In my opinion, it is little bit confusing. > Because argument data_buf has type "void *". > What about: byte array null byte ('\0') byte array terminated with null byte ('\0') > >Do we really need null byte terminated string? >I think fmemopen will need null byte terminated string only if buffer is opened >in append mode. > >>+ * @param[in] data_len Length of memory data >>+ * not including terminating NULL. >>+ * @param[out] file_ctx Configuration file object. >>+ * >>+ * @return 0 - Success. >>+ * @return EINVAL - Invalid parameter. >>+ * @return ENOMEM - No memory. >>+ */ >>+int ini_config_file_from_mem(void *data_buf, >>+ uint32_t data_len, >>+ struct ini_cfgfile **file_ctx); >>+ > >>+/** >> * @brief Close configuration file after parsing >> * >> * Closes file but keeps the context. File can be reopened >>diff --git a/ini/ini_fileobj.c b/ini/ini_fileobj.c >>index d87956a..fbb1a81 100644 >>--- a/ini/ini_fileobj.c >>+++ b/ini/ini_fileobj.c >>@@ -46,6 +46,12 @@ enum index_utf_t { >> INDEX_UTF8 = 4 >> }; >> >>+/* Trick to work around the fact that >>+ * fmemopen failes if buffer is 0 length >>+ */ >>+unsigned char alt_buffer[2] = {0, 0}; > {'\n', 0}; >It would be better to have string with length 1. >(gdb) print strlen("\n") >$1 = 1 > >>+uint32_t alt_buffer_len = 1; >Could you use static modifier (both variable)? > >sh-4.2$ nm ini/ini_fileobj.o | grep " D " >0000000000000004 D alt_buffer >0000000000000000 D alt_buffer_len > >It is not big problem because symbols will be hidden by version-script file. >But It it will be better to hide them explicitly. > >> /* Close file but not destroy the object */ >> void ini_config_file_close(struct ini_cfgfile *file_ctx) >> { >>@@ -138,7 +144,7 @@ static enum index_utf_t check_bom(enum index_utf_t ind, >> return ind; >> } >> >>-static int read_chunk(int raw_file, size_t left, size_t increment, >>+static int read_chunk(FILE *file, size_t left, size_t increment, >> char *position, size_t *read_num) >> { >> int error = EOK; >>@@ -149,22 +155,28 @@ static int read_chunk(int raw_file, size_t left, size_t >>increment, >> >> to_read = how_much_to_read(left, increment); >> >>- TRACE_INFO_NUMBER("About to read", to_read); >>- errno = 0; >>- read_cnt = read(raw_file, position, to_read); >>- if (read_cnt == -1) { >>- error = errno; >>- TRACE_ERROR_NUMBER("Failed to read data from file", error); >>- return error; >>- } >>+ TRACE_INFO_NUMBER("About to read", (unsigned int)to_read); > ^^^^^^^^^^^^^^ > casting is not necessary in this case. > because in macro TRACE_NUMBER variable is casted to > ((unsigned long int)) >> >>- if (read_cnt != to_read) { >>- error = EIO; >>- TRACE_ERROR_NUMBER("Read less than required", error); >>- return error; >>+ Read_cnt = fread(position, to_read, 1, file); >>+ >>+ TRACE_INFO_NUMBER("Read", (unsigned int)(read_cnt * to_read)); > ^^^^^^^^^^^^^^ > the same here. >>+ >>+ if (read_cnt == 0) { >>+ error = ferror(file); >>+ if (error) { >>+ TRACE_ERROR_NUMBER("Failed to read data from file", error); >>+ return error; >>+ } >>+ error = feof(file); >>+ if(error) { >>+ TRACE_FLOW_EXIT(); >>+ return EOK; >>+ } >It would be better to call feof before ferror. > >>+ TRACE_ERROR_NUMBER("Failed to read data from file", EIO); >>+ return EIO; >> } >> >>- *read_num = read_cnt; >>+ *read_num = to_read; >> >> TRACE_FLOW_EXIT(); >> return error; >>@@ -229,7 +241,9 @@ static int initialize_conv(unsigned char *read_buf, >> } >> >> /* Internal conversion part */ >>-static int common_file_convert(int raw_file, struct ini_cfgfile *file_ctx) >>+static int common_file_convert(FILE *file, >>+ struct ini_cfgfile *file_ctx, >>+ uint32_t size) >> { >> int error = EOK; >> size_t read_cnt = 0; >>@@ -249,8 +263,8 @@ static int common_file_convert(int raw_file, struct >>ini_cfgfile *file_ctx) >> >> do { >> /* print_buffer(read_buf, ICONV_BUFFER); */ >>- error = read_chunk(raw_file, >>- file_ctx->file_stats.st_size - total_read, >>+ error = read_chunk(file, >>+ size - total_read, >> ICONV_BUFFER - in_buffer, >> read_buf + in_buffer, >> &read_cnt); >>@@ -305,9 +319,8 @@ static int common_file_convert(int raw_file, struct >>ini_cfgfile *file_ctx) >> /* We need to just read more if we can */ >> TRACE_INFO_NUMBER("Incomplete sequence len", >> src - read_buf); >>- TRACE_INFO_NUMBER("File size.", >>- file_ctx->file_stats.st_size); >>- if (total_read == file_ctx->file_stats.st_size) { >>+ TRACE_INFO_NUMBER("File size.", size); >>+ if (total_read == size) { >> /* Or return error if we can't */ >> TRACE_ERROR_NUMBER("Incomplete sequence", error); >> iconv_close(conv); >>@@ -356,7 +369,7 @@ static int common_file_convert(int raw_file, struct >>ini_cfgfile *file_ctx) >> } >> while (1); >> } >>- while (total_read < file_ctx->file_stats.st_size); >>+ while (total_read < size); >> >> iconv_close(conv); >> >>@@ -365,8 +378,7 @@ static int common_file_convert(int raw_file, struct >>ini_cfgfile *file_ctx) >> (char *)simplebuffer_get_vbuf(file_ctx->file_data)); >> TRACE_INFO_NUMBER("File len", >> simplebuffer_get_len(file_ctx->file_data)); >>- TRACE_INFO_NUMBER("Size", >>- file_ctx->file_data->size); >>+ TRACE_INFO_NUMBER("Size", size); >> errno = 0; >> file_ctx->file = fmemopen(simplebuffer_get_vbuf(file_ctx->file_data), >> simplebuffer_get_len(file_ctx->file_data), >>@@ -383,59 +395,98 @@ static int common_file_convert(int raw_file, struct >>ini_cfgfile *file_ctx) >> >> >> /* Internal common initialization part */ >>-static int common_file_init(struct ini_cfgfile *file_ctx) >>+static int common_file_init(struct ini_cfgfile *file_ctx, >>+ void *data_buf, >>+ uint32_t data_len) >> { >> int error = EOK; >>- int raw_file = 0; >>+ FILE *file = NULL; >> int stat_ret = 0; >>+ uint32_t size = 0; >>+ void *internal_data = NULL; >>+ uint32_t internal_len = 0; >> >> TRACE_FLOW_ENTRY(); >> >>- TRACE_INFO_STRING("File", file_ctx->filename); >>+ if (data_buf) { >> >>- /* Open file in binary mode first */ >>- errno = 0; >>- raw_file = open(file_ctx->filename, O_RDONLY); >>- if (raw_file == -1) { >>- error = errno; >>- TRACE_ERROR_NUMBER("Failed to open file in binary mode", error); >>- return error; >>+ if(data_len) { >>+ internal_data = data_buf; >>+ internal_len = data_len; >>+ } >>+ else { >>+ /* If buffer is empty fmemopen will return an error. >>+ * This will prevent creation of adefault config object. >>+ * Instead we will use buffer that has at least one character. */ >>+ internal_data = (void *)alt_buffer; > ^^^^^^^^ > Any pointer can be stored to variable with type "void *" > without explicit casting. > >>+ internal_len = alt_buffer_len; >>+ } >>+ >>+ TRACE_INFO_NUMBER("Inside file_init len", internal_len); >>+ TRACE_INFO_STRING("Inside file_init data:", (char *)internal_data); >>+ >>+ file = fmemopen(internal_data, internal_len, "r"); >>+ if (!file) { >>+ error = errno; >>+ TRACE_ERROR_NUMBER("Failed to memmap file", error); >>+ return error; >>+ } >>+ size = internal_len; >> } >>+ else { >> >>- /* Get the size of the file */ >>- errno = 0; >>- stat_ret = fstat(raw_file, &(file_ctx->file_stats)); >>- if (stat_ret == -1) { >>- error = errno; >>- close(raw_file); >>- TRACE_ERROR_NUMBER("Failed to get file stats", error); >>- return error; >>+ TRACE_INFO_STRING("File", file_ctx->filename); >>+ >>+ /* Open file to get its size */ >>+ errno = 0; >>+ file = fopen(file_ctx->filename, "r"); >>+ if (!file) { >>+ error = errno; >>+ TRACE_ERROR_NUMBER("Failed to open file", error); >>+ return error; >>+ } >>+ >>+ /* Get the size of the file */ >>+ errno = 0; >>+ stat_ret = fstat(fileno(file), &(file_ctx->file_stats)); >>+ if (stat_ret == -1) { >>+ error = errno; >>+ fclose(file); >>+ TRACE_ERROR_NUMBER("Failed to get file stats", error); >>+ return error; >>+ } >>+ size = file_ctx->file_stats.st_size; >> } >> >> /* Trick to overcome the fact that >> * fopen and fmemopen behave differently when file >> * is 0 length >> */ >>- if (file_ctx->file_stats.st_size) { >>- error = common_file_convert(raw_file, file_ctx); >>- close(raw_file); >>+ if (size) { >>+ error = common_file_convert(file, file_ctx, size); >> if (error) { >> TRACE_ERROR_NUMBER("Failed to convert file", >> error); >>+ fclose(file); >> return error; >> } >> } >> else { >>+ >>+ TRACE_INFO_STRING("File is 0 length",""); >> errno = 0; >>- file_ctx->file = fdopen(raw_file, "r"); >>+ >>+ file_ctx->file = fdopen(fileno(file), "r"); >> if (!(file_ctx->file)) { >> error = errno; >>- close(raw_file); >>+ fclose(file); >> TRACE_ERROR_NUMBER("Failed to fdopen file", error); >> return error; >> } >> } >> >>+ fclose(file); >>+ >> /* Collect stats */ >> if (file_ctx->metadata_flags & INI_META_STATS) { >> file_ctx->stats_read = 1; >>@@ -505,7 +556,7 @@ int ini_config_file_open(const char *filename, >> } >> >> /* Do common init */ >>- error = common_file_init(new_ctx); >>+ error = common_file_init(new_ctx, NULL, 0); >> if(error) { >> TRACE_ERROR_NUMBER("Failed to do common init", error); >> ini_config_file_destroy(new_ctx); >>@@ -517,6 +568,63 @@ int ini_config_file_open(const char *filename, >> return error; >> } >> >>+/* Create a file object from a memory buffer */ >>+int ini_config_file_from_mem(void *data_buf, >>+ uint32_t data_len, >>+ struct ini_cfgfile **file_ctx) >>+{ >>+ int error = EOK; >>+ struct ini_cfgfile *new_ctx = NULL; >>+ >>+ TRACE_FLOW_ENTRY(); >>+ >>+ if ((!data_buf) || (!file_ctx)) { >>+ TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL); >>+ return EINVAL; >>+ } >>+ >>+ /* Allocate structure */ >>+ new_ctx = malloc(sizeof(struct ini_cfgfile)); >>+ if (!new_ctx) { >>+ TRACE_ERROR_NUMBER("Failed to allocate file ctx.", ENOMEM); >>+ return ENOMEM; >>+ } >>+ >>+ new_ctx->filename = NULL; >>+ new_ctx->file = NULL; >>+ new_ctx->file_data = NULL; >>+ new_ctx->metadata_flags = 0; >Could we use calloc instead of malloc. >Memory will be set to zero autmatically. We could remove these lines in this >case. > >>+ >>+ error = simplebuffer_alloc(&(new_ctx->file_data)); >>+ if (error) { >>+ TRACE_ERROR_NUMBER("Failed to allocate buffer ctx.", error); >>+ ini_config_file_destroy(new_ctx); >>+ return error; >>+ } >>+ >>+ /* Put an empty string into the file name */ >>+ new_ctx->filename = strdup(""); >>+ if (!(new_ctx->filename)) { >>+ ini_config_file_destroy(new_ctx); >>+ TRACE_ERROR_NUMBER("Failed to put empty string into filename.", >>ENOMEM); >>+ return ENOMEM; >>+ } >>+ >>+ /* Do common init */ >>+ error = common_file_init(new_ctx, data_buf, data_len); >>+ if(error) { >>+ TRACE_ERROR_NUMBER("Failed to do common init", error); >>+ ini_config_file_destroy(new_ctx); >>+ return error; >>+ } >>+ >>+ *file_ctx = new_ctx; >>+ TRACE_FLOW_EXIT(); >>+ return error; >>+} >>+ >>+ >>+ >> /* Create a file object from existing one */ >> int ini_config_file_reopen(struct ini_cfgfile *file_ctx_in, >> struct ini_cfgfile **file_ctx_out) >>@@ -564,7 +672,7 @@ int ini_config_file_reopen(struct ini_cfgfile >>*file_ctx_in, >> } >> >> /* Do common init */ >>- error = common_file_init(new_ctx); >>+ error = common_file_init(new_ctx, NULL, 0); >> if(error) { >> TRACE_ERROR_NUMBER("Failed to do common init", error); >> ini_config_file_destroy(new_ctx); >>diff --git a/ini/libini_config.sym b/ini/libini_config.sym >>index d38b17b..d0035f2 100644 >>--- a/ini/libini_config.sym >>+++ b/ini/libini_config.sym >>@@ -46,6 +46,7 @@ global: >> ini_config_destroy; >> ini_config_clean_state; >> ini_config_file_open; >>+ ini_config_file_from_mem; >> ini_config_file_close; >> ini_config_file_reopen; >> ini_config_file_destroy; >>-- >>1.7.1 >> > >>From 16c9140ada8461250d2aa8ac484e29c5237fdeaa Mon Sep 17 00:00:00 2001 >>From: Dmitri Pal <d...@redhat.com> >>Date: Sat, 8 Mar 2014 19:04:02 -0500 >>Subject: [PATCH 4/4] [INI] Unit test for the new interface >> >>This patch adds unit test for the interface that allows >>reading configuration data from memory. >>--- >> ini/ini_parse_ut.c | 154 >> +++++++++++++++++++++++++++++++++++++++++++++++----- >> 1 files changed, 140 insertions(+), 14 deletions(-) >> >>diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c >>index 1fa2624..721ee4a 100644 >>--- a/ini/ini_parse_ut.c >>+++ b/ini/ini_parse_ut.c >>@@ -50,7 +50,8 @@ typedef int (*test_fn)(void); >> >> static int test_one_file(const char *in_filename, >> const char *out_filename, >>- int edge) >>+ int edge, >>+ int mem) > I think type bool would be better. For example: bool from_memory > In my opinion, it is easier to read code: "if (from_memory)" > type bool is just a cosmetic change. (it needn't be changed) > > >> { >> int error = EOK; >> struct ini_cfgfile *file_ctx = NULL; >>@@ -60,6 +61,11 @@ static int test_one_file(const char *in_filename, >> char **error_list = NULL; >> struct simplebuffer *sbobj = NULL; >> uint32_t left = 0; >>+ uint32_t stream_len = 0; >>+ void *stream_data = NULL; >>+ struct stat file_stats; >>+ int stat_ret = 0; >>+ FILE *file = NULL; >> >> INIOUT(printf("<==== Testing file %s ====>\n", in_filename)); >> >>@@ -70,14 +76,73 @@ static int test_one_file(const char *in_filename, >> return error; >> } >> >>- error = ini_config_file_open(in_filename, >>- 0, /* TBD */ >>- &file_ctx); >>- if (error) { >>- printf("Failed to open file %s for reading. Error %d.\n", >>- in_filename, error); >>- ini_config_destroy(ini_config); >>- return error; >>+ if(mem) { > ^^^ >You forget to add space between "if" and the bracket. > >>+ /* Get file stats */ >>+ errno = 0; >>+ stat_ret = stat(in_filename, &file_stats); >>+ if (stat_ret == -1) { > ^^^^ > with space >>+ error = errno; >>+ printf("Failed to get file stats. Error %d.\n", error); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >>+ /* Allocate memory to store file */ >>+ errno = 0; >>+ stream_len = file_stats.st_size; >>+ stream_data = malloc(file_stats.st_size + 1); >>+ if(!stream_data) { > ^^^^ > without space >>+ error = errno; >>+ printf("Failed to allocate memory for stream. Error %d.\n", >>error); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >>+ *((unsigned char *)(stream_data) + stream_len) = '\0'; >>+ /* Open file */ >>+ errno = 0; >>+ file = fopen(in_filename, "r"); >>+ if(!stream_data) { > ^^^^ > without space >>+ error = errno; >>+ printf("Failed to open file to prepare stream. Error %d.\n", >>error); >>+ free(stream_data); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >>+ /* Read file into memory */ >>+ errno = 0; >>+ fread(stream_data, stream_len, 1, file); >>+ error = ferror(file); >>+ if(error) { > ^^^^ > without space >>+ printf("Failed to read stream data. Error %d.\n", error); >>+ free(stream_data); >>+ fclose(file); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >>+ fclose(file); >>+ >>+ INIOUT(printf("Data len %u\n", stream_len)); >>+ INIOUT(printf("Data:\n%s\n", (char *)stream_data)); >>+ >>+ error = ini_config_file_from_mem(stream_data, >>+ stream_len, >>+ &file_ctx); >>+ if (error) { >>+ printf("Failed to open from memory. Error %d.\n", error); >>+ free(stream_data); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >>+ } >>+ else { >>+ error = ini_config_file_open(in_filename, >>+ 0, /* TBD */ >>+ &file_ctx); >>+ if (error) { >>+ printf("Failed to open file %s for reading. Error %d.\n", >>+ in_filename, error); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >> } >> >> error = ini_config_parse(file_ctx, >>@@ -89,15 +154,29 @@ static int test_one_file(const char *in_filename, >> INIOUT(printf("Failed to parse configuration. Error %d.\n", error)); >> >> if (ini_config_error_count(ini_config)) { >>- INIOUT(printf("Errors detected while parsing: %s\n", >>- ini_config_get_filename(file_ctx))); >>+ if (mem) { >>+ INIOUT(printf("Errors detected while parsing" >>+ " configuration stored in memory: %s\n", >>+ in_filename)); >>+ } >>+ else { >>+ INIOUT(printf("Errors detected while parsing: %s\n", >>+ ini_config_get_filename(file_ctx))); >>+ } >> ini_config_get_errors(ini_config, &error_list); >> INIOUT(ini_config_print_errors(stdout, error_list)); >> ini_config_free_errors(error_list); >> } >>- /* We do not return here intentionally */ >>+ /* If we are testing memory mapped, return error */ >>+ if (mem) { >>+ free(stream_data); >>+ ini_config_file_destroy(file_ctx); >>+ ini_config_destroy(ini_config); >>+ return error; >>+ } >> } >> >>+ if (mem) free(stream_data); >> ini_config_file_destroy(file_ctx); >> >> INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT)); >>@@ -200,8 +279,9 @@ static int read_save_test(void) >> snprintf(infile, PATH_MAX, "%s/ini/ini.d/%s.conf", >> (srcdir == NULL) ? "." : srcdir, files[i]); >> snprintf(outfile, PATH_MAX, "./%s_%d.conf.out", files[i], edge); >>- error = test_one_file(infile, outfile, edge); >>+ error = test_one_file(infile, outfile, edge, 0); >> INIOUT(printf("Test for file: %s returned %d\n", files[i], >> error)); >>+ if (error) return error; >> } >> i++; >> } >>@@ -211,6 +291,51 @@ static int read_save_test(void) >> return EOK; >> } >> >>+ >>+/* Run tests for multiple files */ >>+static int read_mem_test(void) >>+{ >>+ int error = EOK; >>+ int i = 0; >>+ int edge = 5; >>+ char infile[PATH_MAX]; >>+ char outfile[PATH_MAX]; >>+ char *srcdir = NULL; >>+ const char *files[] = { "real", >>+ "mysssd", >>+ "ipa", >>+ "test", >>+ "smerge", >>+ "real8", >>+ "real16be", >>+ "real16le", >>+ "real32be", >>+ "real32le", >>+ "symbols", >I am attaching two files: empty.conf (size is zero) > new_line.conf (size is one and contains only '\n' >Could you add them to tests? > >>+ NULL }; >>+ >>+ INIOUT(printf("<==== Read mem test ====>\n")); >>+ >>+ srcdir = getenv("srcdir"); >>+ >>+ while(files[i]) { >>+ for ( edge = 15; edge < 100; edge +=25) { >>+ snprintf(infile, PATH_MAX, "%s/ini/ini.d/%s.conf", >>+ (srcdir == NULL) ? "." : srcdir, files[i]); >>+ snprintf(outfile, PATH_MAX, "./%s_%d.conf.mem.out", files[i], >>edge); >>+ error = test_one_file(infile, outfile, edge, 1); >>+ INIOUT(printf("Test for file: %s returned %d\n", files[i], >>error)); >>+ if ((error) && (strncmp(files[i], "test", 4) != 0)) return error; >>+ } >>+ i++; >>+ } >>+ >>+ INIOUT(printf("<==== Read mem test end ====>\n")); >>+ >>+ return EOK; >>+} >>+ >>+ >> /* Run tests for multiple files */ >> static int read_again_test(void) >> { >>@@ -241,7 +366,7 @@ static int read_again_test(void) >> snprintf(infile, PATH_MAX, "./%s_%d.conf.out", files[i], edge); >> snprintf(outfile, PATH_MAX, "./%s_%d.conf.2.out", files[i], >> edge); >> >>- error = test_one_file(infile, outfile, edge); >>+ error = test_one_file(infile, outfile, edge, 0); >> INIOUT(printf("Test for file: %s returned %d\n", files[i], >> error)); >> if (error) break; >> snprintf(command, PATH_MAX * 3, "diff -q %s %s", infile, >> outfile); >>@@ -3058,6 +3183,7 @@ int main(int argc, char *argv[]) >> int error = 0; >> test_fn tests[] = { read_save_test, >> read_again_test, >>+ read_mem_test, >> merge_values_test, >> merge_section_test, >> merge_file_test, >>-- >>1.7.1 >> > >>From: Dmitri Pal <d...@redhat.com> >>Date: Sat, 8 Mar 2014 19:02:29 -0500 >>Subject: [PATCH 3/4] [INI] Prevent tight loop >> >>New functionality added revealed a potential tight loop >>with files of the 0 length. This patch addresses this issue. >>--- >> ini/ini_parse.c | 24 +++++++++++++++--------- >> 1 files changed, 15 insertions(+), 9 deletions(-) >> >>diff --git a/ini/ini_parse.c b/ini/ini_parse.c >>index 7792324..0bab822 100644 >>--- a/ini/ini_parse.c >>+++ b/ini/ini_parse.c >>@@ -1534,16 +1534,22 @@ static int parser_error(struct parser_obj *po) >> else po->ret = EIO; >> } >> else if (po->error_level == INI_STOP_ON_NONE) { >>- action = PARSE_READ; >>- if (po->ret == 0) { >>- if (po->last_error & INI_WARNING) po->ret = EILSEQ; >>- else po->ret = EIO; >>+ if (po->last_error != ERR_READ) { >>+ action = PARSE_READ; >>+ if (po->ret == 0) { >>+ if (po->last_error & INI_WARNING) po->ret = EILSEQ; >>+ else po->ret = EIO; >>+ } >>+ /* It it was warning but now if it is an error >>+ * bump to return code to indicate error. */ >>+ else if((po->ret == EILSEQ) && >>+ (!(po->last_error & INI_WARNING))) po->ret = EIO; >>+ } >>+ else { >>+ /* Avoid endless loop */ >>+ action = PARSE_DONE; >>+ po->ret = EIO; >> } >>- /* It it was warning but now if it is an error >>- * bump to return code to indicate error. */ >>- else if((po->ret == EILSEQ) && >>- (!(po->last_error & INI_WARNING))) po->ret = EIO; >>- >> } >> else { /* Stop on error */ >> if (po->last_error & INI_WARNING) { > >ACK to this patch. > >LS
> >_______________________________________________ >sssd-devel mailing list >sssd-devel@lists.fedorahosted.org >https://lists.fedorahosted.org/mailman/listinfo/sssd-devel _______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel