prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Cron.py unicode decode error
  It looks like input evidence caused a unicode error for cron. I think this would only be raised when receiving unreadable input but filing this if we want to catch this exception differently/look into it further
  
  ```
   Traceback (most recent call last):
    File "/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/__init__.py", line 1005, in run_wrapper
      self.result = self.run(evidence, self.result)
    File "/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/cron.py", line 54, in run
      crontab = input_file.read()
    File "/usr/lib/python3.8/codecs.py", line 322, in decode
      (result, consumed) = self._buffer_decode(data, self.errors, final)
  UnicodeDecodeError: 'utf-8' codec can't decode byte 0xdc in position 0: invalid continuation byte
  ```
  
  </issue>
  <code>
  [start of turbinia/workers/cron.py]
  1 # -*- coding: utf-8 -*-
  2 # Copyright 2021 Google Inc.
  3 #
  4 # Licensed under the Apache License, Version 2.0 (the "License");
  5 # you may not use this file except in compliance with the License.
  6 # You may obtain a copy of the License at
  7 #
  8 #      http://www.apache.org/licenses/LICENSE-2.0
  9 #
  10 # Unless required by applicable law or agreed to in writing, software
  11 # distributed under the License is distributed on an "AS IS" BASIS,
  12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 # See the License for the specific language governing permissions and
  14 # limitations under the License.
  15 """Task for analysing cron files."""
  16 
  17 from __future__ import unicode_literals
  18 
  19 import os
  20 import re
  21 
  22 from turbinia.evidence import EvidenceState as state
  23 from turbinia.evidence import ReportText
  24 from turbinia.lib import text_formatter as fmt
  25 from turbinia.workers import TurbiniaTask
  26 from turbinia.workers import Priority
  27 
  28 
  29 class CronAnalysisTask(TurbiniaTask):
  30   """Task to analyze crontabs."""
  31 
  32   REQUIRED_STATES = [
  33       state.ATTACHED, state.CONTAINER_MOUNTED, state.DECOMPRESSED
  34   ]
  35 
  36   def run(self, evidence, result):
  37     """Run the cron analysis worker.
  38 
  39     Args:
  40         evidence (Evidence object):  The evidence we will process.
  41         result (TurbiniaTaskResult): The object to place task results into.
  42 
  43     Returns:
  44         TurbiniaTaskResult object.
  45     """
  46     # Where to store the resulting output file.
  47     output_file_name = 'cron_analysis.txt'
  48     output_file_path = os.path.join(self.output_dir, output_file_name)
  49     # Set the output file as the data source for the output evidence.
  50     output_evidence = ReportText(source_path=output_file_path)
  51 
  52     # Read the input file
  53     with open(evidence.local_path, 'r') as input_file:
  54       crontab = input_file.read()
  55 
  56     (report, priority, summary) = self.analyse_crontab(crontab)
  57     output_evidence.text_data = report
  58     result.report_priority = priority
  59     result.report_data = report
  60 
  61     # Write the report to the output file.
  62     with open(output_file_path, 'wb') as fh:
  63       fh.write(output_evidence.text_data.encode('utf-8'))
  64 
  65     # Add the resulting evidence to the result object.
  66     result.add_evidence(output_evidence, evidence.config)
  67     result.close(self, success=True, status=summary)
  68     return result
  69 
  70   def analyse_crontab(self, crontab):
  71     """Analyses a Cron file.
  72 
  73     Args:
  74       crontab (str): file content.
  75 
  76     Returns:
  77       Tuple(
  78         report_text(str): The report data
  79         report_priority(int): The priority of the report (0 - 100)
  80         summary(str): A summary of the report (used for task status)
  81       )
  82     """
  83     findings = []
  84     wget_or_curl = re.compile(r'(wget|curl)', re.IGNORECASE | re.MULTILINE)
  85     pipe_to_sh = re.compile(r'\|(.*)sh ', re.IGNORECASE | re.MULTILINE)
  86     get_piped_to_sh = re.compile(
  87         r'((wget|curl).*\|)+(.*sh)', re.IGNORECASE | re.MULTILINE)
  88 
  89     if re.search(get_piped_to_sh, crontab):
  90       findings.append(fmt.bullet('Remote file retrieval piped to a shell.'))
  91     elif re.search(wget_or_curl, crontab):
  92       findings.append(fmt.bullet('Remote file retrieval'))
  93     elif re.search(pipe_to_sh, crontab):
  94       findings.append(fmt.bullet('File piped to shell'))
  95 
  96     if findings:
  97       summary = 'Potentially backdoored crontab found.'
  98       findings.insert(0, fmt.heading4(fmt.bold(summary)))
  99       report = '\n'.join(findings)
  100       return (report, Priority.HIGH, summary)
  101 
  102     report = 'No issues found in crontabs'
  103     return (report, Priority.LOW, report)
  104
  [end of turbinia/workers/cron.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/turbinia/workers/cron.py b/turbinia/workers/cron.py
  --- a/turbinia/workers/cron.py
  +++ b/turbinia/workers/cron.py
  @@ -51,7 +51,14 @@
   
       # Read the input file
       with open(evidence.local_path, 'r') as input_file:
  -      crontab = input_file.read()
  +      try:
  +        crontab = input_file.read()
  +      except UnicodeDecodeError as exception:
  +        message = 'Error parsing cron file {0:s}: {1!s}'.format(
  +            evidence.local_path, exception)
  +        result.log(message)
  +        result.close(self, success=False, status=message)
  +        return result
   
       (report, priority, summary) = self.analyse_crontab(crontab)
       output_evidence.text_data = report
  
verification_info: {"golden_diff": "diff --git a/turbinia/workers/cron.py b/turbinia/workers/cron.py\n--- a/turbinia/workers/cron.py\n+++ b/turbinia/workers/cron.py\n@@ -51,7 +51,14 @@\n \n     # Read the input file\n     with open(evidence.local_path, 'r') as input_file:\n-      crontab = input_file.read()\n+      try:\n+        crontab = input_file.read()\n+      except UnicodeDecodeError as exception:\n+        message = 'Error parsing cron file {0:s}: {1!s}'.format(\n+            evidence.local_path, exception)\n+        result.log(message)\n+        result.close(self, success=False, status=message)\n+        return result\n \n     (report, priority, summary) = self.analyse_crontab(crontab)\n     output_evidence.text_data = report\n", "issue": "Cron.py unicode decode error\nIt looks like input evidence caused a unicode error for cron. I think this would only be raised when receiving unreadable input but filing this if we want to catch this exception differently/look into it further\r\n\r\n```\r\n Traceback (most recent call last):\r\n  File \"/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/__init__.py\", line 1005, in run_wrapper\r\n    self.result = self.run(evidence, self.result)\r\n  File \"/usr/local/lib/python3.8/dist-packages/turbinia-20220216-py3.8.egg/turbinia/workers/cron.py\", line 54, in run\r\n    crontab = input_file.read()\r\n  File \"/usr/lib/python3.8/codecs.py\", line 322, in decode\r\n    (result, consumed) = self._buffer_decode(data, self.errors, final)\r\nUnicodeDecodeError: 'utf-8' codec can't decode byte 0xdc in position 0: invalid continuation byte\r\n```\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright 2021 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Task for analysing cron files.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport os\nimport re\n\nfrom turbinia.evidence import EvidenceState as state\nfrom turbinia.evidence import ReportText\nfrom turbinia.lib import text_formatter as fmt\nfrom turbinia.workers import TurbiniaTask\nfrom turbinia.workers import Priority\n\n\nclass CronAnalysisTask(TurbiniaTask):\n  \"\"\"Task to analyze crontabs.\"\"\"\n\n  REQUIRED_STATES = [\n      state.ATTACHED, state.CONTAINER_MOUNTED, state.DECOMPRESSED\n  ]\n\n  def run(self, evidence, result):\n    \"\"\"Run the cron analysis worker.\n\n    Args:\n        evidence (Evidence object):  The evidence we will process.\n        result (TurbiniaTaskResult): The object to place task results into.\n\n    Returns:\n        TurbiniaTaskResult object.\n    \"\"\"\n    # Where to store the resulting output file.\n    output_file_name = 'cron_analysis.txt'\n    output_file_path = os.path.join(self.output_dir, output_file_name)\n    # Set the output file as the data source for the output evidence.\n    output_evidence = ReportText(source_path=output_file_path)\n\n    # Read the input file\n    with open(evidence.local_path, 'r') as input_file:\n      crontab = input_file.read()\n\n    (report, priority, summary) = self.analyse_crontab(crontab)\n    output_evidence.text_data = report\n    result.report_priority = priority\n    result.report_data = report\n\n    # Write the report to the output file.\n    with open(output_file_path, 'wb') as fh:\n      fh.write(output_evidence.text_data.encode('utf-8'))\n\n    # Add the resulting evidence to the result object.\n    result.add_evidence(output_evidence, evidence.config)\n    result.close(self, success=True, status=summary)\n    return result\n\n  def analyse_crontab(self, crontab):\n    \"\"\"Analyses a Cron file.\n\n    Args:\n      crontab (str): file content.\n\n    Returns:\n      Tuple(\n        report_text(str): The report data\n        report_priority(int): The priority of the report (0 - 100)\n        summary(str): A summary of the report (used for task status)\n      )\n    \"\"\"\n    findings = []\n    wget_or_curl = re.compile(r'(wget|curl)', re.IGNORECASE | re.MULTILINE)\n    pipe_to_sh = re.compile(r'\\|(.*)sh ', re.IGNORECASE | re.MULTILINE)\n    get_piped_to_sh = re.compile(\n        r'((wget|curl).*\\|)+(.*sh)', re.IGNORECASE | re.MULTILINE)\n\n    if re.search(get_piped_to_sh, crontab):\n      findings.append(fmt.bullet('Remote file retrieval piped to a shell.'))\n    elif re.search(wget_or_curl, crontab):\n      findings.append(fmt.bullet('Remote file retrieval'))\n    elif re.search(pipe_to_sh, crontab):\n      findings.append(fmt.bullet('File piped to shell'))\n\n    if findings:\n      summary = 'Potentially backdoored crontab found.'\n      findings.insert(0, fmt.heading4(fmt.bold(summary)))\n      report = '\\n'.join(findings)\n      return (report, Priority.HIGH, summary)\n\n    report = 'No issues found in crontabs'\n    return (report, Priority.LOW, report)\n", "path": "turbinia/workers/cron.py"}]}