Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2010.02.28;
Скачать: [xml.tar.bz2];

Вниз

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

 
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 вся ветка

Форум: "WinAPI";
Текущий архив: 2010.02.28;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.004 c
2-1261641926
Андрей_11
2009-12-24 11:05
2010.02.28
запрос БД с другого компьютера


15-1260971239
Артур Пирожков
2009-12-16 16:47
2010.02.28
НЕ програмное выполнение несложной задачи


15-1261171198
TUser
2009-12-19 00:19
2010.02.28
Искривление времени?


4-1229417136
Riply
2008-12-16 11:45
2010.02.28
Настоящее закрытие файла :)


2-1261836632
Student :)
2009-12-26 17:10
2010.02.28
Чтение параметра реестра





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский