fcntl
—— 系统调用 fcntl
和 ioctl
¶
本模块基于文件描述符来进行文件控制和 I/O 控制。它是 Unix 系统调用 fcntl()
和 ioctl()
的接口。关于这些调用的完整描述,请参阅 Unix 手册的 fcntl(2) 和 ioctl(2) 页面。
Availability: not Emscripten, not WASI.
This module does not work or is not available on WebAssembly platforms
wasm32-emscripten
and wasm32-wasi
. See
WebAssembly platforms for more information.
本模块的所有函数都接受文件描述符 fd 作为第一个参数。可以是一个整数形式的文件描述符,比如 sys.stdin.fileno()
的返回结果,或为 io.IOBase
对象,比如 sys.stdin
提供一个 fileno()
,可返回一个真正的文件描述符。
在 3.8 版更改: fcntl 模块现在有了 F_ADD_SEALS
、F_GET_SEALS
和 F_SEAL_*
常量,用于文件描述符 os.memfd_create()
的封装。
在 3.9 版更改: On macOS, the fcntl module exposes the F_GETPATH
constant, which obtains
the path of a file from a file descriptor.
On Linux(>=3.15), the fcntl module exposes the F_OFD_GETLK
, F_OFD_SETLK
and F_OFD_SETLKW
constants, which are used when working with open file
description locks.
在 3.10 版更改: 在 Linux 2.6.11 以上版本中,fcntl 模块提供了 F_GETPIPE_SZ
和``F_SETPIPE_SZ`` 常量,分别用于检查和修改管道的大小。
在 3.11 版更改: On FreeBSD, the fcntl module exposes the F_DUP2FD
and F_DUP2FD_CLOEXEC
constants, which allow to duplicate a file descriptor, the latter setting
FD_CLOEXEC
flag in addition.
在 3.12 版更改: On Linux >= 4.5, the fcntl
module exposes the FICLONE
and
FICLONERANGE
constants, which allow to share some data of one file with
another file by reflinking on some filesystems (e.g., btrfs, OCFS2, and
XFS). This behavior is commonly referred to as “copy-on-write”.
这个模块定义了以下函数:
- fcntl.fcntl(fd, cmd, arg=0)¶
对文件描述符 fd 执行 cmd 操作(能够提供
fileno()
方法的文件对象也可以接受)。 cmd 可用的值与操作系统有关,在fcntl
模块中可作为常量使用,名称与相关 C 语言头文件中的一样。参数 arg 可以是整数或bytes
对象。若为整数值,则本函数的返回值是 C 语言fcntl()
调用的整数返回值。若为字节串,则其代表一个二进制结构,比如由struct.pack()
创建的数据。该二进制数据将被复制到一个缓冲区,缓冲区地址传给 C 调用fcntl()
。调用成功后的返回值位于缓冲区内,转换为一个bytes
对象。返回的对象长度将与 arg 参数的长度相同。上限为 1024 字节。如果操作系统在缓冲区中返回的信息大于 1024 字节,很可能导致内存段冲突,或更为不易察觉的数据错误。如果
fcntl()
调用失败,会触发OSError
。引发一条 auditing 事件
fcntl.fcntl
,参数为fd
、cmd
、arg
。
- fcntl.ioctl(fd, request, arg=0, mutate_flag=True)¶
本函数与
fcntl()
函数相同,只是参数的处理更加复杂。request 参数的上限是 32位。
termios
模块中包含了可用作 request 参数其他常量,名称与相关 C 头文件中定义的相同。参数 arg 可为整数、支持只读缓冲区接口的对象(如
bytes
)或支持读写缓冲区接口的对象(如bytearray
)。除了最后一种情况,其他情况下的行为都与
fcntl()
函数一样。如果传入的是个可变缓冲区,那么行为就由 mutate_flag 参数决定。
如果 mutate_flag 为 False,缓冲区的可变性将被忽略,行为与只读缓冲区一样,只是没有了上述 1024 字节的上限——只要传入的缓冲区能容纳操作系统放入的数据即可。
如果 mutate_flag 为 True(默认值),那么缓冲区(实际上)会传给底层的 系统调用
ioctl()
,其返回代码则会回传给调用它的 Python,而缓冲区的新数据则反映了ioctl()
的运行结果。这里做了一点简化,因为若是给出的缓冲区少于 1024 字节,首先会被复制到一个 1024 字节长的静态缓冲区再传给ioctl()
,然后把结果复制回给出的缓冲区去。如果
ioctl()
调用失败,则会触发OSError
异常。举个例子:
>>> import array, fcntl, struct, termios, os >>> os.getpgrp() 13341 >>> struct.unpack('h', fcntl.ioctl(0, termios.TIOCGPGRP, " "))[0] 13341 >>> buf = array.array('h', [0]) >>> fcntl.ioctl(0, termios.TIOCGPGRP, buf, 1) 0 >>> buf array('h', [13341])
触发一条 auditing 事件
fcntl.ioctl
,参数为fd
、request
、arg
。
- fcntl.flock(fd, operation)¶
在文件描述符 fd 上执行加锁操作 operation (也接受能提供
fileno()
方法的文件对象)。 详见 Unix 手册 flock(2)。 (在某些系统中,此函数是用fcntl()
模拟出来的。)如果
flock()
调用失败,就会触发OSError
异常。触发一条 审计事件
fcntl.flock
,参数为fd
、operation
。
- fcntl.lockf(fd, cmd, len=0, start=0, whence=0)¶
本质上是对
fcntl()
加锁调用的封装。fd 是要加解锁的文件描述符(也接受能提供fileno()
方法的文件对象),cmd 是以下值之一:LOCK_UN
——解锁LOCK_SH
—— 获取一个共享锁LOCK_EX
—— 获取一个独占锁
如果 cmd 为
LOCK_SH
或LOCK_EX
,则还可以与LOCK_NB
进行按位或运算,以避免在获取锁时出现阻塞。 如果用了LOCK_NB
,无法获取锁时将触发OSError
,此异常的 errno 属性将被设为EACCES
或EAGAIN
(视操作系统而定;为了保证可移植性,请检查这两个值)。 至少在某些系统上,只有当文件描述符指向需要写入而打开的文件时,才可以使用LOCK_EX
。len 是要锁定的字节数,start 是自 whence 开始锁定的字节偏移量,whence 与
io.IOBase.seek()
的定义一样。0
—— 自文件起始位置(os.SEEK_SET
)。1
—— 自缓冲区当前位置(os.SEEK_CUR
)2
—— 自文件末尾(os.SEEK_END
)
start 的默认值为 0,表示从文件起始位置开始。len 的默认值是 0,表示加锁至文件末尾。 whence 的默认值也是 0。
触发一条 审计事件
fcntl.lockf
,参数为fd
、cmd
、len
、start
、whence
。
示例(都是运行于符合 SVR4 的系统):
import struct, fcntl, os
f = open(...)
rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY)
lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)
注意,在第一个例子中,返回值变量 rv 将存有整数;在第二个例子中,该变量中将存有一个 bytes
对象。lockdata 变量的结构布局视系统而定——因此采用 flock()
调用可能会更好。