您的位置:首页 > 产品设计 > UI/UE

《apue》读书笔记 第四章 文件和目录(2)

2015-11-29 21:29 260 查看

第四章 文件和目录

7.umask函数

当我们登录系统之后创建一个文件总是有一个默认权限的,那么这个权限是怎么来的呢?这就是umask干的事情。umask设置了用户创建文件的默认权限,它与chmod的效果刚好相反,umask设置的是权限“补码”,而chmod设置的是文件权限码。即,umask是从权限中“拿走”相应的位。

对于文件来说,权限的最大值是666,因为系统不允许你在创建一个文本文件时就赋予它执行权限,必须在创建后用chmod命令增加这一权限。目录则允许设置执行权限,这样针对目录来说,权限值最大可以到7。

例如,umask值002 所对应的文件和目录创建缺省权限分别为6 6 4和7 7 5。

由于umask指定的是需要忽略(屏蔽)的位,故称为屏蔽码。umask函数用来设置进程创建文件的屏蔽码(它也是少数几个没有错误返回的函数之一),声明如下:

#include <sys/stat.h>
mode_t umask(mode_t cmask);
返回:之前的文件创建模式屏蔽码。


参数cmask是9个权限常量的若干个按位“或”构成的。

例子:创建两个文件,第一个的umask为0,第二个的umask值禁止所有组和其他用户的访问权限。

#include "apue.h"
#include <fcntl.h>

#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)

int
main(void)
{
umask(0);
if (creat("foo", RWRWRW) < 0)
err_sys("creat error for foo");
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (creat("bar", RWRWRW) < 0)
err_sys("creat error for bar");
exit(0);
}


测试:

$ umask
002
$ ./umask
$ ls -l foo bar
-rw------- 1 jiange jiange 0 11月 29 20:38 bar
-rw-rw-rw- 1 jiange jiange 0 11月 29 20:38 foo
$ umask
002


从上面也可以看出,我们在进程中更改文件模式创建屏蔽字并不影响其父进程(bash)的屏蔽字。

常用的umask:

002:阻止其他用户写你的文件;

022:阻止同组成员和其他用户写你的文件;

027:阻止同组成员写你的文件,阻止其他用户读写或执行你的文件。

符号形式的文件模式创建屏蔽字:

$ umask -S


8.chomod 和 fchmod 函数

这两个函数使我们可以更改已有文件的访问权限:

#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
两者返回:如果成功,返回0,如果错误,返回-1


chmod对一个路径指定的文件进行操作,而fchmod对一个打开的文件描述符号filedes对应的文件进行操作。

为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程必须具有超级用户权限。

chmod函数的mode常量:



一般“ls -l”命令只显示文件内容改变的时间,而chmod修改的是i-node的最近更改时间。更改之后,按系统默认方式, ls -l列出的也只是最后修改文件内容的时间,而不是chmod的时间。

另外,chmod函数在下列条件下自动清除两个权限位:

a)如果我们试图设置普通文件的粘滞位 ( S_ISVTX ),而且又没有超级用户优先权,那么mode中的粘滞位自动被关闭(下一节说明粘住位)。也就是只有超级用户才能设置普通文件的粘住位。这样可以防止不怀好意的用户设置粘住位。

b)新创建文件的组ID可能不是调用进程所属的组。前面说过,新文件的组ID可能是父目录的组ID。特别地,如果新文件的组ID不等于进程的有效组ID或者进程添加组ID中的一个,以及进程没有超级用户特权,那么set-group-ID位自动被关闭。这就防止了用户创建一个并非该用户所属的组拥有的set-group-ID文件。

9.粘住位(sticky bit)

S_ISVTX bit,在尚未使用分页技术的unix系统时,如果可执行文件设置了这个位,那么,第一次运行可执行文件的时候,会在进程退出的时候将可执行文件的text段(包含机器指令的部分)拷贝一份保存到swap分区。因为swap分区连续存储,这样下次运行的时候会更快。由于现在有了虚拟内存和更快的文件系统,所以这个位就不那么需要了。

在当前的系统,对这个位进行了扩展,unix标准允许这个位设置目录,如果目录设置了这个位,那么目录中的文件可以在如下的情况下被重新命名或者删除:

用户具有目录的写权限,并且满足下面的条件之一:

a)用户拥有这个文件

b)用户拥有这个目录

c)用户是超级用户

/tmp 和 /var/spool/uucppublic就是一个典型的应用,任何用户可以在这个目录里面创建和删除文件,但是只能删除属于自己的文件。

10.chown,fchown和lchown函数

chown函数可用于更改文件的用户ID和组ID:

#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
三者返回:如果成功返回0,如果错误返回-1


chown和lchown修改路径指向文件的属主/组,而fchown修改被打开的文件描述符号代表的文件的属主/组。在符号连接情况下, lchown更改符号连接本身的所有者,而不是该符号连接所指向的文件。

如果参数是-1,则对应的ID不变。

11.文件长度

stat结构的st_size成员表示以字节为单位的文件长度,这个成员仅对普通文件,目录,链接文件有意义。对于普通文件,如果大小为0,则表示我们读取文件的时候将会获得一个文件结束标记;对于目录文件,文件大小一般是一个数的整数倍(例如16或者512),我们后面会讨论目录读取;对于符号链接,文件大小表示链接所指向的文件的文件名称的大小(如“usr/lib”大小为7)。

目前多数UNIX系统提供了st_blksize和st_blocks域。前者表示这个文件进行I/O的时候的期望块大小,后者表示实际分配的512字节块的数目。前面我们说过,读取一个文件,设置不同的缓存,消耗的时间有所不同。当我们设置其大小为st_blksize的时候,实际就是最优的大小,这时候读取文件消耗的时间最小。为提高效率,标准I/O库也尝试每次都用st_blksize字节的大小进行读写。另外,我们需要注意,不同版本的UNIX系统使用的st_blocks的单位可能不全是512字节块。

12.文件截断

有时我们需要在文件尾端处截去一些数据以缩短文件。将一个文件的长度截断为0是一个特例,open时候用O_TRUNC标志可以做到这一点。

为了截断文件可以调用函数truncate和ftruncate。声明如下:

#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
两者返回:如果成功返回0,如果错误返回-1


函数的作用是将指定的存在的文件的长度截短为length。如果该文件以前的长度大于length,则超过length以外的数据就不再能存取。如果以前的长度短于length,则其结果依赖系统实现。若某个实现的处理是扩展该文件,则在以前的文件尾端和新的文件尾端之间的数据将读作0 (也就是在文件中创建了空洞)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: