Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.08.21;
Скачать: CL | DM;

Вниз

Расположение заблокированного файла на диске.   Найти похожие ветки 

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

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

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


 
Игорь Шевченко ©   (2005-06-22 18:22) [1]


> Приветствую гуру, кто может подсказать как получить покластерное
> расположение заблокированного файла на диске, например pagefile.sys


Среди API дефрагментации ничего нету ?


 
Семен Сорокин ©   (2005-06-22 18:28) [2]

3 функции:
FSCTL_GET_RETRIEVAL_POINTERS Get information about a file"s cluster use.
FSCTL_GET_VOLUME_BITMAP Get a bitmap of cluster allocation.
FSCTL_MOVE_FILE Move all or part of a file from one set of clusters to another within a volume.

FSCTL_GET_VOLUME_BITMAP - возвращает карту диска по занятым/незанятым кластерам без конкретики по файлам...
FSCTL_GET_RETRIEVAL_POINTERS - именно эту я использую для получения информации по отдельному открытому(!) файлу.
FSCTL_MOVE_FILE - непосредственно для дефрагментации...

PS. ведь O&O Defrag как-то показывает расположение того же свопа на диске... наверняка есть какие нибудь функции, а я не знаю куда копать

PPS. можно конечно попробовать вычислить из общей карты диска - вычитанием имеющихся расположений файлов, но, имхо, не то...


 
Игорь Шевченко ©   (2005-06-22 18:32) [3]

А открыть файл с FILE_SHARE_READ + FILE_SHARE_WRITE не помогает ?


 
Семен Сорокин ©   (2005-06-22 18:39) [4]


> Игорь Шевченко ©   (22.06.05 18:32) [3]
> А открыть файл с FILE_SHARE_READ + FILE_SHARE_WRITE не помогает
> ?

неа, я уже перепробовал все возможные флаги :)
результат один и тот-же:
32 The process cannot access the file because it is being used by another process. ERROR_SHARING_VIOLATION  
я уже даже пробовал открывть его из сервиса с SYSTEM-правами - та же песня.


 
Игорь Шевченко ©   (2005-06-22 18:49) [5]

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

Defrag имени Руссиновича тоже не показывает :)

Можно, конечно, и структуры NTFS читать, у Свена Шрайбера пример есть, но уж больно муторно.


 
Семен Сорокин ©   (2005-06-22 18:57) [6]

ага, а ведь есть же что-то :) по поводу структуры NTFS - это да (через FSCTL_GET_NTFS_FILE_RECORD если я не ошибаюсь), а что делать если FAT32... необходимо нечто универсальное.

PS. Спасибо за помощь.


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

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

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


 
MS-MEN ©   (2005-06-23 07:09) [8]

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;


 
MS-MEN ©   (2005-06-23 07:09) [9]

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.


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

>MS-MEN ©

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

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


 
MS-MEN ©   (2005-06-23 10:18) [11]

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

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


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


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


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


 
Kerk ©   (2005-06-23 10:22) [13]

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


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


 
MS-MEN ©   (2005-06-23 10:28) [14]

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

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

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


 
Kerk ©   (2005-06-23 10:30) [15]

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


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

>Kerk

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

>MS-MEN

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


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

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


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


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

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


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


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

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

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

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


 
BiN ©   (2005-06-24 12:42) [19]

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

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


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


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


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


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


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

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

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

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

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


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

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


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


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


 
BiN ©   (2005-06-24 13:35) [23]

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

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


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


 
BiN ©   (2005-06-24 14:14) [24]

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

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


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


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

BiN ©   (24.06.05 14:14) [24]


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


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


 
NikNet ©   (2005-06-24 20:32) [26]

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



Страницы: 1 вся ветка

Текущий архив: 2005.08.21;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.028 c
14-1122115821
Piter
2005-07-23 14:50
2005.08.21
Может ли мотоцикл разогнаться до 315 км/ч?


6-1115955780
Delphi forever
2005-05-13 07:43
2005.08.21
Прием и отправка почты (с прикрепленными файлами)


1-1122630609
Aleksandr.
2005-07-29 13:50
2005.08.21
Как правильно удалить TMenuItem?


11-1105726128
chum
2005-01-14 21:08
2005.08.21
Работа со строками


14-1122620079
Ёжик
2005-07-29 10:54
2005.08.21
Net use