c-F_GETFL和F_SETFL的用法 [英] c - Usage of F_GETFL and F_SETFL

查看:214
本文介绍了c-F_GETFL和F_SETFL的用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当尝试通过命令F_GETFLF_SETFL使用fcntl()时,我遇到了一些问题:

While trying to use fcntl() with command F_GETFL and F_SETFL, I got some questions:

  1. 为什么fcntl(fd, F_GETFL)返回的标志仅包含打开文件时设置的位的子集?它仅显示可修改的内容吗?

  1. 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 via fcntl(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