IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> File I/O (unbufferd) -APUE第三版 -> 正文阅读

[系统运维]File I/O (unbufferd) -APUE第三版

3.1 introduction ?介绍

先介绍unix 系统的?五个I/O 函数- open?, read, write, lseek, close . 然后?检查?不同?buffer sizes 对??read, write 函数的?效率的影响。

在这章中?函数?相比standard I/O (5章)的是??unbuffered I/O, ?术语?unbuffered 指的?是?每个?read, write 调用内核的系统调用。这些?unbuffered I/O function 不是?ISO?C 一部分,但是是?是POSIX.1 ?和?single Unix Specification 的一部分。

多进程之家?共享资源,这里的?原子操作?概念?变的很重要。从这个角度?检查下?I/O 函数。

最后?介绍下?dup, fcntl, sync, fsync, ioctl 函数。

3.2 File?Descriptors 文件描述符

对于内核,所有打开的文件?都被?file?descriptors 来引用,file?descriptor 是?非负整数。

当我们打开(open)一个已存在的文件或?创建(create)一个新file, 内核会返回一个file?descriptor 给?调用进程。

?方便起见, unix 系统?shell 把?file?descriptor ?0 和?进程的标准输入?关联起来, file?descriptor 1 和?标准输出?关联起来,file descriptor 2 ?和?进程的标准错误关联起来。这种方便的做法,通常?是?shell 和?大多数applications 所采用的。 注意,它不是unix?内核的功能。然而,许多应用也可能不遵守?此约定。

尽管?POSIX.1 对0,1,2 的含义是标准化的,应该使用?symbolic constants ?STDIN_FILENO, STDOUT_FILENO, 和?STDERR_FILENO?来提高可读性。这几个常量?被定义在<unistd.h> 中

file?descriptors?的范围?是?从0 到?OPEN_MAX-1 .

对于FreeBSD8.0 ,Linux 3.2.0, Mac OS X 10.6.8 和?Solaris?10, 这个限制是?基本上是无限的(essentially infinite), 取决于?系统的内存量, integer 的size?, 由管理员设置的硬件和软件的?限制。

3.3 open??openat?函数

#include <fcntl.h>

int open(const char *path, int oflag, ... /* mode_t mode */ );

int openat(int fd, const char *path, int oflag, ... /* mode_t mode */ );

????????????????????????????????????????????????????????Both return: file descriptor if OK, -1 on error

... ??是ISO?C 的方式?用以?指定?剩余的?可能的?多个参数。

/* mode_t mode*/最后参数, 来指定模式。

path 是?文件名

flag??这个使用?一个或多个?如下的常量?的?OR?来定义, 这些常量被定义在<fcntl.h> 头中。

O_RDONLY ??打开只为了?读

O_WRONLY ??打开?只为了?写

O_RDWR ????打开?为?读?和?写

O_EXEC ?????打开?只为了??execute

O_SEARCH ???打开?只为了?search??( 应用到?目录)

?????????????注意?在本书上的,还没有任何版本的操作系统?支持这个选项。

以上的?五个?必须?指定一个, 下面的选项?是可选的。

O_APPEND ??对于每个write?都追加到文件的末尾。

O_CLOEXEC ???3.14部分会讨论

O_CREAT ????如果文件不存在就创建, open需要第三个参数, openat 需要第四个参数。这个参数指?mode

O_DIRECTORY ??如果?path?指向的不是目录,就会产生一个error

O_EXCL ???如果O_CREAT 也被指定,且?file 已经存在,就会产生一个?error. ?这用来测试?是否文件已经存在?并且?当不存在时创建一个文件,这个过程是个原子操作。 在3.11 部分会描述更多的原子操作。

O_NOCTTY ??如果path?指向?一个?terminal device, ?不要分配这个?device?做为进程的?controlling terminal. ??9.6部分会讨论?controlling terminals

O_NOFOLLOW ??如果path?指向一个?symbolic link 就会产生error。 4.17部分会讨论symbolic link

