Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Расположение заблокированного файла на диске. [D7, NT4, Win2k, WinXP]


Страницы:   1 2

Семен Сорокин ©   (2005-06-22 18:06:00) 

Приветствую гуру, кто может подсказать как получить покластерное расположение заблокированного файла на диске, например pagefile.sys (NT4, W2k, XP). Не блокированные файлы просмотриваю с помощью ф-ии DeviceIoControl с управляющим кодом FSCTL_GET_RETRIEVAL_POINTERS, но дело в том что там входным параметром используется Handle открытого файла, а если он заблокирован, то этот Handle не удасться получить.

С уважением, Семен.


NikNet   (2005-06-24 20:32:00) [1]

Удалено модератором


Игорь Шевченко   (2005-06-24 14:19:00) [2]

BiN ©   (24.06.05 14:14) [24]


> Что я делаю не так?


Знаешь заранее, что это не pipe.


BiN   (2005-06-24 14:14:00) [3]

Игорь Шевченко ©   (24.06.05 12:52) [20]

Только вот при дублировании файловых хэндлов ты можешь повиснуть.


Почему-то при работе с файлами FS (не с пайпами) добиться зависания не удалось. Что я делаю не так?


BiN   (2005-06-24 13:35:00) [4]

Семен Сорокин ©   (24.06.05 13:05) [21]

Можешь предложить иной выход? :))


Внедрение?
Не очень красивый метод, но зато можно обойтись без DuplicateHandle.


Игорь Шевченко   (2005-06-24 13:15:00) [5]

Семен Сорокин ©   (24.06.05 13:05) [21]


> где про эти проблемы можно почитать?


Гэри Неббет, справочник по функциям базового API Windows 2000/NT


Семен Сорокин   (2005-06-24 13:05:00) [6]


> BiN ©   (24.06.05 12:42) [19]
> Алгоритм-то реализуем, но стоит ли овчинка?

Можешь предложить иной выход? :))

> Игорь Шевченко ©   (24.06.05 12:52) [20]
> Реализуем. Только вот при дублировании файловых хэндлов
> ты можешь повиснуть. Это проблема широко известна.

хм. даже если дублировать с минимальными правами: FILE_SHARE_READ + FILE_SHARE_WRITE?

а можно поподробней? где про эти проблемы можно почитать?


Игорь Шевченко   (2005-06-24 12:52:00) [7]


> интересует мнение, реализуем ли такой алгоритм?


Реализуем. Только вот при дублировании файловых хэндлов ты можешь повиснуть. Это проблема широко известна.


BiN   (2005-06-24 12:42:00) [8]

Семен Сорокин ©   (24.06.05 12:33) [18]

Алгоритм-то реализуем, но стоит ли овчинка?


Семен Сорокин   (2005-06-24 12:33:00) [9]


> А кстати, вопрос такой - нафига тебе надо покластерное расположение
> pagefile.sys ?

Мне нужно нарисовать карту диска, и разукрасить ее различными цветами (по типу O&O Defrag: фрагментированные/дефрагментированные/сжаты/системные/... файлы) с основной задачей справился, за одним исключением (сабж)...

Тут в голову пришла другая идея для получения Locked file handle:
 - Перебирать все процессы (искать заблокировавший данный файл
   процесс (для Pagefile.sys - system))
 - Перебирать все handle этого процесса
 - находить handle имя которого pagefile
 - делаеть DuplicateHandle

интересует мнение, реализуем ли такой алгоритм? и с какими трудностями я могу сттолкнуться? :)


Игорь Шевченко   (2005-06-23 19:28:00) [10]

Семен Сорокин ©   (23.06.05 10:38) [16]


>  файл заблокирован системой, Файловая система FAT32


Для fat32 тебе не обязательно открывать файл. Открой диск, прочитай корневой каталог, найди там цепочки для pagefile.sys и будет тебе счастье. Правда, счастье будет неполным, если размер файла автоматически устанавливается системой, так как реальные кластеры, отведенные под него, в данный конкретный момент находятся в кэше.

