7

ファイル記述子またはファイル名が与えられた場合、介在する部分がディスク上で明示的に消去されるのを待たずに、任意の場所に書き込めるかどうかをどのように知ることができますか?

4

2 に答える 2

3

ファイルをstat()使用してファイル サイズとディスク ブロック数を取得し、ファイルの末尾を越えて比較的少数のディスク ブロックをシークし、既知の数のブロックを書き込んでから、ファイルを再度 stat することができます。ディスク ブロックの元の数と最終的な数を比較します。ファイル システムがスパース ファイルをサポートしていない場合、ほんの数個のディスク ブロックの書き込みに時間がかかりすぎないようにする必要があります。

元のディスク ブロック数と最終的なディスク ブロック数を考慮して、ファイル システムがスパース ファイルをサポートしているかどうかを判断します。一部のファイルシステムではこれが困難になる可能性があるため、「試してください」と言います。たとえば、圧縮が有効になっているZFSなどです。

このようなもの:

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

int check( const char *filename )
{
    struct stat sb;
    long blocksize;
    off_t filesize;
    blkcnt_t origblocks;
    char *buffer;
    int fd;

    fd = open( filename, O_CREAT | O_RDWR, 0644 );

    fstat( fd, &sb );
    blocksize = sb.st_blksize;
    filesize = sb.st_size;
    origblocks = sb.st_blocks;

    lseek( fd, 16UL * blocksize, SEEK_END );

    buffer = malloc( blocksize );
    memset( buffer, 0xAA, blocksize );

    write( fd, buffer, blocksize );
    fsync( fd );

    free( buffer );

    // kludge to give ZFS time to update metadata
    for ( ;; )
    {
        stat( filename, &sb );
        if ( sb.st_blocks != origblocks )
        {
            break;
        }
    }

    printf( "file: %s\n filesystem: %s\n blocksize: %d\n size: %zd\n"
        " blocks: %zd\n orig blocks: %zd\n disk space: %zd\n",
        filename, sb.st_fstype, blocksize, sb.st_size,
        ( size_t ) sb.st_blocks, ( size_t ) origblocks,
        ( size_t ) ( 512UL * sb.st_blocks ) );

    // return file to original size
    ftruncate( fd, filesize );
    return( 0 );
}

int main( int argc, char **argv )
{
    for ( int ii = 1; ii < argc; ii++ )
    {
        check( argv[ ii ] );
    }

    return( 0 );
}

(わかりやすくするために、エラー チェックは省略されています)

圧縮が有効になっている ZFS は、ファイルのメタデータをすばやく更新していないように見えるため、変更が表示されるのを待って回転します。

asdfファイル(ZFS ファイルシステム、圧縮が有効) /tmp/asdf(tmpfs ファイルシステム)、および(ZFS、圧縮なし) を使用して Solaris 11 ボックスで実行すると/var/tmp/asdf、そのコードは次の出力を生成します。

file: asdf
 filesystem: zfs
 blocksize: 131072
 size: 2228224
 blocks: 10
 orig blocks: 1
 disk space: 5120
file: /tmp/asdf
 filesystem: tmpfs
 blocksize: 4096
 size: 69632
 blocks: 136
 orig blocks: 0
 disk space: 69632
file: /var/tmp/asdf
 filesystem: zfs
 blocksize: 131072
 size: 2228224
 blocks: 257
 orig blocks: 1
 disk space: 131584

その出力から、/tmp/asdfはスパース ファイルをサポートしないファイル システム上にあり、そのようなファイルをサポートするファイル システム内にあることが明らか/var/tmp/asdfです。

そして、plainasdfはまったく別のものにあり、128 kB のデータを書き込むと 9,512 バイトのディスク ブロックがすべて追加されます。このことから、ファイルシステムで何らかの圧縮が行われていることが推測できます。率直に言って、このようなネイティブ圧縮をサポートするファイルシステムは、スパースファイルもサポートすると想定するのがかなり安全だと思います。

また、ファイル名または開いているファイル記述子を指定したときに、ファイルシステムがスパース ファイルをサポートしているかどうかを判断する最も速い方法は、ファイル名またはファイル記述子で を呼び出しstat()、からフィールドをfstat()取得し、ファイルのファイル システム タイプを一連の文字列と比較することです。スパース ファイルをサポートすることが知られているファイル システム タイプ。st_fstypestruct stat

于 2016-08-02T13:33:22.197 に答える