From: Reuben Thomas Date: Sat, 20 Jan 2018 00:01:53 +0000 (+0000) Subject: Overhaul error handling in transform steps (fixes Debian bug #215285) X-Git-Tag: v3.7~84 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f364f1e0831bac1a812ac22ae473da2c9263c9f5;p=recode Overhaul error handling in transform steps (fixes Debian bug #215285) Three main principles were applied: 1. Check all return codes (this fixes Debian bug #215285, data is lost when no space left on device). 2. Ensure that resources are not leaked (memory and file descriptors). 3. Consistently use the recode error signalling mechanism: rather than arbitrarily signalling failure on an I/O error, set error level RECODE_SYSTEM_ERROR, and signal failure according to fail_level. It proved to be useful to merge perform_{memory,pass}_sequence. --- diff --git a/src/mixed.c b/src/mixed.c index 29be7d8..01869e5 100644 --- a/src/mixed.c +++ b/src/mixed.c @@ -61,8 +61,7 @@ open_mixed (struct mixed *mixed, RECODE_TASK task) !task->output.file) { recode_perror (NULL, "fopen (%s)", task->output.name); - if (task->input.file != stdin) - fclose (task->input.file); + fclose (task->input.file); return false; } task->output.name = NULL; @@ -78,15 +77,18 @@ open_mixed (struct mixed *mixed, RECODE_TASK task) return true; } -static void +static bool close_mixed (struct mixed *mixed) { /* Clean up. */ - if (*(mixed->input_name)) - fclose (mixed->subtask.task->input.file); - if (*(mixed->output_name)) - fclose (mixed->subtask.task->output.file); + if (mixed->subtask.task->input.file + && fclose (mixed->subtask.task->input.file) != 0) + return false; + if (mixed->subtask.task->output.file + && fclose (mixed->subtask.task->output.file)) + return false; + return true; } static void @@ -125,70 +127,27 @@ bool transform_c_source (RECODE_TASK task) { struct mixed mixed; - bool status = true; int character; if (!open_mixed (&mixed, task)) - return false; - - character = get_byte (&mixed.subtask); - while (character != EOF) - switch (character) - { - case '\'': - /* Skip character constant, while copying it untranslated. */ - - put_byte ('\'', &mixed.subtask); - character = get_byte (&mixed.subtask); - - if (character == EOF) - { - status = false; - break; - } - - if (character == '\\') + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + else + { + character = get_byte (&mixed.subtask); + while (character != EOF) + switch (character) { - put_byte ('\\', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character == EOF) - { - status = false; - break; - } - put_byte (character, &mixed.subtask); - character = get_byte (&mixed.subtask); - } + case '\'': + /* Skip character constant, while copying it untranslated. */ - if (character == '\'') - { put_byte ('\'', &mixed.subtask); character = get_byte (&mixed.subtask); - } - else - status = false; - break; - - case '"': - /* Copy the string, translated. */ - put_byte ('"', &mixed.subtask); - character = get_byte (&mixed.subtask); - - /* Read in string. */ - - start_accumulation (&mixed); - - while (true) - { if (character == EOF) { - recode_accumulated (&mixed); - status = false; + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); break; } - if (character == '"') - break; if (character == '\\') { @@ -196,90 +155,135 @@ transform_c_source (RECODE_TASK task) character = get_byte (&mixed.subtask); if (character == EOF) { - recode_accumulated (&mixed); - status = false; + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); break; } + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); } - put_byte (character, &mixed.subtask); - character = get_byte (&mixed.subtask); - } - if (character == EOF) - break; - - /* Translate string and dump it. */ - - if (!recode_accumulated (&mixed)) - status = false; - put_byte ('"', &mixed.subtask); - character = get_byte (&mixed.subtask); - break; - - case '/': - put_byte ('/', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character == EOF) - break; - if (character == '*') - { - /* Copy the comment, translated. */ - put_byte ('*', &mixed.subtask); + if (character == '\'') + { + put_byte ('\'', &mixed.subtask); + character = get_byte (&mixed.subtask); + } + else + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + break; + + case '"': + /* Copy the string, translated. */ + + put_byte ('"', &mixed.subtask); character = get_byte (&mixed.subtask); - /* Read in comment. */ + /* Read in string. */ start_accumulation (&mixed); + while (true) { if (character == EOF) { recode_accumulated (&mixed); - status = false; + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); break; } - if (character == '*') + if (character == '"') + break; + + if (character == '\\') { + put_byte ('\\', &mixed.subtask); character = get_byte (&mixed.subtask); if (character == EOF) { recode_accumulated (&mixed); - status = false; - put_byte ('*', &mixed.subtask); + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); break; } - if (character == '/') - break; - put_byte ('*', &mixed.subtask); - } - else - { - put_byte (character, &mixed.subtask); - character = get_byte (&mixed.subtask); } + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); } - if (character == EOF) break; - /* Translate comment and dump it. */ + /* Translate string and dump it. */ if (!recode_accumulated (&mixed)) - status = false; - put_byte ('*', &mixed.subtask); + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + put_byte ('"', &mixed.subtask); + character = get_byte (&mixed.subtask); + break; + + case '/': put_byte ('/', &mixed.subtask); character = get_byte (&mixed.subtask); - } - break; + if (character == EOF) + break; + if (character == '*') + { + /* Copy the comment, translated. */ - default: - put_byte (character, &mixed.subtask); - character = get_byte (&mixed.subtask); - break; - } + put_byte ('*', &mixed.subtask); + character = get_byte (&mixed.subtask); - close_mixed (&mixed); - return status; + /* Read in comment. */ + + start_accumulation (&mixed); + while (true) + { + if (character == EOF) + { + recode_accumulated (&mixed); + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + break; + } + if (character == '*') + { + character = get_byte (&mixed.subtask); + if (character == EOF) + { + recode_accumulated (&mixed); + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + put_byte ('*', &mixed.subtask); + break; + } + if (character == '/') + break; + put_byte ('*', &mixed.subtask); + } + else + { + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); + } + } + + if (character == EOF) + break; + + /* Translate comment and dump it. */ + + if (!recode_accumulated (&mixed)) + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + put_byte ('*', &mixed.subtask); + put_byte ('/', &mixed.subtask); + character = get_byte (&mixed.subtask); + } + break; + + default: + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); + break; + } + } + + if (!close_mixed (&mixed)) + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + SUBTASK_RETURN (&mixed.subtask); } /*------------------------------------------------------------------------. @@ -298,140 +302,135 @@ bool transform_po_source (RECODE_TASK task) { struct mixed mixed; - bool status = true; bool recode = false; bool msgstr = false; - int character; if (!open_mixed (&mixed, task)) - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + else + { + int character = get_byte (&mixed.subtask); + while (character != EOF) + switch (character) + { + case '#': + /* Copy a comment, recoding only those written by translators. */ - character = get_byte (&mixed.subtask); - while (character != EOF) - switch (character) - { - case '#': - /* Copy a comment, recoding only those written by translators. */ + put_byte ('#', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character == EOF) + break; + recode = character == ' ' || character == '\t'; - put_byte ('#', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character == EOF) - break; - recode = character == ' ' || character == '\t'; + if (recode) + start_accumulation (&mixed); + + while (character != '\n' && character != EOF) + { + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); + } - if (recode) - start_accumulation (&mixed); + if (recode && !recode_accumulated (&mixed)) + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); - while (character != '\n' && character != EOF) - { - put_byte (character, &mixed.subtask); + if (character == EOF) + break; + put_byte ('\n', &mixed.subtask); character = get_byte (&mixed.subtask); - } + break; - if (recode) - { - if (!recode_accumulated (&mixed)) - status = false; - } + case 'm': + /* Attempt to recognise `msgstr'. */ - if (character == EOF) - break; - put_byte ('\n', &mixed.subtask); - character = get_byte (&mixed.subtask); - break; - - case 'm': - /* Attempt to recognise `msgstr'. */ - - msgstr = false; - - put_byte ('m', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character != 's') - break; - put_byte ('s', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character != 'g') - break; - put_byte ('g', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character != 's') - break; - put_byte ('s', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character != 't') - break; - put_byte ('t', &mixed.subtask); - character = get_byte (&mixed.subtask); - if (character != 'r') - break; - put_byte ('r', &mixed.subtask); - character = get_byte (&mixed.subtask); - - msgstr = true; - break; - - case '"': - /* Copy the string, translating only the `msgstr' ones. */ - - put_byte ('"', &mixed.subtask); - character = get_byte (&mixed.subtask); - recode = msgstr; - - if (recode) - start_accumulation (&mixed); - - while (true) - { - if (character == EOF) - { - if (recode) - { - recode_accumulated (&mixed); - status = false; - } - break; - } - if (character == '"') + msgstr = false; + + put_byte ('m', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character != 's') + break; + put_byte ('s', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character != 'g') + break; + put_byte ('g', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character != 's') break; + put_byte ('s', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character != 't') + break; + put_byte ('t', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character != 'r') + break; + put_byte ('r', &mixed.subtask); + character = get_byte (&mixed.subtask); - if (character == '\\') + msgstr = true; + break; + + case '"': + /* Copy the string, translating only the `msgstr' ones. */ + + put_byte ('"', &mixed.subtask); + character = get_byte (&mixed.subtask); + recode = msgstr; + + if (recode) + start_accumulation (&mixed); + + while (true) { - put_byte ('\\', &mixed.subtask); - character = get_byte (&mixed.subtask); if (character == EOF) { if (recode) { recode_accumulated (&mixed); - status = false; + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); } break; } + if (character == '"') + break; + + if (character == '\\') + { + put_byte ('\\', &mixed.subtask); + character = get_byte (&mixed.subtask); + if (character == EOF) + { + if (recode) + { + recode_accumulated (&mixed); + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + } + break; + } + } + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); } - put_byte (character, &mixed.subtask); - character = get_byte (&mixed.subtask); - } - if (character == EOF) - break; + if (character == EOF) + break; - if (recode) - { - if (!recode_accumulated (&mixed)) - status = false; - } + if (recode && !recode_accumulated (&mixed)) + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); - put_byte ('"', &mixed.subtask); - character = get_byte (&mixed.subtask); - break; + put_byte ('"', &mixed.subtask); + character = get_byte (&mixed.subtask); + break; - default: - put_byte (character, &mixed.subtask); - character = get_byte (&mixed.subtask); - break; - } + default: + put_byte (character, &mixed.subtask); + character = get_byte (&mixed.subtask); + break; + } + } - close_mixed (&mixed); - return status; + if (!close_mixed (&mixed)) + recode_if_nogo (RECODE_SYSTEM_ERROR, &mixed.subtask); + SUBTASK_RETURN (&mixed.subtask); } diff --git a/src/task.c b/src/task.c index 1075525..db7aa2f 100644 --- a/src/task.c +++ b/src/task.c @@ -52,21 +52,24 @@ void put_byte (int byte, RECODE_SUBTASK subtask) { if (subtask->output.file) - putc (byte, subtask->output.file); + { + if (putc (byte, subtask->output.file) == EOF) + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + } else if (subtask->output.cursor == subtask->output.limit) { RECODE_OUTER outer = subtask->task->request->outer; size_t old_size = subtask->output.limit - subtask->output.buffer; size_t new_size = old_size * 3 / 2 + 40; - /* FIXME: Rethink about how the error should be reported. */ - if (REALLOC (subtask->output.buffer, new_size, char)) { subtask->output.cursor = subtask->output.buffer + old_size; subtask->output.limit = subtask->output.buffer + new_size; *subtask->output.cursor++ = byte; } + else + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); } else *subtask->output.cursor++ = byte; @@ -113,12 +116,14 @@ transform_mere_copy (RECODE_SUBTASK subtask) if (fwrite (buffer, BUFFER_SIZE, 1, subtask->output.file) != 1) { recode_perror (NULL, "fwrite ()"); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } if (size > 0) if (fwrite (buffer, size, 1, subtask->output.file) != 1) { recode_perror (NULL, "fwrite ()"); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } } @@ -143,6 +148,7 @@ transform_mere_copy (RECODE_SUBTASK subtask) != 1) { recode_perror (NULL, "fwrite ()"); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } } @@ -205,20 +211,18 @@ transform_byte_to_variable (RECODE_SUBTASK subtask) /*---------------------------------------------------------------------. | Execute the conversion sequence for a recoding TASK, using several | -| passes with two alternating memory buffers. This routine assumes at | -| least one needed recoding step. | +| passes with two alternating memory buffers or intermediate files. | +| This routine assumes at least one needed recoding step. | `---------------------------------------------------------------------*/ static bool -perform_memory_sequence (RECODE_TASK task) +perform_sequence (RECODE_TASK task, enum recode_sequence_strategy strategy) { RECODE_CONST_REQUEST request = task->request; struct recode_subtask subtask_block; RECODE_SUBTASK subtask = &subtask_block; struct recode_read_write_text input; struct recode_read_write_text output; - unsigned sequence_index; - RECODE_CONST_STEP step; memset (subtask, 0, sizeof (struct recode_subtask)); memset (&input, 0, sizeof (struct recode_read_write_text)); @@ -227,11 +231,14 @@ perform_memory_sequence (RECODE_TASK task) /* Execute one pass for each step of the sequence. */ - for (sequence_index = 0; + for (unsigned sequence_index = 0; sequence_index < (unsigned)request->sequence_length && task->error_so_far < task->abort_level; sequence_index++) { + RECODE_CONST_STEP step = request->sequence_array + sequence_index; + subtask->step = step; + /* Select the input text for this step. */ if (sequence_index == 0) @@ -246,7 +253,8 @@ perform_memory_sequence (RECODE_TASK task) subtask->input.file == NULL) { recode_perror (NULL, "fopen (%s)", subtask->input.name); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + goto exit; } } } @@ -255,149 +263,42 @@ perform_memory_sequence (RECODE_TASK task) subtask->input.buffer = input.buffer; subtask->input.cursor = input.buffer; subtask->input.limit = input.cursor; - } - - /* Select the output text for this step. */ - - if (sequence_index < (unsigned)request->sequence_length - 1) - { - subtask->output = output; - subtask->output.cursor = subtask->output.buffer; - } - else - { - subtask->output = task->output; + subtask->input.file = input.file; - if (subtask->output.name) + if (strategy == RECODE_SEQUENCE_WITH_FILES && + fseek (subtask->input.file, 0L, SEEK_SET) != 0) { - if (!*subtask->output.name) - subtask->output.file = stdout; - else if (subtask->output.file = fopen (subtask->output.name, - "w"), - subtask->output.file == NULL) - { - recode_perror (NULL, "fopen (%s)", subtask->output.name); - return false; - } + recode_perror (NULL, "fseek (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + goto exit; } } - /* Execute one recoding step. */ - - step = request->sequence_array + sequence_index; - subtask->step = step; - (*step->transform_routine) (subtask); - - /* Post-step clean up. */ - - if (sequence_index == 0) - { - if (subtask->input.name && *subtask->input.name) - fclose (subtask->input.file); - - task->input = subtask->input; - - subtask->input.name = NULL; - subtask->input.file = NULL; - } - - /* Prepare for next step. */ - - task->swap_input = RECODE_SWAP_UNDECIDED; + /* Select the output text for this step. */ if (sequence_index < (unsigned)request->sequence_length - 1) { - output = input; - input = subtask->output; - } - else - { - if (subtask->output.name && *subtask->output.name) - fclose (subtask->output.file); - - task->output = subtask->output; - } - } - - /* Final clean up. */ - - /* FIXME: Maybe we should manage this so it could wait, instead, for - avoiding buffer reallocation each time a new recoding is done? */ - - free (input.buffer); - free (output.buffer); - - SUBTASK_RETURN (subtask); -} - -/*-------------------------------------------------------------------------. -| Execute the conversion sequence for a recoding TASK, using several | -| passes with two alternating intermediate files. This routine assumes at | -| least one needed recoding step. | -`-------------------------------------------------------------------------*/ - -static bool -perform_pass_sequence (RECODE_TASK task) -{ - RECODE_CONST_REQUEST request = task->request; - struct recode_subtask subtask_block; - RECODE_SUBTASK subtask = &subtask_block; - struct recode_read_write_text input; - struct recode_read_write_text output; - unsigned sequence_index; - RECODE_CONST_STEP step; - - memset (subtask, 0, sizeof (struct recode_subtask)); - memset (&input, 0, sizeof (struct recode_read_write_text)); - memset (&output, 0, sizeof (struct recode_read_write_text)); - subtask->task = task; - - /* Execute one pass for each step of the sequence. */ - - for (sequence_index = 0; - sequence_index < (unsigned)request->sequence_length - && task->error_so_far < task->abort_level; - sequence_index++) - { - step = request->sequence_array + sequence_index; - subtask->step = step; - - /* Select the input text for this step. */ - - if (sequence_index == 0) - { - subtask->input = task->input; + subtask->output = output; - if (subtask->input.name) + switch (strategy) { - if (!*subtask->input.name) - subtask->input.file = stdin; - else if (subtask->input.file = fopen (subtask->input.name, "r"), - subtask->input.file == NULL) + case RECODE_SEQUENCE_IN_MEMORY: + subtask->output = output; + subtask->output.cursor = subtask->output.buffer; + break; + + case RECODE_SEQUENCE_WITH_FILES: + if (subtask->output.file = tmpfile (), subtask->output.file == NULL) { - recode_perror (NULL, "fopen (%s)", subtask->input.name); + recode_perror (NULL, "tmpfile ()"); recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); - return false; + goto exit; } - } - } - else - { - subtask->input.file = input.file; - rewind (subtask->input.file); - } - - /* Select the output text for this step. */ + break; - if (sequence_index < (unsigned)request->sequence_length - 1) - { - subtask->output = output; - - if (subtask->output.file = tmpfile (), subtask->output.file == NULL) - { - recode_perror (NULL, "tmpfile ()"); - recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); - return false; + default: /* Should never happen */ + recode_if_nogo (RECODE_INTERNAL_ERROR, subtask); + break; } } else @@ -408,13 +309,12 @@ perform_pass_sequence (RECODE_TASK task) { if (!*subtask->output.name) subtask->output.file = stdout; - else if (subtask->output.file = fopen (subtask->output.name, - "w"), + else if (subtask->output.file = fopen (subtask->output.name, "w"), subtask->output.file == NULL) { recode_perror (NULL, "fopen (%s)", subtask->output.name); recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); - return false; + goto exit; } } } @@ -425,21 +325,23 @@ perform_pass_sequence (RECODE_TASK task) /* Post-step clean up. */ - if (sequence_index == 0) + if (subtask->input.file) { - if (subtask->input.name && *subtask->input.name) - fclose (subtask->input.file); + FILE *fp = subtask->input.file; - task->input = subtask->input; - - subtask->input.name = NULL; - subtask->input.buffer = NULL; - subtask->input.cursor = NULL; - subtask->input.limit = NULL; + subtask->input.file = NULL; + if (fclose (fp) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + goto exit; + } } - else + + if (sequence_index == 0) { - fclose (subtask->input.file); + task->input = subtask->input; + memset (&subtask->input, 0, sizeof (struct recode_read_write_text)); } /* Prepare for next step. */ @@ -451,15 +353,27 @@ perform_pass_sequence (RECODE_TASK task) output = input; input = subtask->output; } - else - { - if (subtask->output.name && *subtask->output.name) - fclose (subtask->output.file); + } - task->output = subtask->output; - } + /* Final clean up. */ + exit: + + if (subtask->input.file && fclose (subtask->input.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + } + + if (subtask->output.file && fclose (subtask->output.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); } + free (input.buffer); + free (output.buffer); + + task->output = subtask->output; SUBTASK_RETURN (subtask); } @@ -522,12 +436,14 @@ perform_pipe_sequence (RECODE_TASK task) if (pipe (pipe_pair) < 0) { recode_perror (outer, "pipe ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } if (child_process = fork (), child_process < 0) { recode_perror (outer, "fork ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } if (child_process == 0) { @@ -537,23 +453,31 @@ perform_pipe_sequence (RECODE_TASK task) if (close (pipe_pair[1]) < 0) { recode_perror (outer, "close ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } if (subtask->input.file = fdopen (pipe_pair[0], "r"), subtask->input.file == NULL) { recode_perror (outer, "fdopen ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } step = request->sequence_array + sequence_index; subtask->step = step; (*step->transform_routine) (subtask); - fclose (subtask->input.file); - if (sequence_index < (unsigned)request->sequence_length - 1 - || *subtask->output.name) - fclose (subtask->output.file); + if (fclose (subtask->input.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + } + if (subtask->output.file && fclose (subtask->output.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + } exit (task->error_so_far < task->fail_level ? EXIT_SUCCESS : EXIT_FAILURE); @@ -565,17 +489,20 @@ perform_pipe_sequence (RECODE_TASK task) if (dup2 (pipe_pair[1], fileno (subtask->output.file)) < 0) { recode_perror (outer, "dup2 ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } if (close (pipe_pair[0]) < 0) { recode_perror (outer, "close ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } if (close (pipe_pair[1]) < 0) { recode_perror (outer, "close ()"); - return false; + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + SUBTASK_RETURN (subtask); } } } @@ -589,17 +516,23 @@ perform_pipe_sequence (RECODE_TASK task) subtask->input.file == NULL) { recode_perror (outer, "fopen (%s)", subtask->input.name); - return false; + SUBTASK_RETURN (subtask); } step = request->sequence_array; subtask->step = step; (*step->transform_routine) (subtask); - if (*subtask->input.name) - fclose (subtask->input.file); - - fclose (subtask->output.file); + if (subtask->input.file && fclose (subtask->input.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + } + if (subtask->output.file && fclose (subtask->output.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + } /* Wait on all children, mainly to avoid synchronisation problems on output file contents, but also to reduce the number of zombie @@ -724,10 +657,18 @@ perform_pipe_sequence (RECODE_TASK task) subtask->step = step; (*step->transform_routine) (subtask); - fclose (subtask->input.file); - if (sequence_index < request->sequence_length - 1 - || *subtask->output.name) - fclose (subtask->output.file); + if (subtask->input.file && fclose (subtask->input.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + return false; + } + if (subtask->output.file && fclose (subtask->output.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + return false; + } exit (task->error_so_far < task->fail_level ? EXIT_SUCCESS : EXIT_FAILURE); @@ -739,16 +680,19 @@ perform_pipe_sequence (RECODE_TASK task) if (dup2 (pipe_pair[1], fileno (subtask->output.file)) < 0) { recode_perror (outer, "dup2 ()"); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } if (close (pipe_pair[0]) < 0) { recode_perror (outer, "close ()"); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } if (close (pipe_pair[1]) < 0) { recode_perror (outer, "close ()"); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } } @@ -766,6 +710,7 @@ perform_pipe_sequence (RECODE_TASK task) subtask->input.file == NULL) { recode_perror (outer, "fopen (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } @@ -773,10 +718,19 @@ perform_pipe_sequence (RECODE_TASK task) subtask->step = step; (*step->transform_routine) (subtask); - if (*subtask->input.name) - fclose (subtask->input.file); + if (subtask->input.file && fclose (subtask->input.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + return false; + } - fclose (subtask->output.file); + if (subtask->output.file && fclose (subtask->output.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + return false; + } /* Wait on all children, mainly to avoid synchronisation problems on output file contents, but also to reduce the number of zombie @@ -792,6 +746,7 @@ perform_pipe_sequence (RECODE_TASK task) { recode_error (outer, _("Child process wait status is 0x%0.2x"), wait_status); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } @@ -919,13 +874,13 @@ recode_perform_task (RECODE_TASK task) if ((task->input.name || task->input.file) && (task->output.name || task->output.file)) - success = perform_pass_sequence (task); + success = perform_sequence (task, RECODE_SEQUENCE_WITH_FILES); else - success = perform_memory_sequence (task); + success = perform_sequence (task, RECODE_SEQUENCE_IN_MEMORY); break; case RECODE_SEQUENCE_IN_MEMORY: - success = perform_memory_sequence (task); + success = perform_sequence (task, RECODE_SEQUENCE_IN_MEMORY); break; case RECODE_SEQUENCE_WITH_PIPE: @@ -937,7 +892,7 @@ recode_perform_task (RECODE_TASK task) #endif case RECODE_SEQUENCE_WITH_FILES: - success = perform_pass_sequence (task); + success = perform_sequence (task, RECODE_SEQUENCE_WITH_FILES); break; default: @@ -963,6 +918,7 @@ recode_perform_task (RECODE_TASK task) subtask->input.file == NULL) { recode_perror (NULL, "fopen (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } } @@ -975,6 +931,7 @@ recode_perform_task (RECODE_TASK task) subtask->output.file == NULL) { recode_perror (NULL, "fopen (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); return false; } } @@ -991,10 +948,18 @@ recode_perform_task (RECODE_TASK task) task->output = subtask->output; - if (subtask->input.name && *subtask->input.name) - fclose (subtask->input.file); - if (subtask->output.name && *subtask->output.name) - fclose (subtask->output.file); + if (subtask->input.file && fclose (subtask->input.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->input.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + return false; + } + if (subtask->output.file && fclose (subtask->output.file) != 0) + { + recode_perror (NULL, "fclose (%s)", subtask->output.name); + recode_if_nogo (RECODE_SYSTEM_ERROR, subtask); + return false; + } } return success;