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

Вниз

Настоящее закрытие файла :)   Найти похожие ветки 

 
Riply ©   (2008-12-16 11:45) [0]

Здравствуйте !
(Не смогла придумать другое название ветки. Будем считать что и это отражает ее суть :) )

Пытаюсь работать, примерно, по такой схеме:

Result := Nt_FileReadToBMem(pImageFileName, pImageInfo, False, nil, SIZE_RESTRICT_MAX);
if NT_SUCCESS(Result) then
begin
 FilePos.QuadPart := pImageInfo.Length;
 if FilePos.QuadPart > 0
  then Result := ZwDeviceIoControl(..., IOCTL_MY_SUPER_PUPER_CODE, ...);


Где Nt_FileReadToBMem открывает файл на чтение, работает с ним и закрывает Handle.
В ней мы обращаемся к файлу из user-mode.

Ф-ия ZwDeviceIoControl(..., IOCTL_MY_SUPER_PUPER_CODE
Сообщает драйверу, что работа закончена и столько-то байт обработано (BytesTransfer).

Драйвер сравнивает три значения: размер данного файла (pImageFileName) в user-mode,
его же размер в kernel-mode и BytesTransfer (обработанные байты).
В зависимости от результата предпринимает различные дейтвия в т.ч.
если все три значения совпали то устанавливает файлу нулевой размер
при помощи ZwSetInformationFile(..., FileEndOfFileInformation).

Все работает и не пискает, кроме как в полнолуние :)
А в полнолуние ZwSetInformationFile выдает нам следующую ошибку:
STATUS_USER_MAPPED_FILE (The requested operation cannot be performed on a file with a user-mapped section open)

Теперь попробую сформулировать вопрос (если правильно понимаю суть происходящего)
Как бы в user-mode закрыть файл "совсем" или хотябы дождаться когда это сделает система,
чтобы смело вызывать ZwDeviceIoControl ?


 
Rouse_ ©   (2008-12-17 10:50) [1]


> Как бы в user-mode закрыть файл "совсем" или хотябы дождаться
> когда это сделает система

Так ты покажи как ты делаеш это сейчас :)


 
Riply ©   (2008-12-17 22:52) [2]

> [1] Rouse_ ©   (17.12.08 10:50)
> Так ты покажи как ты делаеш это сейчас :)

Саш, в общем-то все как у всех. Ничего выходящего за рамки приличий себе не позволяю :)
Ф-ия Nt_FileReadToBMem выглядит, примерно так:
function Nt_FileReadToBMem(const pFileName: PUNICODE_STRING; ...; const RestrictSize: ULONG = SIZE_RESTRICT_MAX): NTSTATUS;
//...
begin
Result := ZwOpenFile(..., FILE_READ_DATA or SYNCHRONIZE, FILE_SHARE_SH_ALL,
 FILE_SEQUENTIAL_ONLY or FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, ...);
if NT_SUCCESS(Result) then
 try
  Result := Zw_FileGetSize(hFileObj, @Offset);
  if NT_SUCCESS(Result) then
   if Offset <= RestrictSize then
    begin
     Result := ZwReadFile(hFileObj, ..., Offset, ...);
     if NT_SUCCESS(Result) then
      begin
       //...
      end;
    end
   else Result := STATUS_INSUFFICIENT_RESOURCES;
 finally
  NT_STATUS_SET_WORST(Result, ZwClose(hFileObj));
 end;
end;

