2011-12-31 11 views
2

私は50MiBの小さなパーティションを持ち、ext4形式になっています。/mnt/tmpにマウントされています。ファイルシステムのstatvfs()で計算された使用済みスペースは、fsファイル内のすべてのファイルのサイズの合計よりも大きいです。

その後、私はstatvfs()を使用するためのパーティションで使用されるバイトを計算し、lstat()のための内部のすべてのファイルのサイズを計算し、このために私はこのプログラムを書いた:

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <sys/statvfs.h> 
#include <stdint.h> 
#include <string.h> 
#include <dirent.h> 
#include <stdlib.h> 

//The amount of bytes of all files found 
uint64_t totalFilesSize=0; 

//Size for a sector in the fs 
unsigned int sectorSize=0; 

void readDir(char *path) { 
    DIR *directory; 
    struct dirent *d_file; // a file in *directory 

    directory = opendir (path); 

    while ((d_file = readdir (directory)) != 0) 
    { 
     struct stat filestat; 
     char *abPath=malloc(1024); 
     memset(abPath, 0, 1024); 
     strcpy(abPath, path); 
     strcat(abPath, "/"); 
     strcat(abPath, d_file->d_name); 

     lstat (abPath, &filestat); 

     switch (filestat.st_mode & S_IFMT) 
     { 
     case S_IFDIR: 
     { 
      if (strcmp (".", d_file->d_name) && strcmp ("..", d_file->d_name)) 
      { 
       printf("File: %s\nSize: %d\n\n", abPath, filestat.st_size); 

       //Add slack space to the final sum 
       int slack=sectorSize-(filestat.st_size%sectorSize); 

       totalFilesSize+=filestat.st_size+slack; 

       readDir(abPath); 
      } 
      break; 
     } 
     case S_IFREG: 
     { 
      printf("File: %s\nSize: %d\n\n", abPath, filestat.st_size); 

      //Add slack space to the final sum 
      int slack=sectorSize-(filestat.st_size%sectorSize); 

      totalFilesSize+=filestat.st_size+slack; 

      break; 
     } 
     } 

     free(abPath); 
    } 

    closedir (directory); 
} 

int main (int argc, char **argv) { 

    if(argc!=2) { 
     printf("Error: Missing required parameter.\n"); 
     return -1; 
    } 

    struct statvfs info; 
    statvfs (argv[1], &info); 

    sectorSize=info.f_bsize; //Setting global variable 

    uint64_t usedBytes=(info.f_blocks-info.f_bfree)*info.f_bsize; 

    readDir(argv[1]); 

    printf("Total blocks: %d\nFree blocks: %d\nSize of block: %d\n\ 
Size in bytes: %d\nTotal Files size: %d\n", 
      info.f_blocks, info.f_bfree, info.f_bsize, usedBytes, totalFilesSize); 

    return 0; 
} 

は、パーティションのマウントポイントを渡すとパラメータ(/ mnt/tmp)を指定すると、次の出力が表示されます。

File: /mnt/tmp/lost+found 
Size: 12288 

File: /mnt/tmp/photos 
Size: 1024 

File: /mnt/tmp/photos/IMG_3195.JPG 
Size: 2373510 

File: /mnt/tmp/photos/IMG_3200.JPG 
Size: 2313695 

File: /mnt/tmp/photos/IMG_3199.JPG 
Size: 2484189 

File: /mnt/tmp/photos/IMG_3203.JPG 
Size: 2494687 

File: /mnt/tmp/photos/IMG_3197.JPG 
Size: 2259056 

File: /mnt/tmp/photos/IMG_3201.JPG 
Size: 2505596 

File: /mnt/tmp/photos/IMG_3202.JPG 
Size: 2306304 

File: /mnt/tmp/photos/IMG_3204.JPG 
Size: 2173883 

File: /mnt/tmp/photos/IMG_3198.JPG 
Size: 2390122 

File: /mnt/tmp/photos/IMG_3196.JPG 
Size: 2469315 

Total blocks: 47249 
Free blocks: 19160 
Size of block: 1024 
Size in bytes: 28763136 
Total Files size: 23790592 

最後の2行に注意してください。 FAT32ファイルシステムでは、量は同じですが、ext4では異なります。

質問:なぜですか?

+2

statvfsのマンページから:「返された構造体のすべてのメンバーがすべてのファイルシステム上で意味のある値を持つかどうかは不明です。 – fge

+0

@fge oopsなので、fsで使用されるバイトの信頼できる量を得る方法はありませんか?答えに感謝します。 – jlledom

+1

まあ、あなたができることは、 'df'がやることです - 私はそれがどのように空間を計算するのか分かりません。以下の答えによれば、スパースファイルなどもあります。また、削除されていてもまだ開いているファイルの場合を考えてみましょう。ディスクスペースは必要ですが、ディレクトリには表示されません。 – fge

答えて

4

statvfs()ファイルシステムレベルの動作です。使用されるスペースは、ファイルシステムの観点から計算されます。したがって:inodes and any indirect blocks含まUnixの伝統的なデザインから、に基づいてファイルシステムの場合:

  1. は、これは、任意のファイルシステムの構造が含まれています。

    私のシステムの中には、通常、ルートパーティションのための32KBのスペースごとに256バイトのinodeがあります。より小さいパーティションは、より多くのファイルに対して十分なinodeを提供するために、より高いinode密度を持つかもしれません - 私はmke2fsのデフォルトが16KBのスペースごとに1つのinodeであると信じています。

    デフォルトオプションを使用して850 MBのExt4ファイルシステムを作成すると、約54,000のinodeを持つファイルシステムが生成され、13 MBを超える容量が消費されます。

  2. また、ファイルシステムブロックの最小サイズが1024のジャーナルも含まれるExt3/Ext4の場合。共通ブロックサイズが4KBの場合、ファイルシステムごとに最低でも4MBのです。

    850 MBのExt4ファイルシステムは、デフォルトで16MBのジャーナルを持ちます。

  3. statvfs()の結果には、削除されたまだ開いているファイルも含まれます。これは、アプリケーションで使用するためにtmpディレクトリを格納するパーティションでよく発生します。 lstat()でファイルによって使用される実際の容量を確認するには

  4. 、あなたはどのst_sizeフィールドを使用している、stat構造のst_blocksフィールドを使用して、あなたのプログラムの出力に表示されるサイズで512ジャッジで乗算する必要がありますバイト単位の正確なファイルサイズです。これは通常、使用されている実際のスペースよりも小さくなります.5KBファイルは、実際には4KBブロックのファイルシステムで8KBを使用します。

    逆に、スパースファイルは、ファイルサイズで示されるものより少ないブロックを使用します。

そのため、上記の追加のスペースの使用量は、追加アップします、あなたが見ている矛盾を説明するために、むしろ目立つ額を、。

EDIT:

  1. 私はちょうどあなたのプログラムのたるみスペースの取り扱いに気づきました。それはではありません。実際の使用スペースを計算するには(見た目とは対照的に)推奨される方法ですが、動作するように見えるので、そこにスペースがありません。一方、ファイルシステムのルートディレクトリに使用されているスペースはありませんが、それはおそらく単一のブロックか2つしかないでしょう:-)

  2. tune2fs -l /dev/xxxの出力を見たいかもしれません。 。ファイルシステムのメタデータ用に確保されたスペースを含む、いくつかの関連する番号をリストします。

ところで、あなたのプログラム内の機能のほとんどはdfduを使用して達成することができます。ちなみに

# du -a --block-size=1 mnt/ 
2379776 mnt/img0.jpg 
3441664 mnt/img1.jpg 
2124800 mnt/img2.jpg 
12288 mnt/lost+found 
7959552 mnt/ 
# df -B1 mnt/ 
Filesystem  1B-blocks  Used Available Use% Mounted on 
/dev/loop0  50763776 12969984 35172352 27% /tmp/mnt 

は、上記表示Ext4のテストファイルシステムは、50メガバイトの画像にデフォルトにmkfsオプションを使用して作成されましたファイル。これは1,024バイトのブロックサイズ、1,603KBを消費する12,824の128バイトのinode、4,096KBを使用する4096ブロックのジャーナルを持ちます。 tune2fsによると、さらに199個のブロックがグループ記述子テーブルのために予約されている。

+0

偉大な答え、質問は解決されます。 – jlledom

+0

このプログラムは、私がこの問題を説明する準備をしたことを証明しているので、同じことをするための他の選択肢がある現実世界では使用しません。私の本当の問題は、別のプログラムでプログレスバーを作ろうとしていることです.100%で終了することはなく、ファイルのコピーが終了すると、バーはこの問題のために85%で停止します。 – jlledom

3

iノードはおそらくカウントされず、小さなデータが含まれている可能性があります。

ファイルが疎である場合、ファイルのサイズは実際に占有されているサイズよりも大きくなります。

ファイルが複数回ハードリンクされている場合は、共通のiノードが共有されます。

Ext4の約紙はhere, by Kumar et al

+0

私は9つのパーティションを持つ800MiBのハードドライブで同様のテストを行い、その結果は40MiB以上の違いがあります。私はinodeにはあまりにも多いと思いますか?小さなファイルの空き領域の問題は、プログラムで修正されています。この例ではハードリンクはなく、通常のファイルしかありません。 – jlledom

+0

この文は次のとおりです。「ファイルが疎である場合、ファイルのサイズは実際に占有されているサイズよりも小さくなります。偽です。反対の場合は真です。 –

+0

正しい。ありがとう。 –

関連する問題