А кстати, вопрос такой - нафига тебе надо покластерное расположение pagefile.sys ?


Семен Сорокин   (2005-06-23 10:38:00) [11]

>Kerk

спасибо, только это немного не то: у меня есть имя файла 'f:\pagefile.sys', покластерного распложения нет (!), файл заблокирован системой, Файловая система FAT32

>MS-MEN

ок, отправил мылом


Kerk   (2005-06-23 10:30:00) [12]

function ReadSectorsNT(DriveNumber: Byte; StartingSector, SectorCount: DWORD;
 Buffer: Pointer): DWORD;
var
 hFile: THandle;
 br,TmpLo,TmpHi: DWORD;
begin
 Result := 0;
 hFile := CreateFile(PChar('\\.\PhysicalDrive'+IntToStr(DriveNumber)),
   GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
 if hFile = INVALID_HANDLE_VALUE then Exit;
 TmpLo := __Mul(StartingSector,
   PhysicalDrives[DriveNumber].DiskGeometry.BytesPerSector,TmpHi);
 if SetFilePointer(hFile,TmpLo,@TmpHi,FILE_BEGIN) = TmpLo then
 begin
   SectorCount := SectorCount*PhysicalDrives[DriveNumber].DiskGeometry.BytesPerSector;
   if not ReadFile(hFile,Buffer^,SectorCount,br,nil) then Exit;
   Result := br;
 end;
 CloseHandle(hFile);
end;

из http://kladovka.net.ru/index.cgi?pid=list&rid=9


MS-MEN   (2005-06-23 10:28:00) [13]

Семен Сорокин ©   (23.06.05 10:20) [12]
Как? какие функции использовать? или в какую сторону хотя бы копать в MSDN?

Сегодня на мыло мне MS-MEN@yandex.ru просто сейчас лень копатся.

Я тебе скину свой модуль IODISK.PAS через него ты не только
можешь копатся в файлах но и даже Scandisk можешь сделать )


Kerk   (2005-06-23 10:22:00) [14]

Семен Сорокин ©   (23.06.05 10:20) [12]
или в какую сторону хотя бы копать в MSDN?


все тот же CreateFile/ReadFile
если номера кластеров есть, то проблем быть не должно.


Семен Сорокин   (2005-06-23 10:20:00) [15]


> MS-MEN ©   (23.06.05 10:18) [11]
>
> Обращайся к нему физ.


Как? какие функции использовать? или в какую сторону хотя бы копать в MSDN?


MS-MEN   (2005-06-23 10:18:00) [16]

> Семен Сорокин

Обращайся к нему физ.


Семен Сорокин   (2005-06-23 10:13:00) [17]

>MS-MEN ©