O_NONBLOCK ???如果path 指向?FIFO, 块特殊文件(block special file), 字符特殊文件(character special file), 这个选项设置??nonblocking mode , ?对打开文件及?接下来的操作I/O 都是。 ?在14.2 ?部分会描述这种模式。

O_SYNC ?使?每个write??操作?都wait?到?物理I/O 完成, 这其中包括必要的?更新文件的属性。 3.14部分?会使用这个选项。

O_TRUNC ???如果文件存在?并且?它被成功打开?并且?是?write-only 或?read-write , 则truncate 文件的长度为?0

O_TTY_INIT ??在18章会讨论?terminal I/O

接下来的?两个flags 是?可选的。 他们是?synchronized input 和output 的?一部分,是POSIX.1的规范

O_DSYNC ??使?write?操作?都wait?到?物理?I/O 完成, 但不会等文件属性被更新。

? ? O_DSYNC和O_SYNC?flags是相似的,但是有微妙(subtly)的不同。

? ? O_DSYNC flag?影响?文件的属性?仅当?他们需要更新属性以?反映文件中数据的改变(例如: update文件的size?以反映?有更多的数据). 对带有O_SYNC flag,数据和属性总是被同步地更新。 当覆盖了?文件的?已存在的一部分数据,如果是O_DSYNC flag ,file?times 将不会被同步地更新。对比地如果是?O_SYNC flag 每个write?操作都会?在write return之前?更新文件的times,且?不管?我们?是?覆盖了文件的一部分字节还是?追加到文件的末尾。

O_RSYNC ??: 使每个读操作?等待?直到?任何的?对文件的相同部分的写?的?pending??完成了

Linux3.2.0 支持O_DSYNC flag?,但把它当O_SYNC 来对待。

fd 参数?区分了?openat ?和?open?函数。这有3个可能:

  1. path??参数?是?绝对路径, 这种情况?fd 参数?被忽略, openat的?函数行为就像?open 函数。
  2. ?path?参数?指定了?相对路径名,并且?fd参数?是一个文件描述符它指定了??文件系统中pathname 参考的starting?location . ?fd??可以通过打开?目录(pathname 的参考目录)来获取。
  3. path??参数指定了?相对路径名(relative?pathname),并且?fd参数?是?特殊的?AT_FDCWD。这种情况?pathname 的?参考目录?是指定的当前的工作目录,并且openat 函数的行为就像open?那样。

openat??解决了2个问题。首先?它给?线程?一种?可以使用相对路径来打开文件(而不是当前工作目录), 在11章,我们看到??在相同进程的所有线程?共享当前的工作目录, 使多个线程?在相同时刻,工作在不同的目录是?困难的。 第二,它提供了一种避免?TOCTTOU?errors?(time-of-check-to-time-of-use)的方式.

一个程序是脆弱的,如果它?发起了?两个?基础的file 函数调用,在这种情况, 第二个调用?依赖与?第一个调用的结果。 由于两个调用?不是原子的, ?file?可能在?两次调用之间的间隙时刻?被?改变, 因此?第一次的不合法的调用结果?,就会导致?问题?error. ??文件系统的?TOCTTOU errors ,通常。。。。。

Filename 和?Pathname Truncation

NAME_MAX : 如果文件名?超过了?NAME_MAX 会出现什么。

?对于POSIX.1 常量?_POSIX_NO_TRUNC 决定了?当?filename 太长是被?truncated?还是?返回一个error。 我们可以使用?fpathconf 或?pathconf 来查询一个目录,去看看哪种行为是被支持。

Linux?总是返回error.

If ?_POSIX_NO_TRUNC 是有效的, errno 被设置为ENAMETOOLONG, 并且?error?status 被返回。

大多数file?systems 支持?最大?255个字符。

3.4 creat?函数

#include <fcntl.h>

int creat(const char *path, mode_t mode);

