ZetCode

Python os.fchown 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨了 Python 的 os.fchown 函数,该函数使用文件描述符更改文件所有权。我们将介绍 UID/GID 管理、权限要求和实际示例。

基本定义

os.fchown 函数更改由文件描述符引用的文件的所有者和组。它类似于 os.chown,但适用于打开的文件,而不是路径。

关键参数:fd(文件描述符),uid(用户 ID),gid(组 ID)。使用 -1 可以使 uid 或 gid 保持不变。需要适当的权限。

更改文件所有权

这个基本示例演示了更改打开文件的所有权。我们首先获取当前所有权,然后使用 os.fchown 修改它。

basic_ownership.py
import os
import pwd
import grp

file_path = "testfile.txt"

# Create a test file
with open(file_path, "w") as f:
    f.write("Test content")

# Open file and get current stats
with open(file_path, "r+") as f:
    stat_info = os.fstat(f.fileno())
    print(f"Current owner: {stat_info.st_uid}, group: {stat_info.st_gid}")

    # Change to root:root (usually 0:0)
    os.fchown(f.fileno(), 0, 0)
    new_stat = os.fstat(f.fileno())
    print(f"New owner: {new_stat.st_uid}, group: {new_stat.st_gid}")

# Clean up
os.remove(file_path)

此示例需要 root 权限才能将所有权更改为 root。它展示了如何将 os.fchown 与打开的文件描述符一起使用。

请注意,我们使用 os.fstat 来验证所有权更改。在整个操作过程中,文件描述符保持有效。

部分所有权更改

os.fchown 允许仅更改用户或仅更改组,方法是为您要保持不变的参数传递 -1。此示例演示了这两种情况。

partial_changes.py
import os
import pwd
import grp

file_path = "partial.txt"

# Create test file
with open(file_path, "w") as f:
    f.write("Partial change test")

# Get current user and group
current_uid = os.getuid()
current_gid = os.getgid()

with open(file_path, "r+") as f:
    # Change only the group (leave owner unchanged)
    os.fchown(f.fileno(), -1, current_gid)
    
    # Change only the owner (leave group unchanged)
    os.fchown(f.fileno(), current_uid, -1)

    # Verify changes
    stat_info = os.fstat(f.fileno())
    print(f"Owner: {stat_info.st_uid}, Group: {stat_info.st_gid}")

os.remove(file_path)

这显示了如何在保持另一个不变的情况下修改用户或组。值 -1 表示不应进行任何更改。

当您只需要修改所有权的一个方面时,这很有用。

错误处理

os.fchown 可能会引发各种异常。此示例演示了对权限问题和无效文件描述符的正确错误处理。

error_handling.py
import os
import sys

file_path = "error_test.txt"

try:
    # Create test file
    with open(file_path, "w") as f:
        f.write("Error handling test")

    # Try changing to root:root without privileges
    with open(file_path, "r+") as f:
        try:
            os.fchown(f.fileno(), 0, 0)
        except PermissionError:
            print("Permission denied - need root privileges")
        except OSError as e:
            print(f"OS error occurred: {e}")

    # Try with invalid file descriptor
    try:
        os.fchown(9999, 1000, 1000)
    except OSError as e:
        print(f"Invalid file descriptor: {e}")

finally:
    if os.path.exists(file_path):
        os.remove(file_path)

这显示了常见的错误情况:权限不足和无效的文件描述符。使用 os.fchown 时始终处理这些情况。

无论是否发生错误,finally 块都可确保清理。

使用用户/组名称

此示例显示了如何在用户/组名称和 ID 之间进行转换,从而使 os.fchown 在脚本中更易于使用。

name_resolution.py
import os
import pwd
import grp

file_path = "named_owner.txt"

def change_owner_by_name(fd, username, groupname):
    """Change owner using names instead of IDs"""
    uid = pwd.getpwnam(username).pw_uid
    gid = grp.getgrnam(groupname).gr_gid
    os.fchown(fd, uid, gid)

# Create test file
with open(file_path, "w") as f:
    f.write("Named owner test")

# Change ownership using names
with open(file_path, "r+") as f:
    # Change to current user and group
    username = pwd.getpwuid(os.getuid()).pw_name
    groupname = grp.getgrgid(os.getgid()).gr_name
    
    change_owner_by_name(f.fileno(), username, groupname)
    stat_info = os.fstat(f.fileno())
    print(f"Set owner to {username} ({stat_info.st_uid})")
    print(f"Set group to {groupname} ({stat_info.st_gid})")

os.remove(file_path)

change_owner_by_name 函数抽象了 ID 查找,使代码更具可读性。它使用 pwd 和 grp 模块进行名称解析。

当已知用户/组名称但未知 ID 时,此方法很有用。

保留所有权

此示例显示了如何临时更改所有权,然后恢复原始值,这在特权操作中很有用。

preserve_ownership.py
import os
import pwd

file_path = "preserve_test.txt"

# Create test file
with open(file_path, "w") as f:
    f.write("Ownership preservation test")

with open(file_path, "r+") as f:
    # Get original ownership
    stat_info = os.fstat(f.fileno())
    original_uid = stat_info.st_uid
    original_gid = stat_info.st_gid
    
    try:
        # Temporarily change to root (requires privileges)
        os.fchown(f.fileno(), 0, 0)
        print("Changed ownership to root")
        
        # Perform privileged operations here
        
    finally:
        # Always restore original ownership
        os.fchown(f.fileno(), original_uid, original_gid)
        print("Restored original ownership")

    # Verify restoration
    restored_stat = os.fstat(f.fileno())
    assert restored_stat.st_uid == original_uid
    assert restored_stat.st_gid == original_gid

os.remove(file_path)

try/finally 块确保即使操作失败,所有权也会恢复。这对于维护系统安全性和一致性至关重要。

断言验证所有权是否已正确恢复为原始值。

更改目录所有权

os.fchown 适用于任何文件描述符,包括目录。此示例显示了如何更改打开目录的所有权。

directory_ownership.py
import os

dir_path = "test_dir"

# Create test directory
os.makedirs(dir_path, exist_ok=True)

# Open directory and change ownership
dir_fd = os.open(dir_path, os.O_RDONLY)
try:
    # Get current stats
    stat_info = os.fstat(dir_fd)
    print(f"Current owner: {stat_info.st_uid}, group: {stat_info.st_gid}")
    
    # Change ownership (to current user/group)
    os.fchown(dir_fd, os.getuid(), os.getgid())
    
    # Verify change
    new_stat = os.fstat(dir_fd)
    print(f"New owner: {new_stat.st_uid}, group: {new_stat.st_gid}")
finally:
    os.close(dir_fd)

# Clean up
os.rmdir(dir_path)

这演示了将 os.fchown 与目录文件描述符一起使用。该过程与文件类似,但将 os.open 与 O_RDONLY 一起用于目录。

始终在 finally 块中关闭文件描述符,以防止资源泄漏。

安全注意事项

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已经撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程