Т.к. в ней мы открываем файл только FILE_READ_DATA доступом (иначе не откроется),
то мы здесь ограничены в попытках что-то предпринять типа ZwFlushFileBuffer :(

Схема происходящего в драйвере (в DeviceIOControlDispatch)
case FunctionCode of
IOCTL_MY_SUPER_PUPER_CODE:
 begin
  //...
  Result := Zw_SetFilePointer(pBuffFile.hFileHandle, nil, pNewFilePointer);
  if NT_SUCCESS(Result) then
   begin
    Result := Zw_SetEndOfFileByOffset(pBuffFile.hFileHandle, nil);
    {$IFDEF SH_DRV_DEBUG}DrvLog_WriteMessW("BFILE_CompactFileDirect", "Zw_SetEndOfFileByOffset", Result,                           pNewFilePointer.LowPart, pNewFilePointer.HighPart);{$ENDIF}
   end
  else {$IFDEF SH_DRV_DEBUG}DrvLog_WriteMessW("BFILE_CompactFileDirect", "Zw_SetFilePointer", Result,                                                pNewFilePointer.LowPart, pNewFilePointer.HighPart);{$ENDIF}
 //...
 end;


где ф-ия Zw_SetEndOfFileByOffset, выглядит, примерно так:
function Zw_SetEndOfFileByOffset(const hFileObj: THANDLE; const pOffset: PLARGE_INTEGER): NTSTATUS;{$IFDEF SH_KRNL_DRV}stdcall;{$ENDIF}
var
IoStatusBlock: IO_STATUS_BLOCK;
EndOfFileInfo: FILE_END_OF_FILE_INFORMATION;
{$IFNDEF SH_KRNL_DRV}
FileAllocationInfo: FILE_ALLOCATION_INFORMATION;
{$ENDIF !SH_KRNL_DRV}
begin
if pOffset <> nil
 then EndOfFileInfo.EndOfFile := pOffset^
 else EndOfFileInfo.EndOfFile := LARGE_INTEGER(Make_Int64(0, 0));
  // This call is not supposed to free up any space after the eof marker
  // if the file gets truncated. We have to deallocate the space explicitly afterwards.
  // But...most file systems dispatch both FileEndOfFileInformation
  // and FileAllocationInformation as they were the same command.
Result := ZwSetInformationFile(hFileObj, @IoStatusBlock, @EndOfFileInfo,
                               SizeOf(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation);
{$IFNDEF SH_KRNL_DRV}
if NT_SUCCESS(Result) then
 begin { TODO -oSashka -cCore functions : Is AllcationInfo need in the user mode ? }
  if pOffset <> nil
   //....
 end;
{$ENDIF !SH_KRNL_DRV}
end;


Ошибку очень сложно отлавливать т.к. каждый раз приходиться ждать следующего полнолуния :)
Закономерности ее появления (например, в зависимости от размера файла),
пока не нашла.


 
Германн ©   (2008-12-18 01:16) [3]

Удалено модератором
Примечание: Оффтоп в тематическом разделе...


 
Riply ©   (2008-12-18 02:32) [4]

> [2] Riply © (17.12.08 22:52)

Я себе так представляю происходящее:
В "обычном" приложении мы поработали с файлом и вызвали ZwClose(hFileObj)
"Система" получила комаду, осознала и поручила некой нити ее
выполнение тогда, когда это будет ей (системе) удобно.
Мы же, вызываем наш драйвер (ZwDeviceIoControl) и
он в своей нити пытается установить файлу нулевой размер.
И вот, когда эта попытка происходит раньше, чем первая нить
выполнила команду, мы и получаем STATUS_USER_MAPPED_FILE.

Если это объяснение похоже на правду, а не является "притянутым за уши",
то и появляется мой вопрос: как из приложения "совсем" закрыть файл
или, хотя бы подождать когда это сделает система ?


 
Rouse_ ©   (2008-12-18 09:52) [5]

Вообще конечно неначем проверить, но попробуй перед выставлением размера проверить MmCanFileBeTruncated() и если что-то не так то скажи MmForceSectionClosed()


 
Riply ©   (2008-12-18 15:41) [6]

> Вообще конечно неначем проверить, но попробуй перед выставлением размера
> проверить MmCanFileBeTruncated()
> и если что-то не так то скажи MmForceSectionClosed()

Попробовала потестить при помощи такой ф-ии:
function Section_ForceCloseTest(const hFileObj: THANDLE): NTSTATUS; stdcall;
var
pFileObj: PFILE_OBJECT;
pSectionPointers: PSECTION_OBJECT_POINTERS;
begin
if OBJECT_TYPES_TABLE.IoFileObjectType <> nil then // глобальная таблица типов объектов
 begin
  Result := ObReferenceObjectByHandle(hFileObj, FILE_WRITE_DATA, OBJECT_TYPES_TABLE.IoFileObjectType,
                                      KernelMode, PVOID(pFileObj), nil);
  if NT_SUCCESS(Result) then
   try
    pSectionPointers := pFileObj.SectionObjectPointer;
    if pSectionPointers <> nil then
     if not MmCanFileBeTruncated(pSectionPointers, @LARGE_NULL) then
      if MmFlushImageSection(pSectionPointers, MmFlushForWrite) then
       if MmForceSectionClosed(pSectionPointers, False) then
        begin
         Result := STATUS_SH_SUCCESS;
        end
       else DrvLog_WriteMessW("Section_ForceCloseTest", "MmForceSectionClosed", Result, 0, 0)
      else DrvLog_WriteMessW("Section_ForceCloseTest", "MmFlushImageSection", Result, 0, 0)
     else DrvLog_WriteMessW("Section_ForceCloseTest", "MmCanFileBeTruncated", Result, 0, 0)
    else
     begin
      Result := STATUS_ACCESS_DENIED;
      DrvLog_WriteMessW("Section_ForceCloseTest", "pSectionPointers <> nil", Result, 0, 0);
     end;
   finally
    ObDereferenceObject(pFileObj);
   end
  else DrvLog_WriteMessW("Section_ForceCloseTest", "ObReferenceObjectByHandle", Result, 0, 0);
 end
else
 begin
  Result := STATUS_ACCESS_DENIED;
  DrvLog_WriteMessW("Section_ForceCloseTest", "IoFileObjectType <> nil", Result, 0, 0);
 end;
end;


И, после ее вызова, сразу пытаемся обнулить размер файла.
MmFlushImageSection - можно коментировать.
Первичные (ни в коем случае не окончательные) результаты такие:
Если MmCanFileBeTruncated успешна, то и Zw_SetEndOfFileByOffset отрабатывает без ругани
и наоборот: Zw_SetEndOfFileByOffset ни разу не проскочила при not MmCanFileBeTruncated.
Дальше хуже.
Удалось поймать такие моменты:
1. MmForceSectionClosed - False, Zw_SetEndOfFileByOffset - False;
2. MmForceSectionClosed - True, Zw_SetEndOfFileByOffset - False;

Иными словами Zw_SetEndOfFileByOffset глубоко плевать на результат MmForceSectionClosed
при именно таком тесте (не пробовала варьировать параметры)

Мне кажется, что такого результата и следовало ожидать.
У нас было два Handle`а этого файла - "ядерный" и "юзерный".
Мы устроили танцы с бубном... тьфу ! с секцией :)
которая относится к "ядерному" варианту, а не к "юзерному".
Или я неправильно понимаю ?
Если правильно, то может попробовать как-то добраться до "юзерной" секции ?
Где-то она же сидит...
От чего бы оттолкнутся, ведь "юзерный" Handle уже не существует...
Вообщем совсем запуталась :(

Мне кажется, что такого результата и следовало ожидать.
У нас было два Handle`а этого файла - "ядерный" и "юзерный".
Мы устроили танцы с бубном... тьфу ! с секцией :)
которая относится к "ядерному" варианту, а не к "юзерному".
Или я неправильно понимаю ?
Если правильно, то может попробовать как-то добраться до "юзерной" секции ?
Где-то она же сидит...
От чего бы оттолкнутся, ведь "юзерный" Handle уже не существует...
Вообщем совсем запуталась :(


 
Riply ©   (2008-12-18 15:47) [7]

Sorry. Копи\пайст подвел.
Вот не зря у нас на форуме настойчиво советуют им не пользоваться :)


 
Rouse_ ©   (2008-12-18 18:35) [8]

