名字
access - 对一个文件检测当前真实用户权限
概要
#include <unistd.h>
int access(const char * pathname , int mode );
描述
access () 检测调用进程是否可以访问 pathname 指向的文件。如果 pathname 是一个符号链接,则会解引用。
mode 用来指定需要执行检测的访问模式,或者是 F_OK 。指定的模式可以是 F_OK 、R_OK 、W_OK 、X_OK 执行位或运算的结果。F_OK 测试文件是否存在。R_OK 、W_OK 、X_OK 测试文件存在并且保证可读、可写、可执行。
与真实地去执行一个操作(如 open (2))不一样,本系统调用检测时使用调用进程的 真实 UID 和 GID,而不是有效 IDs。这使得“设置用户 ID”程序可以简单地测试调用用户的权限。
如果调用进程具有特权(如它的真实 UID 是 0),那么对于普通文件执行 X_OK 测试时,只要这个文件的执行权限在文件所主、组或其它用户里被设置,测试总是返回成功。
返回值
成功时(所有要求的权限都得到保证),0 被返回。错误时(至少有一个在 mode 指定的权限被禁止或其它什么错误),-1 被返回,同时 errno 被设置为合适的值。
错误
access () 可能失败于:
-
EACCES
- 指定文件要求访问的权限被禁止,或 pathname 中的某个路径片段的查找权限被禁止。(参看 path_resolution (7)。) ELOOP
- 在访问 pathname 时经历了太多的符号链接。 ENAMETOOLONG
- pathname 太长了。 ENOENT
- pathname 的目录片段不存在或是一个悬空符号链接。 ENOTDIR
- 在 pathname 里的一个片段作为一个目录使用,但是事实上它不是一个目录。 EROFS
- 对一个只读文件系统要求写权限。
access () 也可能失败于:
-
EFAULT
- pathname 指向的地址不在你的可以访问的地址空间。 EINVAL
- mode 指定的不正确。 EIO
- 发生 I/O 错误。 ENOMEM
- 内核可用内存不足。 ETXTBSY
- 对一个正在执行的可执行文件要求写权限。
遵循于
SVr4, 4.3BSD, POSIX.1-2001。
注意
警告 :如果在 open (2) 打开一个之前使用 access () 来认证一个用户将产生一个安全漏洞,因为有人可能会利用检测与打开之间的短暂时间间隔来操作它。出于这个原因,这个系统调用应该避免使用 。(在刚才描述示例中,一个更安全的方式应该是临时把有效用户ID转换到真实用户ID,然后调用 open (2)。)
access () 总是解引用符号链接。如果你需要检测符号链接本身的权限,使用带标志 AT_SYMLINK_NOFOLLOW 的 faccessat (2)。
在访问模式 mode 任何一个权限的禁止都会让 access () 返回错误,此时可能在 mode 里的其它权限是允许的。
如果调用进程具有特权(如是超级用户),试图测试 X_OK 时,即使指定文件执行位没有设置,POSIX.1-2001 也允许实现返回成功。Linux 没有这么做。
一个文件只有在它的路径名 pathname 里的每个前缀目录都是可查找(如执行)的时候才是可访问。如果有任何一个目录是不可查找的,access () 的调用会失败,此时不涉及那个文件自身。
只有访问位被检测,不包括文件类型或内容。所以如果一个目录测试为可写时,这只是表明可以在这个目录里创建文件,而不说这个目录可以像文件一样可以写入内容。类似的,对于一个 DOS 文件可能返回为“可执行”,但是 execve (2) 调用仍然会失败。
对于 NFS 文件系统来说,当 UID 映射启用时,access () 可能工作不正确,因为 UID 映射是针对服务器进程的,这对客户端进程不可见,而做测试的客户端进程。
错误
在内核 2.4 (和更早) 当超级用户测试 X_OK 时存在一些奇怪的事。如果一个非目录文件的所有类型的自毁长城权限都被禁止了,access () 在 mode 只设置为 X_OK 时返回 -1,而当 R_OK 或 W_OK 也被设置在 mode 里时,access () 会返回 0。早期的 2.6 内核(包括2.6.3和更新)也有与 2.4 内核有同样的行为。
在 2.6.20 之前内核,如果 mount (2) 低级的文件系统时使用了MS_NOEXEC 标记, access () 会忽略这个标记位。自从 2.6.20 内核,access () 优先使用这个标记。