如何实现类似“truncateat”的东西?

问题描述 投票:0回答:1

在研究this question时,我发现在POSIX(和Linux)中根本就没有truncateat系统调用。

某些系统调用(例如unlink)有一个等效的替代方法,在其名称的末尾添加了at后缀,即unlinkat。这些方法之间的区别在于,at后缀的变体接受另一个参数,即指向目录的文件描述符。因此,传递到unlinkat的相对路径与当前工作目录无关,而是相对于提供的文件描述符(打开目录)。这在某些情况下非常有用。

看看truncate,旁边只有ftruncatetruncate适用于路径 - 绝对或相对于当前工作目录。 ftruncate直接在打开的文件句柄上工作 - 没有指定任何路径。没有truncateat

很多库(各种“替代”C库)做我做的事情,并使用tuncateat-openat-ftruncate序列模拟close。在大多数情况下,除了...

我遇到了以下问题。我花了几个月的时间来弄清楚发生了什么。在Linux上测试过,不同的3.X和4.X内核。想象一下两个进程(不是线程):

  • 过程“A”
  • 过程“B”

现在想象下面的事件序列(伪代码):

A: fd = open(path = 'filename', mode = write)
A: ftruncate(fd, 100)
A: write(fd, 'abc')
B: truncate('filename', 200)
A: write(fd, 'def')
A: close(fd)

以上工作就好了。在进程“A”打开文件之后,将其大小设置为100并将一些内容写入其中,进程“B”将其大小重新设置为200.然后进程“A”继续。最后,文件的大小为200,并在其开头包含“abcdef”,后跟零字节。

现在,让我们尝试模仿像truncateat这样的东西:

A: fd_a = open(path = 'filename', mode = write)
A: ftruncate(fd_a, 100)
A: write(fd_a, 'abc')
B: fd_b = openat(dirfd = X, path = 'filename', mode = write | truncate)
B: ftruncate(fd_b, 200)
B: close(fd_b)
A: write(fd_a, 'def')
A: close(fd_a)

我的文件长度为200,好的。它从三个零字节开始,不行,然后是“def”,然后是零字节。我刚刚从进程“A”中丢失了第一个写入,而“def”在技术上落在了正确的位置(三个字节,好像我在编写之前调用了seek(fd_a, 3))。

我可以正常使用第一个操作序列。但在我的用例中,就进程“B”而言,我不能依赖于相对于当前工作目录的路径。我真的想使用相对于文件描述符的路径。怎么能实现这一点 - 没有遇到第二个操作序列中演示的问题?在fsync之后从过程“A”调用write(fd_a, 'abc')并没有解决这个问题。

linux posix system-calls glibc
1个回答
1
投票

你的第二种情况用零覆盖所有内容的原因是mode = truncate(即openat(.., O_TRUNC))将首先将文件截断为长度为0。

如果你在没有先截断为0的情况下立即将ftruncate改为200,那么直到那一点的现有数据将保持不变。

© www.soinside.com 2019 - 2024. All rights reserved.