HANDLE WINAPI CreateFile( _In_ LPCTSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile );
NTSTATUS ZwSetInformationFile(
_In_ HANDLE FileHandle,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass
);
일단 파일에 대한 핸들을 열구요... 그 핸들을 이용해 ZwSetInformationFile을 호출하는데요... (그러기 위해선 핸들을 열때 DELETE 권한을 설정해서 열어야 합니다.)
일단 FileInformationClass에는 FileDispositionInformation 값을 지정합니다.
그러고서 FileInformation에는 FILE_DISPOSITION_INFORMATION 구조체의 주소를 설정하는데요... 이때 DeleteFile 멤버를 TRUE로 설정해줍니다.
typedef struct _FILE_DISPOSITION_INFORMATION { BOOLEAN DeleteFile; } FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
DeleteFile을 TRUE로 설정하여 이 api를 호출하게 되면... 파일은 "DeletePending" Mark가 찍히게 되고 이후에 언젠가 그 파일에 대한 모든 핸들이 닫힐 때 파일이 삭제되게 됩니다. 말하자면... "삭제 예정"이라고 표시만 해 놨다가 나중에 핸들이 닫힐 때 (=더 이상 사용되지 않을때) 실제로 지운다 이거죠.
현재 어떤 파일이 DeletePending 상태인지 여부는... ZwQueryInformationFile이라는 api에 FileInformationClass인자에 FileStandardInformation 값을 주고 호출해 보면 알 수 있습니다.
typedef struct _FILE_STANDARD_INFORMATION { LARGE_INTEGER AllocationSize; LARGE_INTEGER EndOfFile; ULONG NumberOfLinks; BOOLEAN DeletePending; BOOLEAN Directory; } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
그런데... 저 위에 나왔던 FileDispositionInformation이란 클래스에 DeleteFile이라는 BOOLEAN값을 설정하게 되어 있는 게... 좀 이상하게 생겼네요. 그렇다면 저 DeleteFile 인자 값에 FALSE를 주고 호출하면 어떻게 될까요??
그것은... 이미 DeleteFile에 TRUE를 주어 호출한 적이 있는, 즉 DeletePending = TRUE인 파일의 DeletePending값을 다시 FALSE로 Reset한다는 의미가 되겠습니다~~~!!!
인자를 저렇게 줘서 호출할 일이 진짜로 생길까요...??
네~ 물론 생깁니다.
일반 파일을 탐색기에서 "Delete" 키를 눌러서 삭제하면... 모두다 아시다시피 파일은 즉시 지워지지 않고 휴지통에 들어가게 되는데요... 이것은 DeleteFile이 아닌 MoveFile Operation이 되겠습니다.
그런데... 이 MoveFile이 이루어지기 전에 DeleteFile을 먼저 시뮬레이션을 해 보고 성공했을 때에 한해서 성공한 DeleteFile을 Cancel시킨 후 휴지통으로 MoveFile이 진행되게 됩니다. (아래 캡쳐이미지 참고)
이런 문제들이 소프트웨어 개발시에도 영향을 미칠 수 있습니다.
예를 들어... 파일 삭제 행위를 로깅하는 기능을 개발한다고 치겠습니다.
파일 삭제 행위를 취소할 수 있다는 것은... 파일 삭제를 로깅하기 위해서는 미니필터에서 SetInformationFile의 FileDispositionInformation class가 아니라 사실은 Cleanup 시점에서 로깅해야 된다는 것을 의미합니다. 어떤 파일이 삭제되었다고 로그를 남겼는데 나중에 삭제가 취소되어 그 파일이 그대로 남아있는 상황이 생길 수도 있으니까요.
그렇다면 Stream Context나 File Context에 DeleteFile 플래그를 기록해놨다가 최종적으로 핸들이 닫힐때의 플래그 값이 뭔지를 확인한다던지... 이런 식이 되어야겠네요. ^^;;
'Kernel Inside > FileSystem' 카테고리의 다른 글
응용 디버깅 시 IRP_MJ_CLEANUP의 프로세스 ID 문제... (0) | 2014.12.12 |
---|---|
미니필터에서 File I/O Redirect 하기 (부제 : simrep 샘플 코드의 버그?) (0) | 2014.07.31 |
File이 Rename (MoveFile)될 때 커널에서 벌어지는 일들 (2) | 2014.07.28 |
IoQueryFileDosDeviceName 의 안전한 사용방법 (?) (2) | 2014.07.18 |
미니필터 샘플코드 "scanner" Flow 정리 (0) | 2013.08.13 |