这两个函数使我们可以更改现有文件的访问权限。
#include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fildes, mode_t mode); // 两个函数的返回值:若成功则返回0,若出错则返回-1
chmod函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。
为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程必须具有超级用户权限。
chmod函数的mode常量如下表:
mode | 说明 | mode | 说明 | mode | 说明 |
S_ISUID S_ISGID S_ISVTX |
执行时设置用户ID 执行时设置组ID 保存正文(粘住位) |
S_IRWXU S_IRUSR S_IWUSR S_IXUSR |
用户(所有者)读、写和执行 用户(所有者)读 用户(所有者)写 用户(所有者)执行 |
S_IRWXO S_IROTH S_IWOTH S_IXOTH |
其他读、写和执行 其他读 其他写 其他执行 |
《UNIX环境高级编程》P82:程序清单4-4 chmod函数实例(有改动)
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/stat.h> int main(int argc, char *argv[]) { struct stat statbuf; // 获取文件的信息结构 if (stat("foo", &statbuf) < 0) fprintf(stderr, "stat error for foo: %s\n", strerror(errno)); // 关闭组执行位,打开设置组ID位 if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) fprintf(stderr, "chmod error for foo: %s\n", strerror(errno)); // 用户读、写;组读;其他读 if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) fprintf(stderr, "chmod error for bar: %s\n", strerror(errno)); exit(0); }
程序执行前的文件权限状态:
$ ls -l foo bar -rw------- 1 user user 0 6月 22 16:38 bar -rw-rw-rw- 1 user user 0 6月 22 16:38 foo
程序运行后:
ls -l foo bar -rw-r--r-- 1 user user 0 6月 22 16:38 bar -rw-rwSrw- 1 user user 0 6月 22 16:38 foo
ls命令将组执行权限表示为S,它表示设置组ID位已经设置,同时,组执行位则未设置。ls命令列出的时间和日期并没有改变,chmod函数更新的只是i节点最近一个被更改的时间。按系统默认方式,ls -l列出的是最后修改文件内容的时间。
在FreeBSD、Mac OS X 和 Solaris 上,只有超级用户才能对普通文件设置粘住位。Linux对设置粘住位并无此种限制,其原因是,粘住位对Linux上的普通文件并无意义。
新创建文件的组ID可能不是调用进程所属的组,如果新文件的组ID不等于进程的有效ID或者进程附加组ID中的一个,以及进程没有超级用户权限,那么设置组ID位将自动关闭。这就防止了用户创建一个设置组ID文件,而该文件是并非该用户所属的组拥有。
如果没有超级用户特权的进程写一个文件,则设置用户ID位和设置组ID位将自动被清除。
如果对一个目录设置了粘住位,则只有对该目录具有写权限的用户在满足下列条件之一的情况下,才能删除或更名该目录下的文件:
(1) 拥有此文件;(2) 拥有此目录;(3) 是超级用户。
目录/tmp设置了黏住位,任何用户都可在这个目录中创建文件,任一用户对这个目录都有读、写和执行的权限,但是用户不能删除或更名属于其他人的文件。
$ ls -ld /tmp/ drwxrwxrwt 7 root root 4096 6月 23 18:29 /tmp/
其中的t表示设置了粘住位。
下面几个chown函数可以用户更改文件的用户ID和组ID。
#include <unistd.h> int chown(const char *path, uid_t owner, gid_t group); int fchown(int fildes, uid_t owner, gid_t group); int lchown(const char *path, uid_t owner, gid_t group); // 三个函数的返回值:若成功则返回0,若出错则返回-1
除了所引用的文件是符号链接以外,这三个函数的操作相似。在符号链接的情况下,lchown更改符号链接本身的所有者,而不是该符号链接所指向的文件。
如若两个参数owner或group中的任意一个是-1,则对应的ID不变。
基于BSD的系统一直规定只有超级用户才能更改一个文件的所有者。这要做的原因是防止用户改变其文件的所有者从而摆脱磁盘空间限额对他们的限制。
若_POSIX_CHOWN_RESTRICTED对指定的文件起作用,则
(1) 只有超级用户进程能更改该文件的用户ID。
(2) 若满足下列条件,一个非超级用户进程就可以更改该文件的组ID:
(a) 进程拥有此文件(其有效用户ID等于该文件的用户ID)。
(b) 参数owner等于-1或文件的用户ID,并且参数group等于进程的有效组ID或进程的附加组ID之一。
这意味着,当_POSIX_CHOWN_RESTRICTED起作用时,你不能更改其他用户文件的用户ID。你可以更改你所拥有的文件的组ID,但只能更改到你所属的组。
如果这些函数由非超级用户进程调用,则在成功返回时,该文件的设置用户ID位和设置组ID位都会被清除。