????????????????????????????????Returns: ?file descriptor opened for write-only if OK, -1 on error

注意这个函数?等效于:

open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);

create?的一个缺点(deficiency) 是?,它打开文件?仅是为了?writing。 ?在open的新版本提供之前,如果我们想?创建一个临时的文件并且?去写,并且稍后读,我们就不得不调用?create, close, 然后打开?open?。 一个更好的方式是?使用?open?函数?如下:

open(path, O_RDWR | O_CREAT | O_TRUNC, mode);

3.5 close?函数

#include <unistd.h>

int close(int fd);

????????????????????????????????????????????????????????????????????????Returns: 0 if OK, ?1 on error

关闭?文件?也会引起?释放?进程施加给文件的?任何的?record?locks 。我们将在14.3 部分讨论这一点。

当一个进程终止, 所有它打开的文件?都会被?内核?自动地?closed?。 许多程序利用这一个优点,不去调用close?关闭文件。

3.6 lseek?函数

字符“l” 意味着?long?integer.

每个打开的文件?都?关联着?一个?“current file offset”, ?正常的是?一个非负数。 Read和?write?操作通常开始?在?“current?file offset”, 并且?通过read或written一些字节会引起?这个offset的?增大。 默认地?,这个offset 当file?被打开时, 被初始化为?0, 除非?指定了 O_APPEND 选项。

一个打开的文件的offset 可以被?lseek?来设置

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

????????????????????????????????????????????????Returns: new file offset if OK, ?1 on error

参数offset 的解释取决于?whence 参数:

?如果whence 是?SEEK_SET, 则?文件的offset 被设置到?从文件开始偏移?参数offset bytes 的位置。

?如果whence 是?SEEK_CUR ,则?文件的offset 被设置为?文件的current value ?加上?参数offset。 注意参数offset 可以是正数,也可以是负数。

??如果whence 被SEEK_END, 文件的offset??被设置为?file的size??加上?参数offset。 参数offset 可以是?正数?或?负数。

如lseek?调用成功就会?返回新的文件offset ,我们可以?设置?参数offset=0 , 且SEEK_CUR 来检测?当前offset。

off_t currpos;

currpos = lseek(fd, 0, SEEK_CUR);

这个技术?也被用于?检测?一个文件?是否?是?可以被seeking 的。如果file descriptor 指向pipe, FIFO,或socket?, 则?lseek就会?设置?errno 为?ESPIPE, 并且?return?-1。

例子3.1 ?测试?他的标准输入?是否可以被?seeking

1.#include?"apue.h"??
2.??
3.int??
4.main(void)??
5.{??
6.????if?(lseek(STDIN_FILENO,?0,?SEEK_CUR)?==?-1)??
7.????????printf("cannot?seek\n");??
8.????else??
9.????????printf("seek?OK\n");??
10.????exit(0);??
11.}??
12.??
13./**?
14.?[xingqiji@work78?fileio]$?./seek?
15.cannot?seek?
16.[xingqiji@work78?fileio]$?./seek??<?/etc/passwd?
17.seek?OK?
18.?*??
19.?*/??

正常地?一个文件的当前offset 必须是?一个?非负integer, ?然而特定的设备?可能允许?负数offsets。 但对于常规文件,offset 必须是?非负数。因为?负数的offsets 是可能的,我们应该小心??地处理?lseek return?的value?: 我们应该把?return?value ?和?等于或不等于-1 来比较,而不是去测量它是否是?小于?0。

文件的offset 可以?大于?文件当前的?size, 这种情况??下一步的write to?file将会?扩展file. 这被。这被?称作?在文件里创建了一个?hole.

在文件中的?hole??,是否存回到disk??,取决于?file?system的实现。

例子3.2 创建一个文件?,它里边有hole

fileio/hole.c

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

char	buf1[] = "abcdefghij";
char	buf2[] = "ABCDEFGHIJ";

int
main(void)
{
	int		fd;

	if ((fd = creat("file.hole", FILE_MODE)) < 0)
		err_sys("creat error");

	if (write(fd, buf1, 10) != 10)
		err_sys("buf1 write error");
	/* offset now = 10 */

	if (lseek(fd, 16384, SEEK_SET) == -1)
		err_sys("lseek error");
	/* offset now = 16384 */

	if (write(fd, buf2, 10) != 10)
		err_sys("buf2 write error");
	/* offset now = 16394 */

	exit(0);
}

/**
 * 
 [xingqiji@work78 fileio]$ ls -l file.hole 
-rw-r--r-- 1 xingqiji xingqiji 16394 12月 24 17:49 file.hole
[xingqiji@work78 fileio]$ od -c file.hole
0000000   a   b   c   d   e   f   g   h   i   j  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0040000   A   B   C   D   E   F   G   H   I   J
0040012
 * 
 [xingqiji@work78 fileio]$ ls -ls file.hole file.nohole
ls: 无法访问file.nohole: 没有那个文件或目录
8 -rw-r--r-- 1 xingqiji xingqiji 16394 12月 24 17:49 file.hole
 */

为了证明在这个文件中确实有一个?hole, 让我们比较这个文件?同?我们刚刚用相同size创建的文件。

ls?-ls file.hole ?file.nohole ?

说明分析: 尽管两个文件有相同的size,没有空洞的文件消费?20 disk blocks, 有空洞的文件仅仅消费?8 disk blocks.

Operating system

CPU architecture

_FILE_OFFSET_BITS value

Undefined

32

64

FreeBSD 8.0

x86 32-bit

8

8

8

Linux 3.2.0

x86 64-bit

8

8

8

Mac OS X 10.6.8

x86 64-bit

8

8

8

Solaris 10

SPARC 64-bit

8

4

8

Figure 3.4 ???Size in bytes of off_t for different platforms

注意,尽管你启动了64-bits?file offset. 你是否能创建的文件大于?2 GB (231?- 1 bytes) 取决于?the underlying file system type

3.7 read?函数

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

????????????????????????????????Returns: number of bytes read, 0 if end of file, -1 on error

这里有几种情况,read?到真实数据的数量?小于要求的数量:

  1. 从?常规文件(regular file)中读, 例如?到文件末尾还有30个字节, 我们尝试读取100个字节,这时read就返回30, 下次再调用read, 它将返回0 (到文件末尾了)
  2. 从?terminal device 中读, 通常地, 一次读取一行(18章,可以看到如何改变这种默认行为)
  3. ?从?network 中读
  4. ?从?pipe??或?FIFO 中读
  5. 从?record-oriented device 中读
  6. ?被信号中断了(interrupted)

3.8 write 函数

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t nbytes);

????????????????????????????????Returns: number of bytes written if OK, -1 on error

通常引起错误的是: 磁盘满了,或者达到了文件的大小限制。

3.9 I/O?Efficiency

3.5 程序: copy 一个文件,仅仅就是使用?read, write 函数。

#include "apue.h"  
  
#define BUFFSIZE    4096  
  
int  
main(void)  
{  
    int     n;  
    char    buf[BUFFSIZE];  
  
    while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)  
        if (write(STDOUT_FILENO, buf, n) != n)  
            err_sys("write error");  
  
    if (n < 0)  
        err_sys("read error");  
  
    exit(0);  
}  
  
/** 
 *  
[xingqiji@work78 fileio]$ ./mycat 
ni hao 
ni hao 
hello world 
hello world 
^C 
[xingqiji@work78 fileio]$  
 *  
 */  

Figure 3.6 Timing results for reading with different buffer sizes on Linux

在3.14部分,我们展示了?同步写(synchronous writes); 在5.8部分,我们比较?这些?unbuffered I/O 同?标准I/O 库(standard I/O library)

注意,当去测量??程序(read?and?write files)的性能时。操作系统将尝试去?缓存文件?incore。 所以?重复测量, 很可能结果比第一次的结果?好。 incore ?:含义是??in main memory。

3.6的测试报告,每次run都使用了不同的?file?copy,目的是?当前run 不会找到?先前run 的缓存。

3.10 File?Sharing 文件共享

unix 系统支持?在多个进程间共享?打开的文件。在描述dup之前需要先描述?sharing.

先来看看内核?关于I/O 用到的数据结构:

注意,如下的描述是?概念性的, 它可能,也可能不?匹配一个特定的实现。

内核使用3个数据结构?来代表?一个?打开的文件。

Figure 3.7 Kernel data structures for open files

注意Linux 没有?v-node, 它使用?generic ?i-node , 尽管实现是不同的v-node ?generic i-node 概念上是相同的

如果两个?独立的(independent)进程s?有相同的?file?open, 我们能看到?3.8 的安排图

??说明:每个进程都有一个它自己的?file?table entry 的其中一个原因是: 使每个进程都有它自己的?current file offset。

看着这些数据结构,我们再来专门的讨论下,特定的操作下,会发生什么:

a: ?在每个write完成后, 在file?table entry 中的?the?current file offset 会被增加?所写内容的字节数。如果这?引起?the?current file offset 超过?current?file size (i-node?entry 中的),则the?current file size ?被设置到跟?the?current???file offset 一样。

b: 如果?打开一个文件时使用了O_APPEND flag, 对应的?这个flag信息被设置在?file table entry 的?file?status flags 中。每次write完成后, 首先更新?i-node table entry 的?the?current file size .

d: lseek?函数?仅仅修改?file table entry 中的?current file offset, ?不是I/O 发生时?才做这样的事。

多个?file?descriptor ?对应?同一个?file?table entry 是可能的, 这发生在?dup 函数, 这也发生在?fork?之后, 这时?parent?和?child??共享相同的?file?table entry。

注意: file descriptor flags 和?file?status flags 的作用域(scope) 是不同的。

3.11 Atomic?Operations ?原子操作

往文件中追加:

老版本unix 系统不支持?open的?O_APPEND?选项,所以程序看起来如下:

if (lseek(fd, 0L, 2) < 0) /* position to EOF */

?????????err_sys("lseek error");

if (write(fd, buf, 100) != 100) /* and write */

????????err_sys("write error");

假定?有两个独立的进程: A, B, 正往同一个文件里追加。这种情况?和3.8中的图一样。

假定A?使用?lseek?, 把进程的?the?current offset ?设置为?1500 (文件的末尾)。--》

然后内核切换进程,进程B?运行,B?然后?lseek,它也设置?the current?offset 为?1500(文件的末尾)--》 B??然后write?, 它?把B的current?file offset 增加到?1600。由于file的size已经被?扩展,内核也会更新?在v-node 的?current?file size 到?1600。---》然后?内核切换进程,假定进程A运行。A?write , 这时他的?current file offset 是1500,这就会覆盖B写到文件中的数据。

出现这个问题的原因就是??定位到文件末尾?和?write?是两个函数。解决方案就是?时这两个操作变成?原子操作。多说一句,任何操作需要超过一个函数的?都不可能是?原子操作。

unix 系统提供了?进行这种原子操作的方式。就是使用O_APPEND flag . 这个会,在每次write前内核都会设置文件的位置,因此我们就不用在每次write之前都进行lseek了。

pread 和?pwrite 函数

unix 规范包含了?2个函数?,他们允许?应用可以?seek 并且?执行I/O 是原子性地,他们就是:pread?,pwrite

#include <unistd.h>

ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);

????????????????Returns: number of bytes read, 0 if end of file, -1 on error

ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);

????????????????Returns: number of bytes written if OK, -1 on error

注意pread, pwrite : 当前的current ?file?offset 不会被更新

创建文件

????????????????检查文件的是否存在, (如果不存在就)创建文件。 如果不用原子操作,可能是如下的写法:

