如何实现类似于"truncateat"的东西? [英] How to implement something similar to "truncateat"?

查看:94
本文介绍了如何实现类似于"truncateat"的东西?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在研究这个问题时,我遇到了一个事实,即在POSIX(和Linux)中根本没有一个系统调用.

While researching this question I came across the fact that in POSIX (and Linux) there simply is not a truncateat system call.

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

Certain system calls like for instance unlink have an equivalent alternative method with an added at suffix at the end of their names, i.e. unlinkat. The difference between those methods is that the variations with the at suffix accept an additional argument, a file descriptor pointing to a directory. Therefore, a relative path passed into unlinkat is not relative to the current working directory but instead relative to the provided file descriptor (an open directory). This is really useful under certain circumstances.

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

Looking at truncate, there only is ftruncate next to it. truncate works on paths - absolute or relative to the current working directory. ftruncate directly works on an open file handle - without any path being specified. There is no truncateat.

许多库(各种替代" C库)都执行了我的工作,并使用openat-ftruncate-close-序列模拟了tuncateat.在大多数情况下,此方法有效,除了...

A lot of libraries (various "alternative" C-libraries) do what I did and mimic tuncateat by using an openat-ftruncate-close-sequence. This works, in most cases, except ...

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

I ran into the following issue. It took me months to figure out what was happening. Tested on Linux, different 3.X and 4.X kernels. Imagine two processes (not threads):

  • 处理"A"
  • 处理"B"

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

Now imagine the following sequence of events (pseudo code):

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",后跟零字节.

The above works just fine. Just after process "A" has the file opened, set its size to 100 and written some stuff into it, process "B" re-sets its size to 200. Then process "A" continues. At the end, the file has a size of 200 and contains "abcdef" at its beginning followed by zero-bytes.

现在,让我们尝试模仿类似truncateat的内容:

Now, let's try and mimic something like 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",而高清"技术在正确的位置落在第一次写入(三个字节中,我好像叫写它之前).

My file has a length of 200, ok. It starts with three zero-bytes, not ok, then the "def", then then again zero-bytes. I have just lost the first write from process "A" while the "def" technically landed at the correct position (three bytes in, as if I had called seek(fd_a, 3) before writing it).

我可以很好地处理第一个操作序列.但是在我的用例中,就进程"B"而言,我不能依赖相对于当前工作目录的路径.我真的很想使用相对于文件描述符的路径.如何实现这一目标-而不会遇到第二步操作中演示的问题?在write(fd_a, 'abc')之后立即从进程"A"调用fsync不能解决此问题.

I can work with the first sequence of operations just fine. But in my use case, I can not rely on paths relative the current working directory as far as process "B" is concerned. I really want to work with paths relative to a file descriptor. How can achieve that - without running into the issue demonstrated in the second sequence of operations? Calling fsync from process "A" just after write(fd_a, 'abc') does not solve this.

推荐答案

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

The reason why your second case overwrites everything with zeroes is that mode=truncate (i.e. openat(.., O_TRUNC)) will first truncate the file to length 0.

如果您立即将ftruncate设置为200,而没有先将其截断为0,则直到该点的现有数据都将保持不变.

If you instead ftruncate to 200 immediately without first truncating to 0, the existing data up until that point will remain untouched.

这篇关于如何实现类似于"truncateat"的东西?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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