- 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
- 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.
이제부터는 호환 레이어 위에서 각 기능들을 구현할 차례입니다. 이번에는 파일 I/O 함수 구현 방법에 대해 알아보도록 하겠습니다.
유저 모드에서 사용할 수 있는 파일 I/O 함수는, 똑같이 커널 모드에서도 사용할 수 있습니다. 당연한 말이겠지만, 커널 모드에서 파일 I/O 함수를 제공해 주기 때문에 유저 모드에서 사용할 수 있는 것입니다. 실제로 유저 모드에서 사용하는 함수들은 빈 껍데기일 뿐입니다. 실제로는 커널 모드 함수가 모든 일을 처리합니다.
따라서 유저 모드 함수에 사용되는 각종 옵션들도 커널 모드에서 그대로 사용할 수 있습니다. 단 WDK 스타일에 따라 각종 매크로 정의나 구조체 형태가 다를 수 있지만, 기능은 동일합니다.
주요 유저 모드 파일 I/O 함수에 해당하는 커널 모드 함수는 다음과 같습니다.
- CreateFile - ZwCreateFile
- ReadFile - ZwReadFile
- WriteFile - ZwWriteFile
- CloseHandle - ZwClose
- DeleteFile - ZwDeleteFile
위 함수들 처럼 1:1 대응이 되는 함수들이 있는 경우에는 해당 함수를 그대로 사용하면 되지만 1:1 대응이 되지 않는 함수들이 있습니다. 이러한 함수들은 커널 모드 함수를 조합하여 동일한 기능을 하도록 구현해주어야 합니다.
GetFileSize
DWORD GetFileSize(
HANDLE hFile,
LPDWARD lpFileSizeHigh)
{
NTSTATUS status;
IO_STATUS_BLOCK iosb;
FILE_STANDARD_INFORMATION fileStandardInfo;
DWORD fileSize = 0;
status = ZwQueryInformationFile(
hFile,
&iosb,
&fileStandardInfo,
sizeof(fileStandardInfo),
FileStandardInformation);
if (NT_SUCCESS(status))
{
*lpFileSizeHigh = fileStandardInfo.EndOfFile.HighPart;
fileSize = fileStandardInfo.EndOfFile.LowPart;
}
return fileSize;
}
커널 모드에는 GetFileSize에 정확히 대응되는 함수가 없기 때문에 ZwQueryInformationFile 함수를 이용합니다. FILE_STANDARD_INFORMATION 구조체를 이용하면 파일 크기를 구할 수 있습니다.
SetFilePointer
DWORD SetFilePointer(
HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod)
{
NTSTATUS status;
IO_STATUS_BLOCK iosb;
FILE_POSITION_INFORMATION filePositionInfo;
FILE_STANDARD_INFORMATION fileStandardInfo;
DWORD ret = INVALID_SET_FILE_POINTER;
switch (dwMoveMethod)
{
case FILE_BEGIN:
filePositionInfo.CurrentByteOffset.HighPart = *lpDistanceToMoveHigh;
filePositionInfo.CurrentByteOffset.LowPart = lDistanceToMove;
status = ZwSetInformationFile(
hFile,
&iosb,
&filePositionInfo,
sizeof(filePositionInfo),
FilePositionInformation);
break;
case FILE_CURRENT:
status = ZwQueryInformationFile(
hFile,
&iosb,
&filePositionInfo,
sizeof(filePositionInfo),
FilePositionInformation);
if (NT_SUCCESS(status))
{
filePositionInfo.CurrentByteOffset.HighPart += *lpDistanceToMoveHigh;
filePositionInfo.CurrentByteOffset.LowPart += lDistanceToMove;
status = ZwSetInformationFile(
hFile,
&iosb,
&filePositionInfo,
sizeof(filePositionInfo),
FilePositionInformation);
}
break;
case FILE_END:
status = ZwQueryInformationFile(
hFile,
&iosb,
&fileStandardInfo,
sizeof(fileStandardInfo),
FileStandardInformation);
if (NT_SUCCESS(status))
{
filePositionInfo.CurrentByteOffset.HighPart =
fileStandardInfo.EndOfFile.HighPart;
filePositionInfo.CurrentByteOffset.LowPart =
fileStandardInfo.EndOfFile.LowPart;
filePositionInfo.CurrentByteOffset.HighPart += *lpDistanceToMoveHigh;
filePositionInfo.CurrentByteOffset.LowPart += lDistanceToMove;
status = ZwSetInformationFile(
hFile,
&iosb,
&filePositionInfo,
sizeof(filePositionInfo),
FilePositionInformation);
}
break;
}
if (NT_SUCCESS(status))
{
status = ZwQueryInformationFile(
hFile,
&iosb,
&filePositionInfo,
sizeof(filePositionInfo),
FilePositionInformation);
if (NT_SUCCESS(status))
{
*lpDistanceToMoveHigh = filePositionInfo.CurrentByteOffset.HighPart;
ret = filePositionInfo.CurrentByteOffset.LowPart;
}
}
return ret;
}
SetFilePointer 함수는 기본적으로 ZwQueryInformationFile, ZwSetInformationFile 함수와 FILE_POSITION_INFORMATION 구조체를 이용합니다. 그리고 FILE_END 옵션을 처리하기 위해 FILE_STANDARD_INFORMATION 구초제를 이용합니다.
GetFileAttributes
DWORD GetFileAttributes(
LPCTSTR lpFileName)
{
NTSTATUS status;
HANDLE fileHandle;
UNICODE_STRING fileName;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iosb;
FILE_ATTRIBUTE_TAG_INFORMATION fileAttributeTagInfo;
DWORD ret = INVALID_FILE_ATTRIBUTES;
RtlInitUnicodeString(&fileName, lpFileName);
InitializeObjectAttributes(
&objectAttributes,
&fileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
status = ZwOpenFile(
&fileHandle,
FILE_ALL_ACCESS,
&objectAttributes,
&iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN);
if (NT_SUCCESS(status))
{
status = ZwQueryInformationFile(
fileHandle,
&iosb,
&fileAttributeTagInfo,
sizeof(fileAttributeTagInfo),
FileAttributeTagInformation);
ret = fileAttributeTagInfo.FileAttributes;
ZwClose(fileHandle);
}
return ret;
}
GetFileAttributes는 매개변수로 핸들을 받는 것이 아니라 파일명을 받기 때문에 일단 ZwOpenFile을 이용하여 핸들을 얻습니다. 그리고 ZwQueryInformationFile 함수와 FILE_ATTRIBUTE_TAG_INFORMATION 구조체를 이용하여 구현합니다.
SetFileAttributes 및 기타 함수들도 ZwQueryInformationFile 함수를 이용하면 어렵지 않게 구현할 수 있습니다.
관련글
저작권 안내
이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.- 블로그, 게시판 등에 퍼가는 것을 금지합니다.
- 비공개 포스트에 퍼가는 것을 금지합니다.
- 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
- 링크 및 SNS 공유는 허용합니다.