if ((fd = open(path, O_WRONLY)) < 0) {

????????if (errno == ENOENT) {

????????????????if ((fd = creat(path, mode)) < 0)

????????????????????????err_sys("creat error");

????????} else {

????????????????err_sys("open error");

????????}

}

问题会产生:在open和create之间可能会产生问题。如果这个文件在open?和create?之间被另一个进程创建,并且另一个进程往文件写了些内容, 则当本进程执行create后?数据就会被擦出。 解决方案是??测试文件的存在性?和创建文件?合并成一个原子操作。

3.12 dup ,dup2 函数

一个已存在的?file descriptor 可被?复制(duplicated ),使用如下两个函数:

#include <unistd.h>

int dup(int fd);

int dup2(int fd, int fd2);

????????????????????????????????????????Both return: new file descriptor if OK, -1 on error

dup(1) ?新的?new?file descriptor ?fd(参数共享相同的?file?table entry. 如下图

说明:

在这个图中,我们假定,进程执行了

newfd = dup(1);

我们假定?下一个可用的?descriptor 是??3 (这是很可能的,由于0,1,2 被shell打开了)。两个描述符?指向共同的?file?table entry, 它们共享相同的?file?status flags -read, write, append 等等,并且有相同的??current?file offset.

每个描述符?有他自己的?file descriptor flags 集。 像在3.14部分描述的, 新的?file?descriptor 的?close-on-exec file?descriptor?flag 总是在?dup 函数中?被?清除掉。

另一个可以?复制?描述符的函数是?fcntl 函数:

dup(fd); ??等效于?fcntl(fd, F_DUPFD, 0);

类似地:dup2(fd, fd2); ?等效于?close(fd2); ?fcntl(fd, F_DUPFD, fd2);

在最后一个例子,dup2 不是?完全精确地?和?close, 后跟fcntl?相同。不同的地方如下:

dup2 是原子操作,dup2 ?和?fcntl?的errno?是不同的。

3.13 sync, fsync, fdatasync 函数

在对硬盘进行?I/O 操作时,unix?系统?内核?通常都?使用?buffer cache 或?page?cache 。当我们往file中写数据时,数据正常地?被copy ?到?内核它自己的?缓冲区,并且?放到队列排队,等待着稍后被写到硬盘。这叫做?delayed write。

为了确保?在硬盘上的file?和?buffer cache中内容一致,提供了?sync, fsync, fdatasync 函数。

#include <unistd.h>

int fsync(int fd);

int fdatasync(int fd);

????????????????????????????????????????????????????????Returns: 0 if OK, -1 on error

void sync(void);

sync?函数?简单queue 所有?被修改的?block buffers 来等着write?并且return; 它不会等到?write?disk?才return?。

sync?正常被系统?daemon 周期地(通常?30秒) 调用。命令sync(1) 也调用sync?函数。

fsync 指向单个file, 由参数fd?来指定, 等待?硬盘write?完成?之后才?return。这个函数通常由应用使用,如果数据库,因为需要?确保?修改的blocks 被write?到disk。

fdatasync 和?fsync?类型,但它?影响一个文件的一部分。使用fsync, 文件的attributes也会被同步地更新。

3.14 fcntl?函数

fcntl 函数可以改变文件的properties 。

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* int arg */ );

????????????????????????????????????????Returns: depends on cmd if OK (see following), -1 on error

fcntl?函数被通常用于以下?5个不同的目的:

  1. 复制?一个已存在的描述符(cmd= F_DUPFD or F_DUPFD_CLOEXEC)
  2. Get/Set file descriptor flags ( cmd= F_GETFD or ?F_SETFD)
  3. Get/Set file status flags (cmd= F_GETFL or F_SETFL)
  4. ?Get/Set 异步I/O (asynchronous) ownership (cmd=F_GETOWN ?or F_SETOWN)
  5. ?Get/Set 记录锁(record?locks) (cmd=F_GETLK, F_SETLK, or F_SETLKW)

