Проблемы с DeviceIoControl FSCTL_GET_RETRIEVAL_POINTERS
От: realand  
Дата: 23.11.08 11:37
Оценка:
Получаю цепочку кластеров файлика с NTFS раздела. Копирую на винт все замечательно.
Пытаюсь проделать тоже самое с файликом на fat32, часть файла является мусором
Опытным путем выяснил, что смещение верхушки в результирующем файле составляет 4096 байта.
В чем может быть проблема при работе с FAT32?
размер таблицы фат? и как это пофиксить. Ниже представлен код копирующий файл.

используем таги ccode & asm для выделения кусков кода. пример см ниже — модератор

//функция для получения цепочки кластеров по имени файла.
ULONGLONG *GetFileClusters(
                    PCHAR lpFileName,
                    ULONG ClusterSize, 
                    ULONG *ClCount,
                    ULONG *FileSize 
                    )
{
    HANDLE  hFile;
    ULONG   OutSize;
    ULONG   Bytes, Cls, CnCount, r;
    ULONGLONG *Clusters = NULL;
    BOOLEAN Result = FALSE;
    LARGE_INTEGER PrevVCN, Lcn;
    STARTING_VCN_INPUT_BUFFER  InBuf;
    PRETRIEVAL_POINTERS_BUFFER OutBuf;

    hFile = CreateFile(lpFileName, FILE_READ_ATTRIBUTES,
                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                       NULL, OPEN_EXISTING, 0, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        *FileSize = GetFileSize(hFile, NULL);

        OutSize = sizeof(RETRIEVAL_POINTERS_BUFFER) + (*FileSize / ClusterSize) * sizeof(OutBuf->Extents);

        OutBuf = (PRETRIEVAL_POINTERS_BUFFER)malloc( OutSize );

        InBuf.StartingVcn.QuadPart = 0;
        
        if (DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, &InBuf, 
                            sizeof(InBuf), OutBuf, OutSize, &Bytes, NULL))
        {
            *ClCount = (*FileSize + ClusterSize - 1) / ClusterSize;

            Clusters = (ULONGLONG*)malloc(*ClCount * sizeof(ULONGLONG));

            PrevVCN = OutBuf->StartingVcn;

            for (r = 0, Cls = 0; r < OutBuf->ExtentCount; r++)
            {
                Lcn = OutBuf->Extents[r].Lcn;

                for (CnCount = (ULONG)(OutBuf->Extents[r].NextVcn.QuadPart - PrevVCN.QuadPart);
                     CnCount; CnCount--, Cls++, Lcn.QuadPart++) Clusters[Cls] = Lcn.QuadPart;

                PrevVCN = OutBuf->Extents[r].NextVcn;
            }
        }
    
        free(OutBuf);    

        CloseHandle(hFile);
    }
    return Clusters;
}

//непосредственно копиривание файла
        hDrive = CreateFile(Name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);

        if (hDrive != INVALID_HANDLE_VALUE)
        {
            hFile = CreateFile(lpDstName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0);

            if (hFile != INVALID_HANDLE_VALUE)
            {
                Buff_Read = malloc(ClusterSize);       

                for (r = 0; r < ClCount; r++, FileSize -= BlockSize)
                {
            Offset.QuadPart = (ClusterSize * Clusters[r]);
            printf( "%d\n", Offset.QuadPart );

            SetFilePointer(hDrive, Offset.LowPart, &Offset.HighPart, FILE_BEGIN);
            ReadFile(hDrive, Buff_Read, ClusterSize, &Bytes, NULL);

            BlockSize = FileSize < ClusterSize ? FileSize : ClusterSize;
            WriteFile(hFile, Buff_Read, BlockSize, &Bytes, NULL);

                }//end_ for_ r

                free(Buff_Read);
                //free(Buff);

                CloseHandle(hFile);
            }
            CloseHandle(hDrive);
        }


первоисточник: http://www.wasm.ru/article.php?article=lockfileswork
Re: Проблемы с DeviceIoControl FSCTL_GET_RETRIEVAL_POINTERS
От: Denwer Россия  
Дата: 23.11.08 13:37
Оценка:
Здравствуйте, realand, Вы писали:

