CHOWN - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-06-09
名称
chown,fchown,lchown,fchownat-更改文件的所有权
语法
#include <unistd.h> int chown(const char *pathname, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group); int lchown(const char *pathname, uid_t owner, gid_t group); #include <fcntl.h> /* Definition of AT_* constants */ #include <unistd.h> int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags);
glibc的功能测试宏要求(请参阅feature_test_macros(7)):
fchown(),lchown():
- / *自glibc 2.12起:* / _POSIX_C_SOURCE>= 200809L || _XOPEN_SOURCE>= 500 || / * Glibc版本
fchownat():
- Since glibc 2.10:
- _POSIX_C_SOURCE>= 200809L
- Before glibc 2.10:
- _ATFILE_SOURCE
说明
这些系统调用更改文件的所有者和组。 chown(),fchown()和lchown()系统调用的区别仅在于文件的指定方式:
- *
- chown()更改由路径名指定的文件的所有权,如果它是符号链接,则将取消引用。
- *
- fchown()更改由打开文件描述符fd引用的文件的所有权。
- *
- lchown()类似于chown(),但不取消引用符号链接。
只有特权进程(Linux:具有CAP_CHOWN功能的进程)才能更改文件的所有者。文件的所有者可以将文件的组更改为该所有者是其成员的任何组。特权进程(Linux:带有CAP_CHOWN)可以任意更改组。
如果将所有者或组指定为-1,则不会更改该ID。
当非特权用户更改了可执行文件的所有者或组时,将清除S_ISUID和S_ISGID模式位。 POSIX没有指定在root执行chown()时是否也应该发生这种情况。 Linux的行为取决于内核版本,并且从Linux 2.2.13开始,root被视为其他用户。如果是非组可执行文件(即未设置S_IXGRP位的文件),则S_ISGID位表示强制锁定,并且不会由chown()清除。
更改(由任何用户)可执行文件的所有者或组时,将清除文件的所有功能集。
fchownat()
除了此处描述的差异外,fchownat()系统调用的操作方式与chown()完全相同。
如果在路径名中给定的路径名是相对的,则它相对于文件描述符dirfd所引用的目录进行解释(而不是相对于调用进程的当前工作目录,如chown()对相对路径名所做的那样) 。
如果路径名是相对的并且dirfd是特殊值AT_FDCWD,则路径名将相对于调用进程的当前工作目录(如chown())进行解释。
如果路径名是绝对的,则dirfd被忽略。
flags参数是通过将0个或多个以下值进行或运算而创建的位掩码;
- AT_EMPTY_PATH(since Linux 2.6.39)
- 如果路径名是空字符串,请对dirfd引用的文件进行操作(该文件可能已使用open(2)O_PATH标志获得)。在这种情况下,dirfd可以引用任何类型的文件,而不仅仅是目录。如果dirfd为AT_FDCWD,则调用在当前工作目录上进行。该标志是特定于Linux的。定义_GNU_SOURCE以获得其定义。
- AT_SYMLINK_NOFOLLOW
- 如果路径名是符号链接,则不要取消引用它:而是像lchown()一样对链接本身进行操作。 (默认情况下,fchownat()取消引用符号链接,例如chown()。)
有关对fchownat()的需求的说明,请参见openat(2)。
返回值
成功时,返回零。如果出错,则返回-1,并正确设置errno。
错误说明
根据文件系统,可能会返回除以下所列错误以外的其他错误。
下面列出了chown()的更常见错误。
- EACCES
- 在路径前缀的组件上拒绝搜索许可。 (另请参见path_resolution(7)。)
- EFAULT
- 路径名指向您可访问的地址空间之外。
- ELOOP
- 解析路径名时遇到太多符号链接。
- ENAMETOOLONG
- 路径名太长。
- ENOENT
- 该文件不存在。
- ENOMEM
- 内核内存不足。
- ENOTDIR
- 路径前缀的组成部分不是目录。
- EPERM
- 呼叫过程没有更改所有者和/或组所需的权限(请参见上文)。
- EPERM
- 该文件被标记为不可变或仅附加。 (请参阅ioctl_iflags(2)。)
- EROFS
- 命名文件驻留在只读文件系统上。
下面列出了fchown()的一般错误:
- EBADF
- fd不是有效的打开文件描述符。
- EIO
- 修改索引节点时发生低级I / O错误。
- ENOENT
- 往上看。
- EPERM
- 往上看。
- EROFS
- 往上看。
对于chown()发生的相同错误也可能对于fchownat()发生。 fchownat()可能会发生以下其他错误:
- EBADF
- dirfd不是有效的文件描述符。
- EINVAL
- 标志中指定的标志无效。
- ENOTDIR
- pathname是相对的,dirfd是引用目录以外的文件的文件描述符。
版本
fchownat()在内核2.6.16中添加到Linux;库支持已添加到版本2.4中的glibc。
遵循规范
chown(),fchown(),lchown():4.4BSD,SVr4,POSIX.1-2001,POSIX.1-2008。
4.4BSD版本只能由超级用户使用(也就是说,普通用户不能放弃文件)。
fchownat():POSIX.1-2008。
备注
Ownership of new files
创建新文件时(例如,通过open(2)或mkdir(2)),其所有者与创建过程的文件系统用户ID相同。文件的组取决于一系列因素,包括文件系统的类型,用于挂载文件系统的选项以及在父目录上是否启用了set-group-ID模式位。如果文件系统支持-o grpid(或同义-o bsdgroups)和-o nogrpid(或同义-o sysvgroups)mount(8)选项,则规则如下:
- *
- 如果使用-ogrpid挂载文件系统,则使新文件的组与父目录的组相同。
- *
- 如果使用-onogrpid挂载文件系统并且在父目录上禁用了set-group-ID位,则将新文件的组与进程的文件系统GID相同。
- *
- 如果使用-onogrpid挂载文件系统并且在父目录上启用了set-group-ID位,则使新文件的组与父目录的组相同。
从Linux 4.12开始,ext2,ext3,ext4和XFS支持-ogrpid和-onogrpid挂载选项。不支持这些挂载选项的文件系统遵循-onogrpid规则。
Glibc notes
在无法使用fchownat()的旧内核上,glibc包装器功能会退回到使用chown()和lchown()。如果路径名是相对路径名,则glibc将基于/ proc / self / fd中与dirfd参数相对应的符号链接构造路径名。
NFS
在启用了UID映射的NFS文件系统上,故意违反了chown()语义。此外,访问chown()可能会导致对已打开文件的立即访问吊销,从而违反了访问文件内容的所有系统调用的语义。客户端缓存可能会导致在更改所有权以允许用户访问的时间与用户实际上可以在其他客户端上访问文件的时间之间产生延迟。
Historical details
原始的Linux chown(),fchown()和lchown()系统调用仅支持16位用户和组ID。随后,Linux 2.4添加了支持32位ID的chown32(),fchown32()和lchown32()。 glibc chown(),fchown()和lchown()包装函数透明地处理了内核版本之间的差异。
在2.1.81之前的Linux版本中(与2.1.46不同),chown()不遵循符号链接。从Linux 2.1.81开始,chown()确实遵循符号链接,并且有一个新的系统调用lchown()不遵循符号链接。从Linux 2.1.86开始,此新调用(与旧的chown()具有相同的语义)具有相同的syscall编号,而chown()得到了新引入的编号。
示例
下面的程序将在其第二个命令行参数中命名的文件的所有权更改为在其第一个命令行参数中指定的值。可以将新所有者指定为数字用户ID或用户名(通过使用getpwnam(3)在系统密码文件中执行查找将转换为用户ID)。
Program source
#include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { uid_t uid; struct passwd *pwd; char *endptr; if (argc != 3 || argv[1][0] == aq##代码##aq) { fprintf(stderr, "%s <owner> <file>\n", argv[0]); exit(EXIT_FAILURE); } uid = strtol(argv[1], &endptr, 10); /* Allow a numeric string */ if (*endptr != aq##代码##aq) { /* Was not pure numeric string */ pwd = getpwnam(argv[1]); /* Try getting UID for username */ if (pwd == NULL) { perror("getpwnam"); exit(EXIT_FAILURE); } uid = pwd->pw_uid; } if (chown(argv[2], uid, -1) == -1) { perror("chown"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。