Вот это посмотри: http://www.rsdn.ru/forum/message/624367.aspx


 
Riply ©   (2008-12-19 06:43) [9]

> [8] Rouse_ ©   (18.12.08 18:35)
> Вот это посмотри: http://www.rsdn.ru/forum/message/624367.aspx

Посмотрела. Спасибо.
Правда, не поняла с чем (и зачем) он работает в этих строчках:
if (pFileObject->SectionObjectPointer->ImageSectionObject != NULL){
    ExAcquireResourceExclusiveLite( pFCB->Header.PagingIoResource, TRUE);
    ExReleaseResourceLite( pFCB->Header.PagingIoResource);

Ну да ладно. Будем считать, что его (xBlackCat`а) сугубо личное дело :)

Попрогоняла такой вариант теста:
if not MmCanFileBeTruncated(pSectionPointers, @LARGE_NULL) then
if MmFlushImageSection(pSectionPointers, MmFlushForWrite) then
 begin
  CcFlushCache(pSectionPointers, nil, 0, nil);
  if CcPurgeCacheSection(pSectionPointers, nil, 0, True) then
   begin
    Result := STATUS_SUCCESS;
    DrvLog_WriteMessW("Section_ForceCloseTest", "Flush all possible !", Result, 0, 0)
   end


Огорчению не было предела, когда на черт знает какой попытке получила,
что зафлешено и пропургено все что можно :), а эта зараза (Zw_SetEndOfFileByOffset)
совершенно невозмутимо заявляет: STATUS_USER_MAPPED_FILE

Вообщем решила так:
Раз с нахрапа(методом тыка) взять не удалось
- переходим к планомерной осаде(изучению документации) :)



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

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

Наверх




Память: 0.51 MB
Время: 0.011 c
4-1229369994
DenisArd
2008-12-15 22:39
2010.02.28
Загрузка иконок


6-1213512971
JanMihail
2008-06-15 10:56
2010.02.28
Как представить тему письма в нормальном виде?


15-1260451652
Владислав
2009-12-10 16:27
2010.02.28
Зависание системы при отладке.


15-1261161523
Washington
2009-12-18 21:38
2010.02.28
Алгоритмы работы с видео


15-1260893769
ocean
2009-12-15 19:16
2010.02.28
Бунт машин