R>Получаю цепочку кластеров файлика с NTFS раздела. Копирую на винт все замечательно.

R>Пытаюсь проделать тоже самое с файликом на fat32, часть файла является мусором
R>Опытным путем выяснил, что смещение верхушки в результирующем файле составляет 4096 байта.
R>В чем может быть проблема при работе с FAT32?
R>размер таблицы фат? и как это пофиксить. Ниже представлен код копирующий файл.

А можно вопрос, зачем это нада? Ну точнее как будит использоваться? Просто на вид вещь то полезная, но как оказывается не всегда. Разве что скопировать залоченные файлы реестра.
Re[2]: Проблемы с DeviceIoControl FSCTL_GET_RETRIEVAL_POINTE
От: realand  
Дата: 23.11.08 13:43
Оценка:
Здравствуйте, Denwer, Вы писали:

D>Здравствуйте, realand, Вы писали:


R>>Получаю цепочку кластеров файлика с NTFS раздела. Копирую на винт все замечательно.

R>>Пытаюсь проделать тоже самое с файликом на fat32, часть файла является мусором
R>>Опытным путем выяснил, что смещение верхушки в результирующем файле составляет 4096 байта.
R>>В чем может быть проблема при работе с FAT32?
R>>размер таблицы фат? и как это пофиксить. Ниже представлен код копирующий файл.

D>А можно вопрос, зачем это нада? Ну точнее как будит использоваться? Просто на вид вещь то полезная, но как оказывается не всегда. Разве что скопировать залоченные файлы реестра.


Ну с помощью этой бодяги можно читать любой залоченый файл.
На диске C Винда и фат32 время от времени бекаплю под досом системные файлы реестра. Все.
Оч помогает если система трапнулась или надо откатится. Спасало не раз. А ответ по существу? слабо?
Re: Проблемы с DeviceIoControl FSCTL_GET_RETRIEVAL_POINTERS
От: MShura  
Дата: 23.11.08 14:17
Оценка: 1 (1)
R>Получаю цепочку кластеров файлика с NTFS раздела. Копирую на винт все замечательно.
R>Пытаюсь проделать тоже самое с файликом на fat32, часть файла является мусором
R>Опытным путем выяснил, что смещение верхушки в результирующем файле составляет 4096 байта.
R>В чем может быть проблема при работе с FAT32?
R>размер таблицы фат? и как это пофиксить. Ниже представлен код копирующий файл.

R> Offset.QuadPart = (ClusterSize * Clusters[r]);

R> printf( "%d\n", Offset.QuadPart );

R> SetFilePointer(hDrive, Offset.LowPart, &Offset.HighPart, FILE_BEGIN);

R> ReadFile(hDrive, Buff_Read, ClusterSize, &Bytes, NULL);

Нумерация кластеров на FAT начинается не от начала тома.
Область данных начинается после области boot + области фат(ов) + (область корневой директории на FAT12/16)

4096 байт для такой области маловато (разве только для дискеты)
Чтобы это пофиксить необходимо к Offset добавить эту область.
Как вычислить эту область? Прочитайте спецификацию на FAT.
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc
Re[2]: Проблемы с DeviceIoControl FSCTL_GET_RETRIEVAL_POINTE
От: realand  
Дата: 24.11.08 17:57
Оценка:
Здравствуйте, MShura, Вы писали:

Правила форума нарушены.
— оверквотинг
Правила можно найти в разделе FAQ данного форума и\или ресурса.
Нарушение правил может повлечь за собой санкции, описанные там же — модератор

MS>Нумерация кластеров на FAT начинается не от начала тома.

MS>Область данных начинается после области boot + области фат(ов) + (область корневой директории на FAT12/16)

MS>4096 байт для такой области маловато (разве только для дискеты)

MS>Чтобы это пофиксить необходимо к Offset добавить эту область.
MS>Как вычислить эту область? Прочитайте спецификацию на FAT.
MS>http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc

