pwrite() & O_APPEND

· 273 words · 1 minute read

Linux 的 pwrite() 有个 BUG: 当文件以 O_APPEND 模式打开时,虽然 file offset 不会变,但是写入的内容会追加到文件尾部。

此外,pwrite()pwritev() 的 offset 参数不能为 -1, 否则会 EINVAL. 但是 pwritev2() 可以,表示使用当前的 file offset 并且会更新之。

man(2) pwrite
BUG
    POSIX  requires that opening a file with the O_APPEND flag should have
    no effect on the location at which pwrite() writes data.  However,  on
    Linux, if a file is opened with O_APPEND, pwrite() appends data to the
    end of the file, regardless of the value of offset.

下面是个示例程序:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    int flags, fd;

    if (argc != 2) {
        printf("usage: %s file\n", argv[0]);
        return 1;
    }

    flags = O_RDWR | O_CREAT | O_TRUNC;
    if (strstr(argv[1], "append") != NULL) {
        flags |= O_APPEND;
    }

    fd = open(argv[1], flags, 0600);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    if (write(fd, "hello\n", 6) < 0) {
        perror("write");
    }

    printf("offset: %ld\n", lseek(fd, 0, SEEK_CUR));

    /* offset = -1 => EINVAL */
    if (pwrite(fd, "world\n", 6, 0) < 0) {
        perror("pwrite");
    }

    printf("offset: %ld\n", lseek(fd, 0, SEEK_CUR));

    close(fd);
    return 0;
}

运行结果:

$ ./a.out hello; cat hello
offset: 6
offset: 6
world
$ ./a.out append; cat append
offset: 6
offset: 6
hello
world
c++
comments powered by Disqus