先描述?11 cmd?value的前8个。

F_DUPFD ?: ?复制文件描述符?fd. ?新的?文件描述符?被做为函数的返回值?返回。 它是?最小的且没有被open的数字,并且大于或等于?第三个参数。 新的文件描述符?和?fd?共享相同的?file?table entry (参考3.9图)。 但新的描述符?有他自己的?file?descriptor flags, 并且他的?F_CLOEXEC file descriptor flag 会被清除掉。

F_DUPFD_CLOEXEC: ?复制文件描述符,并且设置?new?descriptor 的?FD_CLOEXEC??file descriptor flag 。

F_GETFD ?: 返回?fd的?file?descriptor flags 。当前?仅仅只有一个?file?descriptor flag 被定义就是: FD_CLOEXEC flag

F_SETFD : 设置?file?descriptor flags . ?由第三个参数指定。

F_GETFL ?返回fd的?file?status flags . 这些flags描述了打开了文件后的状态。他们含义如下列表:

File status flag

Description

O_RDONLY

open for reading only

O_WRONLY

open for writing only

O_RDWR

open for reading and writing

O_EXEC

open for execute only

O_SEARCH

open directory for searching only

O_APPEND

append on each write

O_NONBLOCK

nonblocking mode

O_SYNC

wait for writes to complete (data and attributes)

O_DSYNC

wait for writes to complete ( data only)

O_RSYNC

synchronize reads and writes

O_ASYNC

asynchronous I/O (FreeBSD and Mac OS X only)

O_FSYNC

wait for writes to complete (FreeBSD and Mac OS X only)

不幸的,5个?access-mode 是相互独立的。 一个文件仅仅只能启用?他们中的一个。因此我们必须使用?O_ACCMODE mask 去获取?access-mode bits 然后?得到的结果和这五个值进行对比。

F_SETFL ?: 设置?file status flags, ?只有这些flags可以被改变,这些flags:O_APPEND, O_NONBLOCK, O_SYNC, O_DSYNC, O_RSYNC, O_FSYNC, O_ASYNC.

F_GETOWN : 收到?SIGIO, SIGURG 信号,Get??进程ID?或进程组?ID。14.5.2会描述。

F_SETOWN : ?设置?进程ID, 进程组ID, 为?收到SIGIO, SIGURG 信号?。正数arg??是进程ID, 负数?arg?应用于进程组ID。

返回什么取决于?command, 发生错误返回-1 ,如果OK?返回其他?值。

F_DUPFD 返回?new?file descriptor,

F_GETFD, F_GETFL, 返回对应的?flags,

F_GETOWN 返回?正数?进程ID, 负数?进程组ID.

例子:

接收一个命令行参数, 这个参数是fd, 打印?fd的?file?flags。

fileio/fileflags.c

