在尝试fcntl()与command F_GETFL和结合使用时F_SETFL,我遇到了一些问题:
为什么fcntl(fd, F_GETFL)打开文件时返回的标志仅包含我设置的位的子集?它仅显示可修改的内容吗?
使用时fcntl(fd, F_SETFL, flag),我应该如何传递标志参数,我是否需要先通过标志读取标志fcntl(fd, F_GETFL),然后对其进行修改并传递它?还是在内部它只是&对新的参数做了一点操作?
在哪里可以找到打开文件标志的32位(或更少)位的完整列表?
代码-[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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
您问:
为什么fcntl(fd,F_GETFL)返回的标志仅包含我在打开文件时设置的位的子集?它仅显示可修改的内容吗?
没有; 它仅显示系统“记住”的内容,例如O_RDWR。这些实际上可以称为“标志”。该oflag参数中ORed的其他一些位更像是open系统调用的“命令性指令” :例如,O_CREAT说“请创建该文件(如果不存在)”和O_TRUNC“请截断它”,但这两个都不是“标志”。在创建时被截断的文件与在创建时未被截断的文件是没有区别的:它们都只是“文件”。因此,在open完成创建或截断文件后,不必“记住”该历史记录。它只会“记住”重要的事情,
编辑添加:这些不同种类的标志具有半官方名称。O_RDWR是“访问模式”(记住的,不可修改的); O_APPEND是一种“操作模式”(记住,通常可以修改);O_TRUNC是一个“开放时间标志”(与open操作本身有关,与文件描述符无关;因此不被记住)。请注意,“访问模式”不可修改-您不能使用fcntl将只读fd转换为只写fd。
使用时
fcntl(fd, F_SETFL, flag),我应该如何传递标志参数,我是否需要先通过标志读取标志fcntl(fd, F_GETFL),然后对其进行修改并传递它?还是在内部它只是&对新的参数做了一点操作?
F_SETFL用您传入的内容完全覆盖这些标志(尽管它将忽略您为设置位(实际上不是)标志而做的微不足道的尝试,例如O_TRUNC)。如果要设置特定标志,而其他标志保持原样,则必须先F_GETFL插入旧标志,再|插入新标志,然后再返回F_SETFL结果。这必须作为两个单独的系统调用来完成;据我所知,没有原子或线程安全的方法来完成它。
在哪里可以找到打开文件标志的32位(或更少)位的完整列表?
在fcntl.h或其文档(man fcntl)中。例如,在我的MacBook上,手册页显示:
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.
Run Code Online (Sandbox Code Playgroud)
换句话说,您可以在OS X上完全设置(或取消设置)三个位。而在Linux上,手册页显示如下:
On Linux this command can change only the O_APPEND, O_ASYNC,
O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
Run Code Online (Sandbox Code Playgroud)
顺便说一下,某些Linux文件系统在文件系统级别具有“仅附加文件”的概念。如果打开这些文件之一,然后尝试清除生成的描述符的O_APPEND标志,则会收到EPERM错误消息。可以使用chattr实用程序在文件系统级别上控制文件的“仅追加” 功能。
这是测试程序的更系统的版本。它可能对您不感兴趣,但是我通过编写来学习了一些东西,所以我将其留在这里。:)
#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);
}
Run Code Online (Sandbox Code Playgroud)
该程序在我的MacBook上的输出(应在任何POSIX系统AFAIK上输出)是:
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
Run Code Online (Sandbox Code Playgroud)
1) fcnl 的返回是描述函数是否成功以及如何执行的代码:
返回值
For a successful call, the return value depends on the operation:
F_DUPFD The new descriptor.
F_GETFD Value of file descriptor flags.
F_GETFL Value of file status flags.
F_GETLEASE
Type of lease held on file descriptor.
F_GETOWN Value of descriptor owner.
F_GETSIG Value of signal sent when read or write becomes possible, or
zero for traditional SIGIO behavior.
F_GETPIPE_SZ, F_SETPIPE_SZ
The pipe capacity.
F_GET_SEALS
A bit mask identifying the seals that have been set for the
inode referred to by fd.
All other commands
Zero.
On error, -1 is returned, and errno is set appropriately.
Run Code Online (Sandbox Code Playgroud)
错误
EACCES or EAGAIN
Operation is prohibited by locks held by other processes.
EAGAIN The operation is prohibited because the file has been memory-
mapped by another process.
EBADF fd is not an open file descriptor
EBADF cmd is F_SETLK or F_SETLKW and the file descriptor open mode
doesn't match with the type of lock requested.
EBUSY cmd is F_SETPIPE_SZ and the new pipe capacity specified in arg
is smaller than the amount of buffer space currently used to
store data in the pipe.
EBUSY cmd is F_ADD_SEALS, arg includes F_SEAL_WRITE, and there
exists a writable, shared mapping on the file referred to by
fd.
EDEADLK
It was detected that the specified F_SETLKW command would
cause a deadlock.
EFAULT lock is outside your accessible address space.
EINTR cmd is F_SETLKW or F_OFD_SETLKW and the operation was
interrupted by a signal; see signal(7).
EINTR cmd is F_GETLK, F_SETLK, F_OFD_GETLK, or F_OFD_SETLK, and the
operation was interrupted by a signal before the lock was
checked or acquired. Most likely when locking a remote file
(e.g., locking over NFS), but can sometimes happen locally.
EINVAL The value specified in cmd is not recognized by this kernel.
EINVAL cmd is F_ADD_SEALS and arg includes an unrecognized sealing
bit.
EINVAL cmd is F_ADD_SEALS or F_GET_SEALS and the filesystem
containing the inode referred to by fd does not support
sealing.
EINVAL cmd is F_DUPFD and arg is negative or is greater than the
maximum allowable value (see the discussion of RLIMIT_NOFILE
in getrlimit(2)).
EINVAL cmd is F_SETSIG and arg is not an allowable signal number.
EINVAL cmd is F_OFD_SETLK, F_OFD_SETLKW, or F_OFD_GETLK, and l_pid
was not specified as zero.
EMFILE cmd is F_DUPFD and the process already has the maximum number
of file descriptors open.
ENOLCK Too many segment locks open, lock table is full, or a remote
locking protocol failed (e.g., locking over NFS).
ENOTDIR
F_NOTIFY was specified in cmd, but fd does not refer to a
directory.
EPERM Attempted to clear the O_APPEND flag on a file that has the
append-only attribute set.
EPERM cmd was F_ADD_SEALS, but fd was not open for writing or the
current set of seals on the file already includes F_SEAL_SEAL.
Run Code Online (Sandbox Code Playgroud)
2)要设置的标志是您的选择::
F_SETFL (int)
Set the file status flags to the value specified by arg. File
access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation
flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are
ignored. On Linux this command can change only the O_APPEND,
O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags. It is not
possible to change the O_DSYNC and O_SYNC flags; see BUGS,
below.
Run Code Online (Sandbox Code Playgroud)
3)在这里你有一个完整的描述。
| 归档时间: |
|
| 查看次数: |
11421 次 |
| 最近记录: |