Благодарю за проявленный интерес к ветке, но проблему этот код не разрешает, дело в том что в функции DF_GetFileClusters используется все тот-же незамысловатый CreateFile, который на заблокированный файл типа pagefile.sys вернет INVALID_HANDLE_VALUE и функция не сработает. :(

Еще раз спасибо за код, почерпнул пару моментов.


MS-MEN   (2005-06-23 07:09:00) [18]

function DF_Access (const FileName : string; FileOffset : Int64; Size : Cardinal; Buf : Pointer; IsRead : Boolean) : Boolean;
var
 ClusterSize, Offset, BlockSize : Cardinal;
 Clusters : TClusterList;
 hDrive : THandle;
 ClusterNo, AbsOffset, FileSize, Cluster0Offset : Int64;
 AccessRights, FileFlags, Tmp : DWORD;
 ClusterBuf : Pointer;
 FileSystem : array [0..255] of Char;
 BootSector : PFAT32BootSector absolute ClusterBuf;
 
begin
 Result := False;
 if (FileOffset < 0) or (Size <= 0) then Exit;

//------------------------------------------------------------------------------
// Получение размера кластера

 ClusterSize := DF_GetClusterSize (FileName);
 if ClusterSize = 0 then Exit;

//------------------------------------------------------------------------------
// Получение списка кластеров, занимаемых файлом

 Result := DF_GetFileClusters (FileName, Clusters);
 if not Result then Exit;

//------------------------------------------------------------------------------
// Открытие устройства для операции чтения/записи

 AccessRights := FILE_READ_DATA;
 if not IsRead then AccessRights := AccessRights or FILE_WRITE_DATA;

 FileFlags := FILE_FLAG_RANDOM_ACCESS;
 if not IsRead then FileFlags := FileFlags or FILE_FLAG_WRITE_THROUGH;
//  FileFlags := FileFlags or FILE_FLAG_NO_BUFFERING;

 hDrive := CreateFile (PChar('\\.\' + DF_GetDrive(FileName)),
                       AccessRights,
                       FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
                       nil,
                       OPEN_EXISTING,
                       FileFlags,
                       0);
 if hDrive = INVALID_HANDLE_VALUE then Exit;

//------------------------------------------------------------------------------
// Получение инфы о диске, в частности - файловая система

 if not GetVolumeInformation (PChar(DF_GetDrive(FileName) + '\'),
                              nil,
                              0,
                              nil,
                              Tmp,
                              Tmp,
                              @FileSystem[0],
                              SizeOf(FileSystem)) then Exit;

// VirtualAlloc хорош тем, что буфер выровнен по странице памяти
 ClusterBuf := VirtualAlloc (nil, ClusterSize, MEM_COMMIT, PAGE_READWRITE);

//------------------------------------------------------------------------------
// Вычисление смещения нулевого кластера относительно начала раздела

// На NTFS'ах нулевой кластер начинается с 0 сектора раздела...
// А на FAT'ах - после таблиц размещения файлов...

 Cluster0Offset := 0;
 if Copy(FileSystem, 1, 3) = 'FAT' then
 begin
// чтение bootsector'а (0 сектор)
   SetFilePointer (hDrive, 0, nil, FILE_BEGIN);
   ReadFile (hDrive, ClusterBuf^, 512, Tmp, nil);

   with BootSector^ do
// FAT32 (тестил)
     if FileSystem[3] = '3' then Cluster0Offset := ResSecs + (FatCnt * FatSize32)

// FAT16 (не тестил) - юзать на свой риск и страх!!!
     else Cluster0Offset := ResSecs + (FatCnt * FatSize);

   Cluster0Offset := Cluster0Offset * BootSector.SectSiz;
 end;

//------------------------------------------------------------------------------
// Мало ли прочитать хотят больше, чем есть в файле ?

 FileSize := DF_GetFileSize (FileName);
 Dec (FileSize, FileOffset);
 if FileSize < Size then Size := FileSize;

//------------------------------------------------------------------------------
// Собственно чтение/запись

 repeat
// № кластера
   ClusterNo := FileOffset div ClusterSize;
   if ClusterNo >= Length(Clusters) then Break;
   ClusterNo := Clusters[ClusterNo];

// смещение в байтах относительно начала диска
   AbsOffset := ClusterSize * ClusterNo + Cluster0Offset;

// смещение начала данных внутри кластера
   Offset := FileOffset mod ClusterSize;

// вычисление размера данных, подлежащих чтению/записи
   BlockSize := ClusterSize;
   if BlockSize > Size then BlockSize := Size;
   if BlockSize > (ClusterSize-Offset) then BlockSize := (ClusterSize-Offset);

// переход на нужный кластер
   SetFilePointer (hDrive, AbsOffset, Pointer(Integer(@AbsOffset)+4), FILE_BEGIN);

// чтение кластера в буфер происходит еще и в случае,
// если нужно записать кластер не полностью
   if IsRead or (BlockSize <> ClusterSize) then
   begin
     ReadFile (hDrive, ClusterBuf^, ClusterSize, Tmp, nil);
     if IsRead then Move (Pointer(Cardinal(ClusterBuf)+Offset)^, Buf^, BlockSize);

// полчаса возился с записью! :)
// и всё из-за того, что забыл возвращать указатель...
     if not IsRead then SetFilePointer (hDrive, AbsOffset, Pointer(Integer(@AbsOffset)+4), FILE_BEGIN);
   end;

// запись кластера
   if not IsRead then
   begin
     Move (Buf^, Pointer(Cardinal(ClusterBuf)+Offset)^, BlockSize);
     WriteFile (hDrive, ClusterBuf^, ClusterSize, Tmp, nil);
   end;

// продолжение работы...
   Inc (FileOffset, BlockSize);
   Dec (Size, BlockSize);
   Inc (Cardinal(Buf), BlockSize);
 until Size <= 0;

// на всякий случай, хотя не помогает...
 if not IsRead then FlushFileBuffers (hDrive);

 VirtualFree (ClusterBuf, 0, MEM_RELEASE);
 CloseHandle (hDrive);

 Result := (Size = 0); // всё прочитано/записано ?
end;

////////////////////////////////////////////////////////////////////////////////

function DF_Read (const FileName : string; Offset, Size : Cardinal; Buf : Pointer) : Boolean;
begin
 Result := DF_Access (FileName, Offset, Size, Buf, True);
end;

function DF_Write (const FileName : string; Offset, Size : Cardinal; Buf : Pointer) : Boolean;
begin
 Result := DF_Access (FileName, Offset, Size, Buf, False);
end;

////////////////////////////////////////////////////////////////////////////////

end.


MS-MEN   (2005-06-23 07:09:00) [19]

unit PSL_DirectFile;

{***********************************************************
Чтение из файла / запись в файл
через прямое обращение к диску
Нужны права администратора
p0s0l, 2004
***********************************************************}

interface

function DF_Read (const FileName : string; Offset, Size : Cardinal; Buf : Pointer) : Boolean;
function DF_Write (const FileName : string; Offset, Size : Cardinal; Buf : Pointer) : Boolean;
function DF_GetFileSize (const FileName : string) : Int64;

implementation

uses Windows;

////////////////////////////////////////////////////////////////////////////////

const
 FILE_READ_DATA               = $0001;
 FILE_WRITE_DATA              = $0002;
 FILE_READ_ATTRIBUTES         = $0080;
 FSCTL_GET_RETRIEVAL_POINTERS = $90073;

type
 PSTARTING_VCN_INPUT_BUFFER = ^STARTING_VCN_INPUT_BUFFER;
 STARTING_VCN_INPUT_BUFFER = record
   StartingVcn: Int64;
 end;

 TRPBExtends = record
   NextVcn: Int64;
   Lcn: Int64;
 end;

 PRETRIEVAL_POINTERS_BUFFER = ^RETRIEVAL_POINTERS_BUFFER;
 RETRIEVAL_POINTERS_BUFFER = record
   ExtentCount: DWORD;
   StartingVcn: Int64;
   Extends: array [0..0] of TRPBExtends;
 end;

type
 TClusterList = array of Int64;

////////////////////////////////////////////////////////////////////////////////

type
 PFAT32BootSector = ^TFat32BootSector;
 TFAT32BootSector = packed record
   Jmp         : array [0..2] of byte;
   Name        : array [0..7] of char;

// BPB
   SectSiz     : word; // (в байтах)
   ClustSiz    : byte; // (в секторах)
   ResSecs     : word; // кол-во зарезерв. секторов перед первым FAT'ом
   FatCnt      : byte; // кол-во FAT'ов
   RootSiz     : word; // (в 32-байтовых записях)
   TotSecs     : word;
   Media       : byte;
   FatSize     : word; // размер одного FAT (в секторах)
   TrkSecs     : word; // секторов в дорожке
   HeadCnt     : word; // головок (поверхностей)
   HidnSec     : dword;
   TotSecs32   : dword;

// FAT32
   FatSize32   : dword;
   Flags       : word;
   Version     : word;
   RootClust   : dword;
   FSInfo      : word;
   BUInfo      : word;
   Reserved    : array [0..11] of byte;

//
   Drive       : byte;
   Reserved2   : byte;
   BootSign    : byte;
   Serial      : dword;
   VolLabel    : array [0..10] of char;
   FileSys     : array [0..7] of char;
 end;

////////////////////////////////////////////////////////////////////////////////

function DF_GetDrive (const FileName : string) : string;
begin
 Result := FileName[1]+FileName[2];
end;

////////////////////////////////////////////////////////////////////////////////

function DF_GetClusterSize (const Drive : string) : Cardinal;
var
 SectorSize, ClusterSize, Tmp : DWORD;
begin
 Result := 0;
 if GetDiskFreeSpace (PChar(DF_GetDrive(Drive)+'\'), SectorSize, ClusterSize, Tmp, Tmp) then
   Result := SectorSize * ClusterSize;
end;

////////////////////////////////////////////////////////////////////////////////

function DF_GetFileSize (const FileName : string) : Int64;
var
 hFile : THandle;
 Tmp : DWORD;

begin
 Result := -1;

 hFile := CreateFile (PChar(FileName),
                      FILE_READ_ATTRIBUTES,
                      FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
                      nil,
                      OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      0);
 if hFile = INVALID_HANDLE_VALUE then Exit;
 Result := GetFileSize (hFile, @Tmp);
 Result := Result or (Int64(Tmp) shl 32);
 CloseHandle (hFile);
end;

////////////////////////////////////////////////////////////////////////////////

function DF_GetFileClusters (const FileName : string; var Clusters : TClusterList) : boolean;
var
 hFile : THandle;
 FileSize, PrevVCN, Lcn : Int64;
 InputBuffer : STARTING_VCN_INPUT_BUFFER;
 OutputBuffer : PRETRIEVAL_POINTERS_BUFFER;
 ClusterSize, BufferSize, Tmp : Cardinal;
 i, Cl : integer;

begin
 Result := False;
 SetLength (Clusters, 0);
 hFile := CreateFile (PChar(FileName),
                      FILE_READ_ATTRIBUTES,
                      FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
                      nil,
                      OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      0);
 if hFile = INVALID_HANDLE_VALUE then Exit;

 FileSize := DF_GetFileSize (FileName);
 ClusterSize := DF_GetClusterSize (FileName);

 BufferSize := SizeOf(OutputBuffer^) + (FileSize div ClusterSize) * SizeOf(TRPBExtends);
 GetMem (OutputBuffer, BufferSize);

 InputBuffer.StartingVcn := 0;

 if DeviceIoControl (hFile, FSCTL_GET_RETRIEVAL_POINTERS,
                     @InputBuffer, SizeOf(InputBuffer),
                     OutputBuffer, BufferSize, Tmp,
                     nil) then
 begin
// По смыслу Tmp := (FileSize + (ClusterSize-1)) div ClusterSize;
// но мало ли ?... :)
   Tmp := 0;
   PrevVCN := OutputBuffer.StartingVcn;
   for i := 0 to OutputBuffer.ExtentCount-1 do
   begin
     Inc (Tmp, OutputBuffer.Extends[i].NextVcn - PrevVCN);
     PrevVCN := OutputBuffer.Extends[i].NextVcn;
   end;

   SetLength (Clusters, Tmp);

   PrevVCN := OutputBuffer.StartingVcn;
   Cl := 0;
   for i := 0 to OutputBuffer.ExtentCount-1 do
   begin
     Tmp := OutputBuffer.Extends[i].NextVcn-PrevVCN;
     Lcn := OutputBuffer.Extends[i].Lcn;
     while Tmp > 0 do
     begin
       Clusters[Cl] := Lcn;
       Inc (Cl);
       Inc (Lcn);
       Dec (Tmp);
     end;
     PrevVCN := OutputBuffer.Extends[i].NextVcn;
   end;
   Result := True;
 end;

 FreeMem (OutputBuffer);
 CloseHandle (hFile);
end;


Игорь Шевченко   (2005-06-22 23:32:00) [20]

Семен Сорокин ©   (22.06.05 18:57) [6]

Кстати, я ошибся в посте [5] - не у Свена Шрайбера, а у Гэри Неббета есть описание структур NTFS и пример непосредственной работы с ними. Только он честно предупреждает, что граблей на этом пути раскидано немеряно.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо