2008-07-11

ディスクのフラグメント防止に関する興味深いペーパー

The Storage Team at Microsoft - File Cabinet Blog : New File Systems and Storage white papers, by Dilip Naik - MVP
ここの、Best Practices To Avoid Fragmentation While Writing To A Fileというペーパーが興味深い。
Sysinternals Contig

ソースコードが示されていないが、大方はこんな感じだろう。

BOOL SetPrivilege(
  LPCTSTR lpszPrivilege, // name of privilege to enable/disable
  BOOL bEnablePrivilege  // to enable or disable privilege
)
{
    LUID luid ;
    // lookup privilege on local
    if ( !LookupPrivilegeValue( NULL, lpszPrivilege, &luid ) )
    {
        return FALSE; 
    }
    
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
      tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
      tp.Privileges[0].Attributes = 0;
      
    // Get Current Process Token
    HANDLE hToken ;
    OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ;

    // Enable the privilege or disable all privileges.
    if ( !AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) )
    {
       return FALSE;
    }
    CloseHandle( hToken ) ;

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
       return FALSE;
    }

    return TRUE;
}


int main()
{
    // CreateFile
    HANDLE file = CreateFile( L"test.dat", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ) ;
    if ( file == INVALID_HANDLE_VALUE )
    {
        return 1 ;
    }
    
    // SetFilePointer to desired file size
    LARGE_INTEGER pointer ;
    pointer.QuadPart = 400 * 1024 ;
    SetFilePointerEx( file, pointer, NULL, FILE_BEGIN ) ;
    
    // SetEndOfFile
    SetEndOfFile( file ) ;
    
    // SetFileValidData
    SetPrivilege( SE_MANAGE_VOLUME_NAME, TRUE ) ;
    SetFileValidData( file, 400 * 1024 ) ;
    
    // SetFilePointer to beginning of file
    pointer.QuadPart = 0 ;
    SetFilePointerEx( file, pointer, NULL, FILE_BEGIN ) ;
    
    // WriteFile in a loop to fill the file with desired data
    // – the loop is executed 400 times and each pass through the loop issues a single 1024 byte WriteFile request.
    char buf[1024] ;
    memset( buf, 0, sizeof(buf) ) ;
    for ( int i = 0 ; i < 400 ; ++i )
    {
        DWORD unused ;
        WriteFile( file, buf, sizeof(buf), &unused, NULL ) ;
    }
    
    // CloseFile
    CloseHandle( file ) ;

    return 0;
}

なぜか管理者権限で実行しても、SetFileValidDataを呼び出した後のGetLastErrorに1314が帰ってきてしまう。しかし、SetFileValidData自体はエラーを返していないので、処理が失敗しているわけでもないのだろうか。ローカルポリシーで確認したが、たしかに、「ボリュームの保守タスクを実行」の権限に、Administratorsが入っている。それにしてもOSの説明が日本語になっているのは面倒だ。こういう部分は敢えて訳さなくてもいいと思うのだが。あるいは、Vistaの言語パックをいれて、英語にしてしまうべきか。

しかし不思議なことに、私の環境では、SetFileValidDataを呼び出さずとも、SetFilePointerとSetEndOfFileだけで、フラグメントは起こらなかった。

1 comment:

Anonymous said...

http://replay.web.archive.org/20080921022116/http://msftmvp.com/Documents/NTFSFrag.pdf