闇の光

读书笔记 经验感受

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Initial Permissions

当你使用O_CREAT标志和open来创建文件时,必须使用open调用的三种模式参数格式。第三个参数mode是几个标志按位OR后得到的,这些标志在头文件sys/stat.h.中定义,它们是:

S_IRUSR读权限,文件属主
S_IWUSR写权限,文件属主
S_IXUSR执行权限,文件属主
S_IRGRP读权限,文件所属组
S_IWGRP写权限,文件所属组
S_IXGRP执行权限,文件所属组
S_IROTH读权限,其他用户
S_IWORH写权限,其他用户
S_IXORH执行权限,其他用户
示例
open ("myfile", O_CREAT, S_IRUSR|S_IXOTH);

创建了一个名叫myfile的文件,同时对文件文件属主拥有读的权限,其他用户则是执行的权限,并且只有这些权限而已。

$ ls -ls myfile
0 -r-------x    1  neil     software         0 Sep 22 08:11 myfile*

有两个因素在影响着文件权限。首先,只有在文件在创建时才能指定文件访问权限。其次,用户掩码(由shell命令umask指定)会影响被创建文件的权限。open调用里给出的模式值会与当时的用户掩码的反值做AND操作。举例说明,假设用户掩码被设置为001,并且指定了S_IXOTH模式标志,那么其他用户对创建的文件不会拥有执行权限,因为用户掩码中指定了不允许向其他用户提供执行权限。因此,open和creat调用中的标志实际上是设置文件访问权限的请求,所请求的权限是否会被设置取决于当时umask的值。

umask

umask是一个系统变量,它的作用是:当文件被创建后为文件访问权限设置一个掩码。当我们登录系统之后创建一个文件会有一个默认权限,这个权限是如何来的呢?这就是umask造成的结果。我们可以通过执行umask命令可以对这个变量进行修改,为其提供一个新值。umask设置了用户创建文件的默认权限,它与chmod的效果刚好相反,umask设置的是权限“补码”,而chmod设置的是文件权限码。一般在/etc/profile、$ [HOME]/.bash_profile或$[HOME]/.profile中设置umask值。

umask命令允许你设定文件创建时的缺省模式,对应每一类用户(文件属主、同组用户、其他用户)存在一个相应的umask值中的数字。对于文件来说,这一数字的最大值分别是6。系统不允许你在创建一个文本文件时就赋予它执行权限,必须在创建后用chmod命令增加这一权限。目录则允许设置执行权限,这样针对目录来说,umask中各个数字最大可以到7。

该命令的一般形式为:

umask nnn

其中nnn为umask置000 - 777。

我们只要记住u m a s k是从权限中“拿走”相应的位即可。下表是umask值与权限的对照表:

umask文件目录
067
166
245
344
423
522
601
700

如:umask值为022,则默认目录权限为755,默认文件权限为644。

当我们通过open或creat调用创建文件时,mode参数将与umask进行比较。在mode参数中被设置的位如果在umask中也被设置了,就会从文件的访问权限中删除。因此,最终用户可以设置自己的环境,比如“不准创建允许其他用户有写权限的文件,即使创建该文件的程序要求该权限也不行。”这样做并不能阻止一个程序或用户在今后使用chmod命令(或者在程序中使用chmod系统调用)来添加其他用户的写权限,但它确实能够帮助用户,使他们不必对每个新文件都去检查和设置其访问权限。

close

我们使用close来终止文件描述符fildes同它所对应的文件之间的关联,这样文件描述符就被释放,从而可以被重新使用。close执行成功返回0,出错就返回-1。

close系统调用的语法结构:

#include <unistd.h>
int close(int fildes);

注意:查看close返回的结果十分重要。有些文件系统,尤其是网络文件系统,可能不会在关闭文件之前报告文件写操作中出现的错误,因为在执行写操作时,数据可能并未确认被写入。

ioctl

ioctl有点像个装东西的袋子。它提供了一个接口,用于控制设备及其文件描述符和配置底层服务。终端、文件描述符、sockets、甚至磁带设备都可以为它们定义ioctl调用,具体细节请参考特定设备的使用手册。POSIX只为流(stream)指定了ioctl,在此不做相关讨论。

ioctl系统调用的语法结构:

#include <unistd.h>
int ioctl(int fildes, int cmd, ...);

ioctl对描述符fildes指定的对象执行cmd参数中给出的操作。根据特定设备所支持函数的不同,还有可能会有一个可选的第三参数。

举例说明,下面所示的ioctl调用在Linux上的功能是打开键盘上LED灯:

ioctl(tty_fd, KDSETLED, LED_NUM|LED_CAP|LED_SCR);

实例:

(一个文件复制程序)

我们已经了解了open、read以及write等系统调用的相关内容,下面让我们来写一个简单的程序copy_system.c,逐个字符地复制一个文件到另外一个文件中。

为简单起见,我们假定输入文件已经存在,输出文件不存在,且用户所有的读写操作都成功。当然,在现实程序中,我们要对此进行确认其有效性。

1.首先,我们创建测试的输入文件file.in。

2.接下来,书写程序copy_system.c的代码:

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
    char c;
    int in, out;

    in = open("file.in", O_RDONLY);
    out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
    while(read(in, &c, 1) == 1);
       write(out, &c, 1);

    exit(0);
}
注意:#include<unistd.h>必须出现在第一行,这是它根据POSIX规范所定义的标志可能会影响到其他的include文件。

3.像下面所给出的那样运行程序:

$ TIMEFORMAT="" time ./copy_system
4.67user  146.90system  2:32.57elapsed  99%CPU
...
$ ls -ls file.in file.out
1029 -rw-r---r-    1 neil   users   1048576 Sep 17 10:46 file.in
1029 -rw-------    1 neil   users   1048576 Sep 17 10:46 file.out

工作原理:

我们在此使用time工具对该程序运行的时间进行了测算。在Linux上使用TIMEFORMAT变量来重置默认的POSIX时间输出格式,POSIX时间格式不包括CPU使用率。我们可以看到在这台相当老的系统上,1MB的输入文件file.in被成功拷贝到file.out,file.out以只允许属主进行读写的权限被创建出来。但这次拷贝花费了大约两分半钟,并且几乎消耗了所有的CPU时间。之所以这么慢,是因为它必须完成超过两百万次的系统调用。


(另一个文件复制程序)

我们通过拷贝大一些的数据块来改善效率较低的问题,请看下面这个改进后的程序copy_block.c,它每次拷贝长度为IK的数据块,用的还是系统调用:

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
    char block[1024];
    int in, out;
    int nread;

    in = open("file.in", O_RDONLY);
    out = open("file.out", O_WRDONLY|O_CREAT, S_IRUSR|S_IWUSR);
    while((nread = read(in, block, sizeof(block))) > 0)
       write(out, block, nread);

    exit(0);
}

现在运行程序:

$ TIMEFORMAT="" time ./copy_system
0.00user  0.02system  0:00.04elapsed  78%CPU
...

工作原理:

改进后的程序只花费了0.01秒的时间,因为它只需做大约2000次系统调用。当然,这些时间与系统本身的性能有很大的关系,但它们确实显示了系统调用需要巨大的开支,因此值得对其使用进行优化。

posted on 2008-04-08 11:34  taizi  阅读(497)  评论(0编辑  收藏  举报