Главная страница
    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.56 MB
Время: 0.035 c
6-1115408403
NikNet
2005-05-06 23:40
2005.08.21
Люди помогите сделать RECV что-то у меня не получается?


3-1121256077
CasperR
2005-07-13 16:01
2005.08.21
Интерфейсы ADO


14-1122887902
Ega23
2005-08-01 13:18
2005.08.21
С днем рождения! 1 августа


14-1122665035
fen
2005-07-29 23:23
2005.08.21
ехе


1-1122984669
mazepa
2005-08-02 16:11
2005.08.21
progress





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский