概述

概述

GIO 致力于提供现代化、易于使用的 VFS API,位于库堆栈的正确层级,以及其他对桌面应用程序(如网络和 D-Bus 支持)普遍有用的 API。目标是克服 GnomeVFS 的不足,提供一个如此出色的 API,以至于开发者愿意选择它而不是直接调用原始的 POSIX 调用。其中之一就是使用 GObject。这也意味着不克隆 POSIX API,而是提供更高级、以文档为中心的接口。

GIO 的抽象文件系统模型由一组 I/O 和文件的基本接口和类组成

GFile
文件的引用
GFileInfo
关于文件或文件系统的信息
GFileEnumerator
列出目录中的文件
GDrive
代表一个驱动器,可能包含零个或多个卷
GVolume
代表一个文件系统,可能有一个挂载点
GMount
代表已挂载的文件系统

然后是一系列流类,与可以在 Java 等框架中找到的输入和输出流层次结构相似

GInputStream
读取数据
GOutputStream
写入数据
GIOStream
读取和写入数据
GSeekable
由流可选实现的接口,支持查找

有与应用程序及其处理文件类型相关的接口

GAppInfo
关于已安装应用程序的信息
GIcon
文件和应用程序图标的高级类型

有一个存储和检索应用程序设置的框架

GSettings
存储和检索应用程序设置

支持网络编程,包括连接监控、名称解析、低级套接字 API 和高级客户端和服务器辅助类

GSocket
低级平台无关的套接字对象
GResolver
异步且可取消的 DNS 解析器
GSocketClient
高级网络客户端辅助程序
GSocketService
高级网络服务器辅助程序
GSocketConnection
网络连接流
GNetworkMonitor
网络连接监控

支持连接到 D-Bus,发送和接收消息,拥有和监视总线名称,以及在总线上提供对象

GDBusConnection
DBus 连接
GDBusMethodInvocation
用于处理远程调用
GDBusServer
接受连接的辅助程序
GDBusProxy
用于访问远程对象的 D-Bus 接口的代理

除了这些,GIO 还提供了文件监控、异步 I/O 和文件名完成等设施。除了接口之外,GIO 还为本地情况提供了实现。各种网络文件系统的实现由 GVFS 软件包作为可加载模块提供。

其他有意识地偏离 GnomeVFS 设计的设计选择是将后端移出进程,这最小化了依赖性膨胀,并使整个系统更健壮。后端不包括在 GIO 中,而是在独立的 GVFS 软件包中。此外,GVFS 软件包还包括 GVFS 守护程序,它为每个单独连接启动更多的挂载守护程序。

GIO in the GTK library stack

IO模型的GIO是状态性的:如果一个应用程序与服务器建立例如SFTP连接,它将对该会话中的所有应用程序可用;用户无需多次输入密码。

将VFS放入GLib层的最大优点之一是,GTK可以直接使用它,例如在文件选择器中。

编写GIO应用程序

关于编写GLib应用程序的信息,通常也适用于编写GIO应用程序。

线程

GDBus有自己的私有工作线程,因此使用GDBus的应用程序至少有3个线程。GIO大量使用线程默认主上下文的概念来执行异步方法的回调,即在启动操作的同一直线上。

异步编程

许多GIO函数有两个版本:同步和异步,后者以_async后缀表示。正确使用这些函数非常重要:同步调用不应在与其他代码共享的主循环中使用,例如在应用程序的主线程中。同步调用将在完成之前阻塞,I/O操作可能需要显著的时间(甚至在快速SSD上)。在等待I/O时阻塞主循环迭代意味着主循环中的其他来源将不会分派,例如输入和重绘处理程序的应用程序UI。这可能导致应用程序在I/O完成之前“冻结”。

有些自包容的函数组,如由gdbus-codegen生成的代码,使用不同的约定:函数默认为异步,同步版本具有_sync后缀。除了命名差异,它们应该与上述正常约定下的函数以相同的方式处理。

函数的异步(_async)版本在将I/O调度到内核并添加回调到主循环后立即将控制权返回给调用者。当操作完成时,将调用此回调。从回调中,应调用配对的_finish函数以检索I/O操作的返回值以及发生的任何错误。有关使用和实现异步函数的更多信息,请参阅GAsyncResultGTask

通过连续启动多个异步操作,它们将并行执行(不超过由GIO内部工作线程池强加的任意限制)。

函数的同步版本可以在应用程序启动初期使用,在没有主循环要阻塞的情况下,例如加载初始配置文件。它们还可以用于在本地磁盘上对保证为小的文件进行I/O。请注意,用户的主目录不一定在本地磁盘上。

安全性

当你的程序需要执行一些特权操作(例如,创建新用户账户)时,你可以通过以下几种方式来完成

  • 实现一个提供特权操作的守护程序。作为D-Bus系统总线服务的这种方式很方便。守护程序在执行操作之前可能需要检查调用者的身份和授权。polkit是允许这样做的一个框架。
  • 使用一个小型辅助程序,通过 pkexec 以提升权限执行。pkexec 是一个程序启动器,它是 polkit 的一部分。
  • 使用一个通过设置 suid root 以提升权限执行的小型辅助程序。

这些方法中没有绝对的优胜者,它们都有各自的优点和缺点。

在编写以提升权限运行的保护程序时,遵循一些基本的编程安全规则非常重要。David Wheeler 关于这个主题有一本优秀的书,Secure Programming for Linux and Unix HOWTO

在用于以提升权限运行代码的代码中使用 GIO 时,必须十分小心。《GIO》有多种扩展点,其实现在模块(共享对象中的可执行代码)中加载,这可能允许攻击者通过诱骗程序以模块的形式加载代码的方式将其自己的代码偷偷放入您的应用程序中。然而,《GIO》永远不会从您的家目录加载模块,除非明确通过环境变量请求这样做。

在大多数情况下,您的辅助程序应该很小,以至于您不需要 GIO,其 API 主要设计来支持完整的桌面应用程序。如果您无法抗拒这些 API 的便利性,请采取以下步骤

  • 清除环境,例如使用 clearenv() 函数。David Wheeler 就为什么需要清理环境有很好的解释。有关影响《GIO》的所有环境变量的列表,请参阅运行《GIO》应用程序的部分。特别是,PATH(用于定位二进制文件),GIO_EXTRA_MODULES(用于定位可加载模块)和DBUS_{SYSTEM,SESSION}_BUS_ADDRESS(用于定位 D-Bus 系统和会话总线)非常重要。
  • 不要使用 GVfs,在环境中设置 GIO_USE_VFS=local。在安全性敏感的程序中避免使用 GVfs 的原因在于它使用了许多尚未经过安全漏洞审计的库。GVfs 还分发广泛并依赖于会话总线存在。

编译 GIO 应用程序

GIO 附带一个 gio-2.0.pc 文件,您应与 pkg-config 一起使用以获取有关头文件和库的必要信息。有关如何使用 pkg-config 编译应用程序的更多信息,请参阅 pkg-config 手册页或 GLib 文档。

如果您在类似 UNIX 的系统上使用 GIO,则可能想要使用 UNIX 特定的 GIO 接口,如 GUnixInputStreamGUnixOutputStreamGUnixMountGDesktopAppInfo。为此,请使用 gio-unix-2.0.pc 文件以及 gio-2.0.pc(或在 GIR 命名空间术语中,GioUnix-2.0 以及 Gio-2.0)。

运行 GIO 应用程序

GIO 检查除 GLib 使用的外的一些环境变量。

  • XDG_DATA_HOMEXDG_DATA_DIRS。《GIO》使用这些环境变量定位 MIME 信息。有关更多信息,请参阅 Shared MIME-info DatabaseBase Directory Specification
  • GVFS_DISABLE_FUSE。可以设置此变量以防止 GVfs 启动 fuse 后端,在某些情况下,这可能是不必要的或不希望有的。
  • GIO_USE_VFS. 这个环境变量可以被设置为GVfs实现的名字,以在调试时覆盖默认值。包含在 GIO 中的本地文件GVfs实现名字为“local”,gvfs模块中的实现名字为“gvfs”。通常情况下,系统软件会将其设置为“local”,以避免GFile API进行不必要的D-Bus调用。特殊值help可用于打印标准输出中的可用实现列表。

以下环境变量仅对调试 GIO 本身或其加载的模块有用。它们不应在生产环境中设置。

  • GIO_USE_FILE_MONITOR. 这个变量可以被设置为GFileMonitor实现的名字,以在调试时覆盖默认值。Linux中包含在 GIO 的本地文件GFileMonitor实现名字为“inotify”,其他根据平台构建的作为模块的实现在(如“fam”和“fen”)。特殊值help可用于打印标准输出中的可用实现列表。
  • GIO_USE_VOLUME_MONITOR. 这个变量可以被设置为GVolumeMonitor实现的名字,以在调试时覆盖默认值。包含在 GIO 的本地文件GVolumeMonitor实现名字为“unix”,gvfs模块中基于udisks2的实现名字为“udisks2”。特殊值help可用于打印标准输出中的可用实现列表。
  • GIO_USE_TLS. 这个变量可以被设置为GTlsBackend实现的名字,以在调试时覆盖默认值。 GIO 没有自己的GTlsBackend实现,glib-networking模块中的基于gnutls的实现名字为“gnutls”。特殊值help可用于打印标准输出中的可用实现列表。
  • GIO_USE_PORTALS. 这个变量可以被设置以覆盖对portals的检测,并强制使用它们提供各种 GIO 功能,用于测试和调试。此变量不打算在生产环境中使用。
  • GIO_MODULE_DIR. 当此环境变量被设置为路径时,GIO 将从这个备用目录加载模块,而不是从 GIO 内置的目录加载。这在运行测试时很有用。在以setuid程序运行时,此环境变量将被忽略。
  • GIO_EXTRA_MODULES. 当此环境变量被设置为路径或以冒号分隔的路径集合时,GIO 将尝试从该路径加载额外的模块。在以setuid程序运行时,此环境变量将被忽略。
  • GSETTINGS_BACKEND. 这个变量可以被设置为GSettingsBackend实现的名字,以在调试时覆盖默认值。包含在 GIO 中的基于内存的实现名字为“memory”,dconf中的实现名字为“dconf”。特殊值help可用于打印标准输出中的可用实现列表。
  • GSETTINGS_SCHEMA_DIR. 这个变量可以被设置为目录名,以供寻找GSettings的编译模式,除了XDG系统数据目录的glib-2.0/schemas子目录。要指定多个目录,请使用G_SEARCHPATH_SEPARATOR_S作为分隔符。
  • DBUS_SYSTEM_BUS_ADDRESS. 这个变量被查询以找到D-Bus系统总线的地址。关于D-Bus地址的格式,请参阅D-Bus规范。设置此变量会覆盖确定系统总线地址的平台特定方式。
  • DBUS_SESSION_BUS_ADDRESS. 这个变量被查询以找到D-Bus会话总线的地址。设置此变量会覆盖确定会话总线地址的平台特定方式。
  • DBUS_STARTER_BUS_TYPE。此变量用于确定通过 D-Bus 激活启动的应用程序的“启动器”总线。可能的值是“system”或“session”。
  • G_DBUS_DEBUG。此变量可以被设置为一组调试选项,当使用 D-Bus 例程时,GLib 会打印出不同类型的调试信息。
  • transport:显示 I/O 活动情况(例如,读取和写入)
  • message:显示所有发送和接收到的 D-Bus 信息
  • payload:显示所有发送和接收到的 D-Bus 信息的有效载荷(隐含 message)
  • call:追踪 g_dbus_connection_call()g_dbus_connection_call_sync() API 使用
  • signal:显示接收到 D-Bus 信号的时刻
  • incoming:显示接收到 D-Bus 方法调用时刻
  • return:显示通过 GDBusMethodInvocation API 返回回复的时刻
  • emission:追踪 g_dbus_connection_emit_signal() API 使用
  • authentication:显示关于连接认证的信息
  • address:显示关于 D-Bus 地址查找和自动启动的信息
  • all:启用所有调试选项
  • help:将受支持的选项列表打印到标准输出
  • G_DBUS_COOKIE_SHA1_KEYRING_DIR。可以用来覆盖用于存储 DBUS_COOKIE_SHA1 认证机制中使用的密钥圈的目录。通常使用的目录是用户家目录中的 .dbus-keyrings
  • G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION。如果设置,则不会检查用于存储 DBUS_COOKIE_SHA1 认证机制中使用的密钥圈的目录的权限。通常该目录必须只能由用户读取。

