@flow.StateHandler(next_state="CheckHash")
  def ReceiveFileHash(self, responses):
    """Add hash digest to tracker and check with filestore."""
    # Support old clients which may not have the new client action in place yet.
    # TODO(user): Deprecate once all clients have the HashFile action.

    if not responses.success and responses.request.request.name == "HashFile":
      logging.debug(
          "HashFile action not available, falling back to FingerprintFile.")
      self.CallClient("FingerprintFile", responses.request.request.payload,
                      next_state="ReceiveFileHash",
                      request_data=responses.request_data)
      return

    index = responses.request_data["index"]
    if not responses.success:
      self.Log("Failed to hash file: %s", responses.status)
      self.state.pending_hashes.pop(index, None)
      self.FileFetchFailed(responses.request.request.payload.pathspec,
                           responses.request.request.name,
                           request_data=responses.request_data)
      return

    self.state.files_hashed += 1
    response = responses.First()
    if response.HasField("hash"):
      hash_obj = response.hash
    else:
      # Deprecate this method of returning hashes.
      hash_obj = rdf_crypto.Hash()

      if len(response.results) < 1 or response.results[0]["name"] != "generic":
        self.Log("Failed to hash file: %s", self.state.indexed_pathspecs[index])
        self.state.pending_hashes.pop(index, None)
        return

      result = response.results[0]

      try:
        for hash_type in ["md5", "sha1", "sha256"]:
          value = result.GetItem(hash_type)
          setattr(hash_obj, hash_type, value)
      except AttributeError:
        self.Log("Failed to hash file: %s", self.state.indexed_pathspecs[index])
        self.state.pending_hashes.pop(index, None)
        return

    try:
      tracker = self.state.pending_hashes[index]
    except __HOLE__:
      # TODO(user): implement a test for this and handle the failure
      # gracefully: i.e. maybe we can continue with an empty StatEntry.
      self.Error("Couldn't stat the file, but got the hash (%s): %s" %
                 (utils.SmartStr(index), utils.SmartStr(response.pathspec)))
      return

    tracker.hash_obj = hash_obj
    tracker.bytes_read = response.bytes_read

    self.state.files_hashed_since_check += 1
    if self.state.files_hashed_since_check >= self.MIN_CALL_TO_FILE_STORE:
      self._CheckHashesWithFileStore()
dataset/ETHPy150Open google/grr/grr/lib/flows/general/transfer.py/MultiGetFileMixin.ReceiveFileHash