Спасибо. То что надо.
Сейчас занимаюсь реализацией.
Если у кого есть готовый работающий пример буду премного благодарен
Re[3]: Проблемы с DeviceIoControl FSCTL_GET_RETRIEVAL_POINTE
От: MShura  
Дата: 24.11.08 20:42
Оценка:
MS>>Нумерация кластеров на FAT начинается не от начала тома.
MS>>Область данных начинается после области boot + области фат(ов) + (область корневой директории на FAT12/16)

R>Спасибо. То что надо.

R>Сейчас занимаюсь реализацией.
R>Если у кого есть готовый работающий пример буду премного благодарен

Примерно так:
typedef struct BIOS_PARAMETER_BLOCK {
    USHORT BytesPerSector;
    UCHAR  SectorsPerCluster;
    USHORT ReservedSectors;
    UCHAR  Fats;
    USHORT RootEntries;
    USHORT Sectors;
    UCHAR  Media;
    USHORT SectorsPerFat;
    USHORT SectorsPerTrack;
    USHORT Heads;
    ULONG32  HiddenSectors;
    ULONG32  LargeSectors;
    ULONG32  LargeSectorsPerFat;
    union {
        USHORT ExtendedFlags;
        struct {
            ULONG ActiveFat:4;
            ULONG Reserved0:3;
            ULONG MirrorDisabled:1;
            ULONG Reserved1:8;
        };
    };
    USHORT FsVersion;
    ULONG32 RootDirFirstCluster;
    USHORT FsInfoSector;
    USHORT BackupBootSector;
} BIOS_PARAMETER_BLOCK, *PBIOS_PARAMETER_BLOCK;

//
//  Define the boot sector
//

typedef struct _PACKED_BOOT_SECTOR {
    UCHAR Jump[3];                                  // offset = 0x000   0
    UCHAR Oem[8];                                   // offset = 0x003   3
    PACKED_BIOS_PARAMETER_BLOCK PackedBpb;          // offset = 0x00B  11
    UCHAR PhysicalDriveNumber;                      // offset = 0x024  36
    UCHAR CurrentHead;                              // offset = 0x025  37
    UCHAR Signature;                                // offset = 0x026  38
    UCHAR Id[4];                                    // offset = 0x027  39
    UCHAR VolumeLabel[11];                          // offset = 0x02B  43
    UCHAR SystemId[8];                              // offset = 0x036  54
} PACKED_BOOT_SECTOR; 

// Не забудьте про упаковку
C_ASSERT( 0x0E == FIELD_OFFSET( PACKED_BOOT_SECTOR, PackedBpb.ReservedSectors ) );
C_ASSERT( 0x10 == FIELD_OFFSET( PACKED_BOOT_SECTOR, PackedBpb.Fats ) );
C_ASSERT( 0x24 == FIELD_OFFSET( PACKED_BOOT_SECTOR, PackedBpb.LargeSectorsPerFat) );


Если взять за основу приведенные структуры, то на x86 платформах на дисках с 512 байтным сектором начало данных будет вычисляться по такой формуле

union{
PACKED_BOOT_SECTOR boot;
UCHAR BootSector [512];
};

//
// Прочитать 512 байт со смещения 0 тома (не диска!) в область BootSector
//
...

ULONG ZeroLcnOffset = boot.PackedBpb.ReservedSectors;

if ( 0 == boot.PackedBpb.SectorsPerFat )
{
  // FAT32
  ZeroLcnOffset += boot.PackedBpb.Fats * boot.PackedBpb.LargeSectorsPerFat;
}
else
{
  // FAT16/12
  ZeroLcnOffset += boot.PackedBpb.Fats * (ULONG)boot.PackedBpb.SectorsPerFat;
  ZeroLcnOffset += (boot.PackedBpb.RootEntries * 32 + 511 ) >> 9;
}
ZeroLcnOffset <<= 9;


В принципе приведенный код будет работать и на не x86 платформах.
Обратите внимание, что хотя в FAT нумерация кластеров LCN начинается с 2, FSCTL_GET_RETRIEVAL_POINTERS вертает 0 based.

P.S. Писал без проверок.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.