扩展 GIO

大部分通过 GIO 访问的功能都是在可加载模块中实现的,模块提供了扩展 GIO 的便捷方式。除了支持编写此类模块的 GIOModule API,GIO 还有一个定义扩展点并注册其实例的机制,请参阅 GIOExtensionPoint

以下扩展点是由 GIO 当前定义的

  • G_VFS_EXTENSION_POINT_NAME。允许覆盖 GVfs 类的功能。实现此扩展点的实现必须继承自 GVfs。GIO 使用最优先的活跃实现,参见 g_vfs_is_active()。GIO 为本地文件实现了此扩展点,gvfs 包含一个支持 gvfs 中所有后端的实现。
  • G_VOLUME_MONITOR_EXTENSION_POINT_NAME。允许添加更多卷监控器。实现此扩展点的实现必须继承自 GVolumeMonitor。GIO 使用所有注册的扩展。gvfs 包含一个与 gvfs 中的 GVfs 实现一起工作的实现。
  • G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME。允许覆盖“本地”卷监控器。实现此扩展点的实现必须继承自 GNativeVolumeMonitor。GIO 使用优先级最高且得到支持的实现,由 GVolumeMonitorClass 中的 is_supported() vfunc 确定。GIO 为本地挂载实现了此扩展点,gvfs 包含一个基于 udisks2 的实现。
  • G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME。允许覆盖本地文件的文件监视器实现。此扩展点的实现必须从 GLocalFileMonitor 派生。GIO 使用最高优先级的实现,这是由 GLocalFileMonitorClass 中的 is_supported() vfunc 确定的。GIO 在内部使用此扩展点,在基于 fam 和基于 inotify 的文件监视器实现之间切换。
  • G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME。允许覆盖本地文件的目录监视器实现。此扩展点的实现必须从 GLocalDirectoryMonitor 派生。GIO 使用最高优先级的实现,这是由 GLocalDirectoryMonitorClass 中的 is_supported() vfunc 确定的。GIO 在内部使用此扩展点,在基于 fam 和基于 inotify 的目录监视器实现之间切换。
  • G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME。仅适用于 Unix。允许提供与 URI 方案关联默认处理程序的方式。此扩展点的实现必须实现 GDesktopAppInfoLookup 接口。GIO 使用最高优先级的实现。此扩展点已在 GLib 2.28 中停止使用。它仍然可用以保持 API 和 ABI 稳定,但 GIO 已不再使用它来处理默认处理程序。相反,使用 mime 处理程序机制,以及 x-scheme-handler 虚拟 mimetypes。
  • G_SETTINGS_BACKEND_EXTENSION_POINT_NAME。允许为 GSettings 提供替代存储。此扩展点的实现必须从 GSettingsBackend 类型派生。GIO 包含基于关键文件的此扩展点的实现,另一个由 dconf 提供。
  • G_PROXY_EXTENSION_POINT_NAME。允许提供网络代理的实现。此扩展点的实现必须提供 GProxy 接口,并且必须根据它们代理的网络协议进行命名。glib-networking 包含基于 libproxy 的此扩展点的实现。
  • G_TLS_BACKEND_EXTENSION_POINT_NAME。允许提供对 TLS 支持的实现。此扩展点的实现必须实现 GTlsBackend 接口。glib-networking 包含此扩展点的实现。
  • G_NETWORK_MONITOR_EXTENSION_POINT_NAME。允许提供网络连接监控的实现。此扩展点的实现必须实现 GNetworkMonitorInterface 接口。GIO 包含使用 Linux 内核 netlink 接口的此扩展点的实现。