3

プロジェクトで、NTFS パーティション上のすべての空き/使用済みクラスターのリストを取得したいと考えています。このために、$Bitmap ファイルをダンプし、その内容を解析する必要があります。

Web 上には API とサンプルがほとんどありませんが、機能していないようです。$Bitmapファイルをどこかにコピーするだけの簡単な方法/コードサンプルはありますか?

FSCTL_GET_VOLUME_BITMAP を使用することが唯一の方法ですか? 理想的には、C# で実行したいと考えています。

4

2 に答える 2

1

直接読み取ろうとするのではなく、確実に簡単な方法で IOCTL を使用することをお勧めします$Bitmap。もちろん、誰かがやってくれたのなら、自分でやる必要はありません。MSDN のブロガーが、素敵な小さなラッパーを既に書いていることがわかりました。

http://blogs.msdn.com/b/jeffrey_wall/archive/2004/09/13/229137.aspx

クラス全体のコードは 300 行を超えているため、すべてを掲載することはできませんが、ボリューム ビットマップを取得する関数は次のとおりです。

    /// <summary>
    /// Get cluster usage for a device
    /// </summary>
    /// <param name="DeviceName">use "c:"</param>
    /// <returns>a bitarray for each cluster</returns>
    static public BitArray GetVolumeMap(string DeviceName)
    {
        IntPtr pAlloc = IntPtr.Zero;
        IntPtr hDevice = IntPtr.Zero;

        try
        {
            hDevice = OpenVolume(DeviceName);

            Int64 i64 = 0;

            GCHandle handle = GCHandle.Alloc(i64, GCHandleType.Pinned);
            IntPtr p = handle.AddrOfPinnedObject();

            // alloc off more than enough for my machine
            // 64 megs == 67108864 bytes == 536870912 bits == cluster count
            // NTFS 4k clusters == 2147483648 k of storage == 2097152 megs == 2048 gig disk storage
            uint q = 1024 * 1024 * 64; // 1024 bytes == 1k * 1024 == 1 meg * 64 == 64 megs

            uint size = 0;
            pAlloc = Marshal.AllocHGlobal((int)q);
            IntPtr pDest = pAlloc;

            bool fResult = DeviceIoControl(
                hDevice,
                FSConstants.FSCTL_GET_VOLUME_BITMAP,
                p,
                (uint)Marshal.SizeOf(i64),
                pDest,
                q,
                ref size,
                IntPtr.Zero);

            if (!fResult)
            {
                throw new Exception(Marshal.GetLastWin32Error().ToString());
            }
            handle.Free();

            /*
            object returned was...
      typedef struct 
      {
       LARGE_INTEGER StartingLcn;
       LARGE_INTEGER BitmapSize;
       BYTE Buffer[1];
      } VOLUME_BITMAP_BUFFER, *PVOLUME_BITMAP_BUFFER;
            */
            Int64 StartingLcn = (Int64)Marshal.PtrToStructure(pDest, typeof(Int64));

            Debug.Assert(StartingLcn == 0);

            pDest = (IntPtr)((Int64)pDest + 8);
            Int64 BitmapSize = (Int64)Marshal.PtrToStructure(pDest, typeof(Int64));

            Int32 byteSize = (int)(BitmapSize / 8);
            byteSize++; // round up - even with no remainder

            IntPtr BitmapBegin = (IntPtr)((Int64)pDest + 8);

            byte[] byteArr = new byte[byteSize];

            Marshal.Copy(BitmapBegin, byteArr, 0, (Int32)byteSize);

            BitArray retVal = new BitArray(byteArr);
            retVal.Length = (int)BitmapSize; // truncate to exact cluster count
            return retVal;
        }
        finally
        {
            CloseHandle(hDevice);
            hDevice = IntPtr.Zero;

            Marshal.FreeHGlobal(pAlloc);
            pAlloc = IntPtr.Zero;
        }
    }
于 2012-04-25T06:28:25.680 に答える
1

「OEM サポート ツール」の (以前は) 一部であった NFI.EXE は、すべての NTFS パーティション項目を列挙できます。$Bitmap のコンテンツをダンプすることもできます。

ここに画像の説明を入力

于 2012-04-26T07:47:50.660 に答える