linux lseek SEEK_DATA似乎不工作

ddrv8njm  于 2023-05-06  发布在  Linux
关注(0)|答案(1)|浏览(130)

运行在内核为6.2.12-1-default的Tumbleweed上
使用_GNU_SOURCE定义应该允许使用SEEK_DATA作为lseek的whence值。
根据手册页,这应该适用于一系列文件系统。我已经在btrfs和ext4上测试了这段代码,得到了相同的结果。

#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>

void test(char *filepath) {
    int write_value = 0x22;

    int fh = open(filepath, O_CREAT | O_TRUNC | O_RDWR);

    int os    = lseek(fh, 10, SEEK_SET);
    int wret  = write(fh, &write_value, sizeof(int));
    int os2   = lseek(fh, 0, SEEK_DATA);
    printf("os: %d os2: %d wret %d\n", os, os2, wret);
    close(fh);
}

给定上面的代码,我希望SEEK_DATA在偏移量10处找到第一个写入的值,并且os 2 == os,但lseek返回0。
文件确实按预期写入,od -x给出以下输出:

0000000 0000 0000 0000 0000 0000 0022 0000

有什么建议吗?我是否对预期行为做了错误的假设…

ccrfmcuu

ccrfmcuu1#

稀疏文件是特定于实现的。我们可以假设孔粒度取决于文件系统I/O块大小。
我修改了你的程序来做一些测试:

#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdint.h>

static void test(off_t offset)
{
    int write_value = 0x22;

    int fh = open("dummy", O_CREAT | O_TRUNC | O_RDWR, 0644);

    off_t os     = lseek(fh, offset, SEEK_SET);
    ssize_t wret = write(fh, &write_value, sizeof(write_value));
    off_t os2    = lseek(fh, 0, SEEK_DATA);

    struct stat statbuf;
    int ret = fstat(fh, &statbuf);

    printf("% 6jd | % 6jd | % 6zd | % 6jd\n",
        (intmax_t)os, (intmax_t)os2, wret,
        (intmax_t)(ret == 0 ? statbuf.st_blocks*512 : -1));

    close(fh);

    unlink("dummy");
}

int main(int, char **argv)
{
    printf("   os  |   os2  |  wret  |  used \n"
           "----------------------------------\n");

    while (*++argv)
    {
        test(atol(*argv));
    }

    return 0;
}

文件系统块大小通常为:

$ stat -f -c "%s" .
4096

结果:

$ ./holes 10 4095 4096 8191 8192 8193
   os  |   os2  |  wret  |  used 
----------------------------------
    10 |      0 |      4 |   4096
  4095 |      0 |      4 |   8192
  4096 |   4096 |      4 |   4096
  8191 |   4096 |      4 |   8192
  8192 |   8192 |      4 |   4096
  8193 |   8192 |      4 |   4096

分析:
写入偏移10:| data |
0块孔,1块数据。数据块从开头开始:os2 == 0。
写入偏移4095:| data | data |
0块孔,2块数据。数据块从开头开始:os2 == 0。
写入偏移4096:| hole | data |
1个孔块,1个数据块。数据块从秒开始,os 2 == 4096。
写入偏移量8191:| hole | data | data |
1块孔,2块数据。数据块从秒开始,os 2 == 4096
写入偏移8192:| hole | hole | data |
2块孔,1块数据。数据块从第三个开始,os 2 == 8192
写入偏移量8193:和8192一样。
观察结果符合预期。

相关问题