docs: def GetExtAttrs(filepath):
    """Fetches extended file attributes.
  
    Args:
      filepath: A path to the file.
  
    Yields:
      `ExtAttr` pairs.
    """
    path = CanonicalPathToLocalPath(filepath)
  
    try:
      attr_names = xattr.listxattr(path)
    except (IOError, OSError, UnicodeDecodeError) as error:
      msg = "Failed to retrieve extended attributes for '%s': %s"
      logging.error(msg, path, error)
      return
  
    # `xattr` (version 0.9.2) decodes names as UTF-8. Since we (and the system)
    # allows for names and values to be arbitrary byte strings, we use `bytes`
    # rather than `unicode` objects here. Therefore we have to re-encode what
    # `xattr` has decoded. Additionally, because the decoding that `xattr` does
    # may fail, we additionally guard against such exceptions.
    def EncodeUtf8(attr_name):
      if isinstance(attr_name, Text):
        return attr_name.encode("utf-8")
      if isinstance(attr_name, bytes):
        return attr_name
      raise TypeError("Unexpected type `%s`" % type(attr_name))
  
    for attr_name in attr_names:
      attr_name = EncodeUtf8(attr_name)
      try:
        attr_value = xattr.getxattr(path, attr_name)
      except (IOError, OSError) as error:
        msg = "Failed to retrieve attribute '%s' for '%s': %s"
        logging.error(msg, attr_name, path, error)
        continue
  
      yield rdf_client_fs.ExtAttr(name=attr_name, value=attr_value)