Linux查看稀疏文件的哪些块没有分配空间

Posted on 2016-02-04 10:53:41 by osdba


我们有时需要知道Linux下的一个文件的数据是存在哪些数据块上,或有时知道稀疏文件有哪些数据块分配的,哪些数据块没有分配。

在Linux中没有提供现成的工具,但我们可以通过调用ioctl函数来查询一个文件的数据块分布情况。此功能源代码fibmap.c的内容如下:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fs.h>


int main (int argc, char* argv[]) 
{
    int fd, blocknum, blocksize;
    struct stat fileinfo;

    if (argc < 1) 
    {
        fprintf(stderr, "Syntax Errof\n");
        exit(EXIT_FAILURE);
    }

    if ((fd = open(argv[1], O_RDONLY)) < 0) 
    {
        int errnum = errno;
        fprintf(stderr, "Cannot open '%s': %s\n", argv[1], strerror(errnum));
        exit(EXIT_FAILURE);
    }

    if (ioctl(fd, FIGETBSZ, &blocksize) < 0 ) 
    {
        int errnum = errno;
        fprintf(stderr, "Cannot get blocksize: %s\n", strerror(errnum));
        exit(EXIT_FAILURE);
    }

    if (fstat(fd, &fileinfo) < 0)
    {
        int errnum = errno;
        fprintf(stderr, "Stat failed: %s\n", strerror(errnum));
        exit(EXIT_FAILURE);
    }

    blocknum = (fileinfo.st_size + blocksize - 1) / blocksize;

    printf("Filename: %s\nBlocksize: %d\nBlocknum: %d\n",
           argv[1], blocksize, blocknum);

    int i;
    for (i = 0; i < blocknum; i++)
    {
        int block = i;
        if (ioctl(fd, FIBMAP, &block)) 
        {
            printf("ioctl failed: %s\n", strerror(errno));
        }
        printf("%10d\n", block);
    }
    close(fd);
    printf("\n");
    exit(EXIT_SUCCESS);
}


我们用dd命令建一个稀疏文件,表明上有16k大小,实际占用空间为0:


[root@pg01 111]# dd if=/dev/zero of=test01.dat bs=4k seek=4 count=0
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000112075 s, 0.0 kB/s
[root@pg01 111]# ls -l
total 16
-rwxr-xr-x. 1 root root  8680 Feb  4 10:17 fibmap
-rw-r--r--. 1 root root  1280 Sep 26 18:40 fibmap.c
-rw-r--r--. 1 root root 16384 Feb  4 10:22 test01.dat


用stat命令看此文件,可以看到文件的“Size:16384”,而实际占用的数据块“Blocks: 0”:


[root@pg01 111]# stat test01.dat
  File: `test01.dat'
  Size: 16384     	Blocks: 0          IO Block: 4096   regular file
Device: fd00h/64768d	Inode: 135577      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2016-02-04 10:22:12.057957629 +0800
Modify: 2016-02-04 10:22:12.057957629 +0800
Change: 2016-02-04 10:22:12.057957629 +0800


用我们的工具fbmap查看此文件可以看到的信息如下:


[root@pg01 111]# ./fibmap test01.dat
Filename: test01.dat
Blocksize: 4096
Blocknum: 4
         0
         0
         0
         0


上面结果上最后的4行中显示了4个零,零表明没有分配实际的空间。下面我们创建一个有分配空间的稀疏文件,再看一下:


[root@pg01 111]# dd if=/dev/zero of=test02.dat bs=4k seek=4 count=2
2+0 records in
2+0 records out
8192 bytes (8.2 kB) copied, 0.000127822 s, 64.1 MB/s
[root@pg01 111]# ls -l
total 24
-rwxr-xr-x. 1 root root  8680 Feb  4 10:17 fibmap
-rw-r--r--. 1 root root  1280 Sep 26 18:40 fibmap.c
-rw-r--r--. 1 root root 16384 Feb  4 10:33 test01.dat
-rw-r--r--. 1 root root 24576 Feb  4 10:33 test02.dat
[root@pg01 111]# ./fibmap test02.dat
Filename: test02.dat
Blocksize: 4096
Blocknum: 6
         0
         0
         0
         0
    591870
    591871


可以看到最后两行有两个数字“591870”和“591871”,表明最后两个块是分配的实际的空间的。