c-F_GETFL和F_SETFL的用法 [英] c - Usage of F_GETFL and F_SETFL
问题描述
当尝试通过命令F_GETFL
和F_SETFL
使用fcntl()
时,我遇到了一些问题:
While trying to use fcntl()
with command F_GETFL
and F_SETFL
, I got some questions:
-
为什么
fcntl(fd, F_GETFL)
返回的标志仅包含打开文件时设置的位的子集?它仅显示可修改的内容吗?
Why the flag returned by
fcntl(fd, F_GETFL)
only include a subset of bits of what I set when open file? Does it only show the ones that are modifiable?
使用fcntl(fd, F_SETFL, flag)
时,应如何传递标志参数,我是否需要先通过fcntl(fd, F_GETFL)
读取标志,然后对其进行修改并传递它?还是在内部仅对新参数执行&
操作?
When use fcntl(fd, F_SETFL, flag)
, how should I pass the flag param, do I need to read flag via fcntl(fd, F_GETFL)
first, then modify it and pass it? Or internally it just do a bit &
operation with the new param?
在哪里可以找到打开文件标志的32位(或更少)的完整列表?
Where can I find a full list of the 32 (or less) bits of open file flags?
代码-[dup_fd_share.c]:
// prove duplicated fd shared file offset and open file status,
// TLPI exercise 5.5
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 100
void fd_share() {
char *fp = "/tmp/fd_share.txt";
char *buf = "abc\n";
int write_size = 4;
int fd, fd2;
off_t cur, cur2;
int open_flag, open_flag2;
// open
int flag = O_RDWR | O_CREAT | O_TRUNC | O_APPEND;
printf("file flag param: %x\n", flag);
fd = open(fp, flag, 0644);
// dup
fd2 = dup(fd);
// initial offset
cur = lseek(fd, 0, SEEK_CUR);
printf("fd[%d] offset: %ld\n", fd, cur);
cur2= lseek(fd2, 0, SEEK_CUR);
printf("fd[%d] offset: %ld\n", fd2, cur2);
// write, offset change,
write(fd, buf, 4);
printf("write %d chars\n", write_size);
// new offset
cur = lseek(fd, 0, SEEK_CUR);
printf("fd[%d] offset: %ld\n", fd, cur);
cur2= lseek(fd2, 0, SEEK_CUR);
printf("fd[%d] offset: %ld\n", fd2, cur2);
// get original open file flag,
open_flag = fcntl(fd, F_GETFL);
printf("fd[%d] open flag: %x\n", fd, open_flag);
open_flag2 = fcntl(fd2, F_GETFL);
printf("fd[%d] open flag: %x\n", fd2, open_flag2);
// change open file flag,
open_flag &= ~O_APPEND;
if(fcntl(fd, F_SETFL, open_flag) == -1) {
printf("failed to set flag\n");
return;
}
printf("change open file flag, remove %s\n", "O_APPEND");
open_flag = fcntl(fd, F_GETFL);
printf("fd[%d] open flag: %x\n", fd, open_flag);
open_flag2 = fcntl(fd2, F_GETFL);
printf("fd[%d] open flag: %x\n", fd2, open_flag2);
close(fd);
}
int main(int argc, char *argv[]) {
fd_share();
return 0;
}
输出:
file flag param: 642
fd[3] offset: 0
fd[4] offset: 0
write 4 chars
fd[3] offset: 4
fd[4] offset: 4
fd[3] open flag: 402
fd[4] open flag: 402
change open file flag, remove O_APPEND
fd[3] open flag: 2
fd[4] open flag: 2
推荐答案
您问过:
为什么打开文件时fcntl(fd,F_GETFL)返回的标志仅包含我设置的位的子集?它仅显示可修改的内容吗?
Why the flag returned by fcntl(fd, F_GETFL) only include a subset of bits of what I set when open file? Does it only show the ones that are modifiable?
否;它仅显示系统已记住"的内容,例如O_RDWR
.这些实际上可以称为标志". oflag
参数中ORed的其他某些位更像是open
系统调用的命令性指令":例如,O_CREAT
说请创建此文件(如果它不存在)"和O_TRUNC
说请截断它",这两个都不是标志".创建时被截断的文件与创建时未被截断的文件没有区别:它们都只是文件".因此,在open
完成创建或截断文件后,就不必再记住"该历史记录了.它只会记住"重要的事情,例如文件是打开供读取还是写入.
No; it only shows the ones that are "remembered" by the system, such as O_RDWR
. These can really be called "flags". Some of the other bits ORed into the oflag
parameter are more like "imperative instructions" to the open
system call: for example, O_CREAT
says "please create this file if it doesn't exist" and O_TRUNC
says "please truncate it", neither of which are "flags". A file that was truncated on creation is indistinguishable from a file that was not truncated on creation: they're both just "files". So after open
is done creating or truncating the file, it doesn't bother to "remember" that history. It only "remembers" important things, like whether the file is open for reading or writing.
编辑后添加:这些不同类型的标志具有半官方名称. O_RDWR
是访问模式"(记住,不可修改); O_APPEND
是操作模式"(记住,通常可以修改); O_TRUNC
是一个开放时间标志"(与open
操作本身有关,与文件描述符无关;因此不被记住).请注意,访问模式"不可修改-您不能使用fcntl
将只读fd转换为只写fd.
Edited to add: These different kinds of flags have semi-official names. O_RDWR
is the "access mode" (remembered, non-modifiable); O_APPEND
is an "operating mode" (remembered, usually modifiable); O_TRUNC
is an "open-time flag" (pertains to the open
operation itself, not to the file descriptor; therefore not remembered). Notice that the "access mode" is not modifiable — you can't use fcntl
to turn a read-only fd into a write-only fd.
使用
fcntl(fd, F_SETFL, flag)
时,应如何传递标志参数,我是否需要先通过fcntl(fd, F_GETFL)
读取标志,然后对其进行修改并传递它?还是在内部仅对新参数执行&
操作?
When use
fcntl(fd, F_SETFL, flag)
, how should I pass the flag param, do I need to read flag viafcntl(fd, F_GETFL)
first, then modify it and pass it? Or internally it just do a bit&
operation with the new param?
F_SETFL
完全用您输入的内容 覆盖这些标志(尽管它会忽略您微不足道的尝试设置位,而不是真正的标志,例如O_TRUNC
) .如果要设置特定标志,而其他标志保持原样,则必须F_GETFL
旧标志,|
新标志,然后F_SETFL
结果. 必须作为两个单独的系统调用来完成;据我所知,没有原子或线程安全的方法可以完成它.
F_SETFL
overwrites the flags with exactly what you pass in (although it will ignore your puny attempts to set bits-that-aren't-really-flags, such as O_TRUNC
). IF you want to set a specific flag and leave the other flags as-is, then you must F_GETFL
the old flags, |
the new flag in, and then F_SETFL
the result. This must be done as two separate system calls; there is no atomic or thread-safe way to accomplish it as far as I know.
在哪里可以找到打开文件标志的32位(或更少)位的完整列表?
Where can I find a full list of the 32 (or less) bits of open file flags?
在fcntl.h
或其文档(man fcntl
)中.例如,在我的MacBook上,手册页上显示:
In fcntl.h
or its documentation (man fcntl
). For example, on my MacBook the man page says:
The flags for the F_GETFL and F_SETFL commands are as follows:
O_NONBLOCK Non-blocking I/O; if no data is available to a read call, or if a write operation would block, the read or write
call returns -1 with the error EAGAIN.
O_APPEND Force each write to append at the end of file; corresponds to the O_APPEND flag of open(2).
O_ASYNC Enable the SIGIO signal to be sent to the process group when I/O is possible, e.g., upon availability of data to be
read.
换句话说,您可以在OS X上设置(或取消设置)三位.而在Linux上,手册页显示
In other words, there are exactly three bits you can set (or unset) on OS X. Whereas on Linux, the man page says this:
On Linux this command can change only the O_APPEND, O_ASYNC,
O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
偶然地,某些Linux文件系统在文件系统级别具有仅附加文件"的概念.如果打开这些文件之一,然后尝试清除生成的描述符的O_APPEND
标志,则会出现EPERM
错误.可以使用 chattr
在文件系统级别控制文件的仅追加"功能. 实用程序.
Incidentally, some Linux filesystems have the concept of an "append-only file" at the filesystem level; if you open one of those files and then try to clear the resulting descriptor's O_APPEND
flag, you'll get an EPERM
error. The "append-only"-ness of a file can be controlled at the filesystem level using the chattr
utility.
这是您的测试程序的更系统的版本.它可能对您不感兴趣,但是我通过编写来学习了一些东西,因此我将其留在这里. :)
Here's a more systematic version of your test program. It might not be of interest to you, but I learned something by writing it, so I'm leaving it here. :)
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("/tmp/fd_share.txt", O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0644);
// append to empty file
write(fd, "aaaaaaaaaa", 10);
off_t cur = lseek(fd, 1, SEEK_SET);
printf("offset after being set to 1: %ld\n", (long)cur);
// append
write(fd, "bbbbbbbb", 8);
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after appending bbbbbbbb: %ld\n", (long)cur);
cur = lseek(fd, 2, SEEK_SET);
printf("offset after being set to 2: %ld\n", (long)cur);
// now toggle "append mode" to FALSE
int open_flag = fcntl(fd, F_GETFL);
if (fcntl(fd, F_SETFL, open_flag & ~O_APPEND) == -1) {
printf("failed to set flag\n");
return 0;
}
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after unsetting O_APPEND: %ld\n", (long)cur);
cur = lseek(fd, 3, SEEK_SET);
printf("offset after being set to 3: %ld\n", (long)cur);
// write without appending
write(fd, "cccc", 4);
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after writing cccc: %ld\n", (long)cur);
// now toggle "append mode" to TRUE
open_flag = fcntl(fd, F_GETFL);
if (fcntl(fd, F_SETFL, open_flag | O_APPEND) == -1) {
printf("failed to set flag\n");
return 0;
}
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after unsetting O_APPEND: %ld\n", (long)cur);
// append
write(fd, "dd", 2);
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after appending dd: %ld\n", (long)cur);
close(fd);
}
此程序在MacBook上的输出(应在任何POSIX系统AFAIK上显示为)
The output of this program on my MacBook (as it should be on any POSIX system AFAIK) is:
offset after being set to 1: 1
offset after appending bbbbbbbb: 18
offset after being set to 2: 2
offset after unsetting O_APPEND: 2
offset after being set to 3: 3
offset after writing cccc: 7
offset after unsetting O_APPEND: 7
offset after appending dd: 20
这篇关于c-F_GETFL和F_SETFL的用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!