1.#include?"apue.h"??
2.#include?<fcntl.h>??
3.??
4.int??
5.main(int?argc,?char?*argv[])??
6.{??
7.????int?????val;??
8.??
9.????if?(argc?!=?2)??
10.????????err_quit("usage:?a.out?<descriptor#>");??
11.??
12.????if?((val?=?fcntl(atoi(argv[1]),?F_GETFL,?0))?<?0)??
13.????????err_sys("fcntl?error?for?fd?%d",?atoi(argv[1]));??
14.??
15.????switch?(val?&?O_ACCMODE)?{??
16.????case?O_RDONLY:??
17.????????printf("read?only");??
18.????????break;??
19.??
20.????case?O_WRONLY:??
21.????????printf("write?only");??
22.????????break;??
23.??
24.????case?O_RDWR:??
25.????????printf("read?write");??
26.????????break;??
27.??
28.????default:??
29.????????err_dump("unknown?access?mode");??
30.????}??
31.??
32.????if?(val?&?O_APPEND)??
33.????????printf(",?append");??
34.????if?(val?&?O_NONBLOCK)??
35.????????printf(",?nonblocking");??
36.????if?(val?&?O_SYNC)??
37.????????printf(",?synchronous?writes");??
38.??
39.#if?!defined(_POSIX_C_SOURCE)?&&?defined(O_FSYNC)?&&?(O_FSYNC?!=?O_SYNC)??
40.????if?(val?&?O_FSYNC)??
41.????????printf(",?synchronous?writes");??
42.#endif??
43.??
44.????putchar('\n');??
45.????exit(0);??
46.}??
47.??
48./**?
49.?*??
50.?[xingqiji@bogon?fileio]$?./fileflags?0?
51.read?write?
52.[xingqiji@bogon?fileio]$?./fileflags?0?<?/dev/tty?
53.read?only?
54.[xingqiji@bogon?fileio]$?./fileflags?1?
55.read?write?
56.[xingqiji@bogon?fileio]$?./fileflags?1?>?temp.foo?
57.[xingqiji@bogon?fileio]$?cat?temp.foo?
58.write?only?
59.[xingqiji@bogon?fileio]$?./fileflags?2?2>>?temp.foo?
60.write?only,?append?
61.[xingqiji@bogon?fileio]$?./fileflags?5?5<>?temp.foo??
62.read?write?
63.[xingqiji@bogon?fileio]$??
64.?
65.5<>temp.foo??在描述符5?打开?temp.foo?,以?reading?,writing?
66.?*??
?*/?

例子: 当修改?file?descriptor flags 或?file?status?flags ,要?当心。

3.12 ?图?打开一个或多个?file status flags

fileio/setfl.c

1.#include?"apue.h"??
2.#include?<fcntl.h>??
3.??
4.void??
5.set_fl(int?fd,?int?flags)?/*?flags?are?file?status?flags?to?turn?on?*/??
6.{??
7.????int?????val;??
8.??
9.????if?((val?=?fcntl(fd,?F_GETFL,?0))?<?0)??
10.????????err_sys("fcntl?F_GETFL?error");??
11.??
12.????val?|=?flags;???????/*?turn?on?flags?*/??
13.??
14.????if?(fcntl(fd,?F_SETFL,?val)?<?0)??
15.????????err_sys("fcntl?F_SETFL?error");??
16.}??

对应的?关闭flags:

val &= ~flags;

3.15 ioctl 函数

#include <unistd.h> /* System V */

#include <sys/ioctl.h> /* BSD and Linux */

int ioctl(int fd, int request, ...);

????????????????????????????????????????????????Returns: -1 on error, something else if OK

3.16 ?/dev/fd

新的系统?提供了?一个目录??叫?/dev/fd 它的entries?是?0, 1,2 等等。打开?/dev/fd/n 等效于?复制描述符?n, (假定?n 是open).

fd = open(“/dev/fd/0”, mode);

注意,mode?是?原始的0 的打开模式的?子集。

例如: 0 被打开?read-only。 即便是如下:

fd?= open(“/dev/fd/0”, O_RDWR);

成功后,仍然不能?write?to?fd.

Linux 对?/dev/fd 的实现?是异类。它映射?file?descriptors ?到?symbolic links (它指向底层的物理文件)。

也可以在create中?通过指定?O_CREAT ,pathname参数是?/dev/fd 来?创建。但是注意!在Linux?,因为Linux 实现?使用?symbolic 链接到?real files, 使用create 参数是/dev/fd 将导致?底层的文件?被?truncated.

一些系统?提供了?pathnames 如: /dev/stdin, ?/dev/stdout, /dev/stderr.

这些?等效于?/dev/fd/0, /dev/fd/1, ?/dev/fd/2

/dev/fd 的用途主要是?shell在使用, 例如:

filter file2 | cat file1 - file3 | lpr?????// - ?代表??standard?input

如果?支持?/dev/fd ,则可以如下写:

?filter file2 | cat file1 /dev/fd/0 file3 | lpr

3.17 Summary

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 21:37:00  更:2022-02-14 21:39:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 5:43:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码