fcntl
— fcntl
和 ioctl
系统调用¶
此模块对文件描述符执行文件和 I/O 控制。 它是 fcntl()
和 ioctl()
Unix 例程的接口。 有关完整详细信息,请参阅 fcntl(2) 和 ioctl(2) Unix 手册页。
可用性: Unix,而非 WASI。
此模块中的所有函数都将文件描述符 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 版本中变更: 在 macOS 上,fcntl
模块公开了 F_GETPATH
常量,该常量从文件描述符获取文件的路径。 在 Linux(>=3.15) 上,fcntl
模块公开了 F_OFD_GETLK
、F_OFD_SETLK
和 F_OFD_SETLKW
常量,这些常量在处理打开的文件描述锁时使用。
在 3.10 版本中变更: 在 Linux >= 2.6.11 上,fcntl
模块公开了 F_GETPIPE_SZ
和 F_SETPIPE_SZ
常量,它们允许分别检查和修改管道的大小。
在 3.11 版本中变更: 在 FreeBSD 上,fcntl
模块公开了 F_DUP2FD
和 F_DUP2FD_CLOEXEC
常量,它们允许复制文件描述符,后者还会设置 FD_CLOEXEC
标志。
在 3.12 版本中变更: 在 Linux >= 4.5 上,fcntl
模块公开了 FICLONE
和 FICLONERANGE
常量,它们允许通过在某些文件系统(例如,btrfs、OCFS2 和 XFS)上进行重新链接来与其他文件共享一个文件的一些数据。 此行为通常被称为“写入时复制”。
在 3.13 版本中变更: 在 Linux >= 2.6.32 上,fcntl
模块公开了 F_GETOWN_EX
、F_SETOWN_EX
、F_OWNER_TID
、F_OWNER_PID
、F_OWNER_PGRP
常量,它们允许将 I/O 可用性信号定向到特定线程、进程或进程组。 在 Linux >= 4.13 上,fcntl
模块公开了 F_GET_RW_HINT
、F_SET_RW_HINT
、F_GET_FILE_RW_HINT
、F_SET_FILE_RW_HINT
和 RWH_WRITE_LIFE_*
常量,这些常量允许通知内核关于给定 inode 或通过特定打开的文件描述进行写入的相对预期生命周期。 在 Linux >= 5.1 和 NetBSD 上,fcntl
模块公开了 F_SEAL_FUTURE_WRITE
常量,以用于 F_ADD_SEALS
和 F_GET_SEALS
操作。 在 FreeBSD 上,fcntl
模块公开了 F_READAHEAD
、F_ISUNIONSTACK
和 F_KINFO
常量。 在 macOS 和 FreeBSD 上,fcntl
模块公开了 F_RDAHEAD
常量。 在 NetBSD 和 AIX 上,fcntl
模块公开了 F_CLOSEM
常量。 在 NetBSD 上,fcntl
模块公开了 F_MAXFD
常量。 在 macOS 和 NetBSD 上,fcntl
模块公开了 F_GETNOSIGPIPE
和 F_SETNOSIGPIPE
常量。
该模块定义了以下函数
- fcntl.fcntl(fd, cmd, arg=0)¶
对文件描述符 fd 执行操作 cmd(也接受提供
fileno()
方法的文件对象)。 用于 cmd 的值取决于操作系统,并且在fcntl
模块中可用作常量,使用与相关 C 头文件中相同的名称。 参数 arg 可以是整数值,也可以是bytes
对象。 如果是整数值,则此函数的返回值是 Cfcntl()
调用的整数返回值。 当参数是字节时,它表示一个二进制结构,例如由struct.pack()
创建。 二进制数据被复制到缓冲区,该缓冲区的地址被传递给 Cfcntl()
调用。 成功调用后的返回值是缓冲区的内容,转换为bytes
对象。 返回对象的长度将与 arg 参数的长度相同。 这限制为 1024 字节。 如果操作系统在缓冲区中返回的信息大于 1024 字节,则很可能导致分段违规或更细微的数据损坏。如果
fcntl()
调用失败,则会引发OSError
。引发一个 审计事件
fcntl.fcntl
,参数为fd
、cmd
和arg
。
- fcntl.ioctl(fd, request, arg=0, mutate_flag=True)¶
此函数与
fcntl()
函数相同,只是参数处理更加复杂。request 参数的值被限制在 32 位以内。作为 request 参数使用的其他相关常量可以在
termios
模块中找到,名称与相关 C 头文件中使用的名称相同。参数 arg 可以是整数,支持只读缓冲接口的对象(如
bytes
)或支持读写缓冲接口的对象(如bytearray
)。除了最后一种情况,行为与
fcntl()
函数相同。如果传递的是可变缓冲区,则行为由 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])
引发一个 审计事件
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 是以下值之一- fcntl.LOCK_UN¶
释放现有锁。
- fcntl.LOCK_SH¶
获取共享锁。
- fcntl.LOCK_EX¶
获取独占锁。
- fcntl.LOCK_NB¶
与其他三个
LOCK_*
常量中的任何一个进行按位或运算,使请求成为非阻塞的。
如果使用
LOCK_NB
并且无法获取锁,则会引发OSError
,并且该异常将具有一个设置为EACCES
或EAGAIN
的 errno 属性(取决于操作系统;为了保证可移植性,请检查这两个值)。至少在某些系统上,只有当文件描述符引用为写入打开的文件时,才能使用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()
调用可能更好。