672 lines
17 KiB
C++
672 lines
17 KiB
C++
//======================================================================
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
// PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// This sample demonstrates how to query information about files and
|
|
// directories using the GetFileInformationByHandle API as well as how
|
|
// to open a file by ID using OpenFileById.
|
|
//
|
|
//=====================================================================
|
|
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
|
|
VOID
|
|
PrintUsage() {
|
|
printf("Usage: ExtendedFileAPIs [-id] targetFile\n\n");
|
|
printf(" Display extended information about the target file or directory\n");
|
|
printf(" using the GetFileInformationByHandleEx API.\n\n");
|
|
printf(" -id If this flag is specified the target file is assumed to be a file ID\n");
|
|
printf(" and the program will attempt to open the file using OpenFileById.\n");
|
|
printf(" The current directory will be used to determine which volume to scope\n");
|
|
printf(" the open to.\n");
|
|
}
|
|
|
|
VOID
|
|
PrintFileAttributes(
|
|
ULONG FileAttributes
|
|
)
|
|
{
|
|
if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
|
|
printf("Archive ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
printf("Directory ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_READONLY) {
|
|
printf("Read-Only ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_HIDDEN) {
|
|
printf("Hidden ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_SYSTEM) {
|
|
printf("System ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_NORMAL) {
|
|
printf("Normal ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_NORMAL;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
|
|
printf("Temporary ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
|
|
}
|
|
if (FileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
|
|
printf("Compressed ");
|
|
FileAttributes &= ~FILE_ATTRIBUTE_COMPRESSED;
|
|
}
|
|
|
|
if (FileAttributes) {
|
|
printf(" Additional Attributes: %x", FileAttributes);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
BOOL
|
|
PrintDate(
|
|
LARGE_INTEGER Date
|
|
)
|
|
{
|
|
BOOL result;
|
|
FILETIME fileTime;
|
|
SYSTEMTIME systemTime;
|
|
|
|
fileTime.dwLowDateTime = Date.LowPart;
|
|
fileTime.dwHighDateTime = Date.HighPart;
|
|
|
|
result = FileTimeToLocalFileTime( &fileTime,
|
|
&fileTime );
|
|
|
|
if (!result) {
|
|
return result;
|
|
}
|
|
|
|
result = FileTimeToSystemTime( &fileTime,
|
|
&systemTime );
|
|
|
|
if (!result) {
|
|
return result;
|
|
}
|
|
|
|
printf("%.2d/%.2d/%.4d %.2d:%.2d",
|
|
systemTime.wMonth,
|
|
systemTime.wDay,
|
|
systemTime.wYear,
|
|
systemTime.wHour,
|
|
systemTime.wMinute);
|
|
|
|
return true;
|
|
}
|
|
|
|
BOOL
|
|
DisplayBasicInfo(
|
|
HANDLE hFile,
|
|
BOOL * bIsDirectory
|
|
)
|
|
{
|
|
FILE_BASIC_INFO basicInfo;
|
|
BOOL result;
|
|
|
|
result = GetFileInformationByHandleEx( hFile,
|
|
FileBasicInfo,
|
|
&basicInfo,
|
|
sizeof(basicInfo));
|
|
|
|
if (!result) {
|
|
printf("Failure fetching basic information: %d\n", GetLastError());
|
|
return result;
|
|
}
|
|
|
|
printf("\n[Basic Information]\n\n");
|
|
|
|
printf(" Creation Time: ");
|
|
|
|
result = PrintDate(basicInfo.CreationTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving creation time.\n");
|
|
}
|
|
|
|
printf(" Change Time: ");
|
|
|
|
result = PrintDate(basicInfo.ChangeTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving creation time.\n");
|
|
}
|
|
|
|
printf(" Last Access Time: ");
|
|
|
|
result = PrintDate(basicInfo.LastAccessTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving last access time.\n");
|
|
}
|
|
|
|
printf(" Last Write Time: ");
|
|
|
|
result = PrintDate(basicInfo.LastWriteTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving last write time.\n");
|
|
}
|
|
|
|
printf(" File Attributes: ");
|
|
PrintFileAttributes(basicInfo.FileAttributes);
|
|
|
|
if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
*bIsDirectory = true;
|
|
} else {
|
|
*bIsDirectory = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
DisplayStandardInfo(
|
|
HANDLE hFile
|
|
)
|
|
{
|
|
FILE_STANDARD_INFO standardInfo;
|
|
BOOL result;
|
|
|
|
result = GetFileInformationByHandleEx( hFile,
|
|
FileStandardInfo,
|
|
&standardInfo,
|
|
sizeof(standardInfo));
|
|
|
|
if (!result) {
|
|
printf("Failure fetching standard information: %d\n", GetLastError());
|
|
return result;
|
|
}
|
|
|
|
printf("\n[Standard Information]\n\n");
|
|
|
|
printf(" Allocation Size: %I64d\n", standardInfo.AllocationSize);
|
|
printf(" End of File: %I64d\n", standardInfo.EndOfFile);
|
|
printf(" Number of Links: %d\n", standardInfo.NumberOfLinks);
|
|
printf(" Delete Pending: ");
|
|
if (standardInfo.DeletePending) {
|
|
printf("Yes\n");
|
|
} else {
|
|
printf("No\n");
|
|
}
|
|
printf(" Directory: ");
|
|
if (standardInfo.Directory) {
|
|
printf("Yes\n");
|
|
} else {
|
|
printf("No\n");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BOOL
|
|
DisplayNameInfo(
|
|
HANDLE hFile
|
|
)
|
|
{
|
|
PFILE_NAME_INFO nameInfo;
|
|
ULONG nameSize;
|
|
BOOL result;
|
|
|
|
//
|
|
// Allocate an information structure that is hopefully large enough to
|
|
// retrieve name information.
|
|
//
|
|
|
|
nameSize = sizeof(FILE_NAME_INFO) + (sizeof(WCHAR) * MAX_PATH);
|
|
|
|
retry:
|
|
|
|
nameInfo = (PFILE_NAME_INFO) LocalAlloc(LMEM_ZEROINIT,
|
|
nameSize);
|
|
|
|
|
|
if (nameInfo == NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return false;
|
|
}
|
|
|
|
result = GetFileInformationByHandleEx( hFile,
|
|
FileNameInfo,
|
|
nameInfo,
|
|
nameSize );
|
|
|
|
if (!result) {
|
|
//
|
|
// If our buffer wasn't large enough try again with a larger one.
|
|
//
|
|
if (GetLastError() == ERROR_MORE_DATA) {
|
|
nameSize *= 2;
|
|
goto retry;
|
|
}
|
|
|
|
printf("Failure fetching name information: %d\n", GetLastError());
|
|
LocalFree(nameInfo);
|
|
return result;
|
|
}
|
|
|
|
printf("\n[Name Information]\n\n");
|
|
|
|
printf(" File Name: %S\n", nameInfo->FileName);
|
|
|
|
LocalFree(nameInfo);
|
|
return true;
|
|
}
|
|
|
|
BOOL
|
|
DisplayStreamInfo(
|
|
HANDLE hFile
|
|
)
|
|
{
|
|
PFILE_STREAM_INFO currentStreamInfo;
|
|
BOOL result;
|
|
PFILE_STREAM_INFO streamInfo;
|
|
ULONG streamInfoSize;
|
|
|
|
|
|
//
|
|
// Allocate an information structure that is hopefully large enough to
|
|
// retrieve stream information.
|
|
//
|
|
|
|
streamInfoSize = sizeof(FILE_STREAM_INFO) + (sizeof(WCHAR) * MAX_PATH);
|
|
|
|
retry:
|
|
|
|
streamInfo = (PFILE_STREAM_INFO) LocalAlloc(LMEM_ZEROINIT,
|
|
streamInfoSize);
|
|
|
|
|
|
if (streamInfo == NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return false;
|
|
}
|
|
|
|
result = GetFileInformationByHandleEx( hFile,
|
|
FileStreamInfo,
|
|
streamInfo,
|
|
streamInfoSize );
|
|
|
|
if (!result) {
|
|
//
|
|
// If our buffer wasn't large enough try again with a larger one.
|
|
//
|
|
if (GetLastError() == ERROR_MORE_DATA) {
|
|
streamInfoSize *= 2;
|
|
goto retry;
|
|
}
|
|
|
|
printf("Failure fetching stream information: %d\n", GetLastError());
|
|
LocalFree(streamInfo);
|
|
return result;
|
|
}
|
|
|
|
printf("\n[Stream Information]\n\n");
|
|
|
|
currentStreamInfo = streamInfo;
|
|
|
|
do {
|
|
printf(" Stream Name: %S\n", currentStreamInfo->StreamName);
|
|
printf(" Stream Size: %I64d\n", currentStreamInfo->StreamSize);
|
|
printf(" Stream Allocation Size: %I64d\n",
|
|
currentStreamInfo->StreamAllocationSize);
|
|
|
|
if (currentStreamInfo->NextEntryOffset == 0) {
|
|
currentStreamInfo = NULL;
|
|
} else {
|
|
currentStreamInfo =
|
|
(PFILE_STREAM_INFO) ((PUCHAR)currentStreamInfo +
|
|
currentStreamInfo->NextEntryOffset);
|
|
}
|
|
} while (currentStreamInfo != NULL);
|
|
|
|
|
|
LocalFree(streamInfo);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
PrintDirectoryEntry(
|
|
PFILE_ID_BOTH_DIR_INFO entry
|
|
)
|
|
{
|
|
WCHAR lastChar;
|
|
BOOL result;
|
|
|
|
//
|
|
// The names aren't necessarily NULL terminated, so we deal with that here.
|
|
//
|
|
lastChar = entry->FileName[(entry->FileNameLength / sizeof(WCHAR))];
|
|
entry->FileName[(entry->FileNameLength / sizeof(WCHAR))] = L'\0';
|
|
|
|
printf("\n %S ", entry->FileName);
|
|
|
|
entry->FileName[(entry->FileNameLength / sizeof(WCHAR))] = lastChar;
|
|
|
|
if (entry->ShortName[0] != L'\0') {
|
|
lastChar = entry->ShortName[(entry->ShortNameLength / sizeof(WCHAR))];
|
|
entry->ShortName[(entry->ShortNameLength / sizeof(WCHAR))] = L'\0';
|
|
|
|
printf("[%S]\n\n", entry->ShortName);
|
|
|
|
entry->ShortName[(entry->ShortNameLength / sizeof(WCHAR))] = lastChar;
|
|
} else {
|
|
printf("\n\n");
|
|
}
|
|
|
|
printf(" Creation Time: ");
|
|
|
|
result = PrintDate(entry->CreationTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving creation time.\n");
|
|
}
|
|
|
|
printf(" Change Time: ");
|
|
|
|
result = PrintDate(entry->ChangeTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving creation time.\n");
|
|
}
|
|
|
|
printf(" Last Access Time: ");
|
|
|
|
result = PrintDate(entry->LastAccessTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving last access time.\n");
|
|
}
|
|
|
|
printf(" Last Write Time: ");
|
|
|
|
result = PrintDate(entry->LastWriteTime);
|
|
|
|
if (result) {
|
|
printf("\n");
|
|
} else {
|
|
printf(" Error retrieving last write time.\n");
|
|
}
|
|
|
|
printf(" End of File: %I64d\n", entry->EndOfFile);
|
|
printf(" Allocation Size: %I64d\n", entry->AllocationSize);
|
|
printf(" File Attributes: ");
|
|
PrintFileAttributes(entry->FileAttributes);
|
|
printf(" File ID: %I64d\n", entry->FileId);
|
|
}
|
|
|
|
BOOL
|
|
DisplayFullDirectoryInfo(
|
|
HANDLE hFile
|
|
)
|
|
{
|
|
PFILE_ID_BOTH_DIR_INFO currentDirInfo;
|
|
PFILE_ID_BOTH_DIR_INFO dirInfo;
|
|
ULONG dirInfoSize;
|
|
FILE_INFO_BY_HANDLE_CLASS infoClass;
|
|
BOOL result;
|
|
|
|
//
|
|
// Allocate an information structure that is hopefully large enough to
|
|
// retrieve at least one directory entry.
|
|
//
|
|
|
|
dirInfoSize = sizeof(FILE_ID_BOTH_DIR_INFO) + (sizeof(WCHAR) * MAX_PATH);
|
|
|
|
//
|
|
// We initially want to start our enumeration from the beginning so we
|
|
// use the restart class.
|
|
//
|
|
infoClass = FileIdBothDirectoryRestartInfo;
|
|
|
|
retry:
|
|
|
|
dirInfo = (PFILE_ID_BOTH_DIR_INFO) LocalAlloc(LMEM_ZEROINIT,
|
|
dirInfoSize);
|
|
|
|
|
|
if (dirInfo == NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return false;
|
|
}
|
|
|
|
for (;;) {
|
|
result = GetFileInformationByHandleEx( hFile,
|
|
infoClass,
|
|
dirInfo,
|
|
dirInfoSize );
|
|
|
|
if (!result) {
|
|
//
|
|
// If our buffer wasn't large enough try again with a larger one.
|
|
//
|
|
if (GetLastError() == ERROR_MORE_DATA) {
|
|
dirInfoSize *= 2;
|
|
goto retry;
|
|
} else if (GetLastError() == ERROR_NO_MORE_FILES) {
|
|
//
|
|
// Enumeration completed successfully, we simply break out here.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// A real error occurred.
|
|
//
|
|
printf("\nFailure fetching directory information: %d\n",
|
|
GetLastError());
|
|
|
|
LocalFree(dirInfo);
|
|
return result;
|
|
}
|
|
|
|
if (infoClass == FileIdBothDirectoryRestartInfo) {
|
|
printf("\n[Full Directory Information]\n\n");
|
|
infoClass = FileIdBothDirectoryInfo;
|
|
}
|
|
|
|
currentDirInfo = dirInfo;
|
|
|
|
do {
|
|
PrintDirectoryEntry(currentDirInfo);
|
|
if (currentDirInfo->NextEntryOffset == 0) {
|
|
currentDirInfo = NULL;
|
|
} else {
|
|
currentDirInfo =
|
|
(PFILE_ID_BOTH_DIR_INFO) ((PUCHAR)currentDirInfo +
|
|
currentDirInfo->NextEntryOffset);
|
|
}
|
|
} while (currentDirInfo != NULL);
|
|
|
|
}
|
|
LocalFree(dirInfo);
|
|
|
|
return true;
|
|
}
|
|
|
|
int __cdecl wmain( __in int argc, __in_ecount(argc) WCHAR* argv[])
|
|
{
|
|
BOOL bIsDirectory;
|
|
BOOL bResult;
|
|
HANDLE hFile;
|
|
FILE_ID_DESCRIPTOR fileId;
|
|
|
|
|
|
if (argc < 2) {
|
|
PrintUsage();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Check for flag that indicates we should open by ID
|
|
//
|
|
if (CompareStringW(LOCALE_INVARIANT,
|
|
NORM_IGNORECASE,
|
|
argv[1],
|
|
-1,
|
|
L"-id",
|
|
-1) == CSTR_EQUAL) {
|
|
|
|
HANDLE hDir;
|
|
|
|
if (argc < 3) {
|
|
PrintUsage();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Open a handle to the current directory to use as a hint when
|
|
// opening the file by ID.
|
|
//
|
|
hDir = CreateFileW(L".",
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS,
|
|
NULL);
|
|
|
|
if (hDir == INVALID_HANDLE_VALUE) {
|
|
printf("Couldn't open current directory.\n");
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Capture the file ID and attempt to open by ID.
|
|
//
|
|
fileId.FileId.QuadPart = _wtoi64(argv[2]);
|
|
fileId.Type = FileIdType;
|
|
fileId.dwSize = sizeof(fileId);
|
|
|
|
hFile = OpenFileById(hDir,
|
|
&fileId,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
NULL,
|
|
FILE_FLAG_BACKUP_SEMANTICS);
|
|
|
|
CloseHandle(hDir);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
printf("\nError opening file with ID %s. Last error was %d.\n",
|
|
argv[2],
|
|
GetLastError());
|
|
|
|
return 1;
|
|
}
|
|
|
|
} else {
|
|
|
|
hFile = CreateFileW(argv[1],
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
printf("\nError opening file %s. Last error was %d.\n",
|
|
argv[1],
|
|
GetLastError());
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Display information about the file/directory
|
|
//
|
|
bResult = DisplayBasicInfo(hFile, &bIsDirectory);
|
|
|
|
if (!bResult) {
|
|
|
|
printf("\nError displaying basic information.\n");
|
|
return 1;
|
|
}
|
|
|
|
bResult = DisplayStandardInfo(hFile);
|
|
|
|
if (!bResult) {
|
|
|
|
printf("\nError displaying standard information.\n");
|
|
return 1;
|
|
}
|
|
|
|
bResult = DisplayNameInfo(hFile);
|
|
|
|
if (!bResult) {
|
|
|
|
printf("\nError displaying name information.\n");
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// For directories we query for full directory information, which gives us
|
|
// various pieces of information about each entry in the directory.
|
|
//
|
|
if (bIsDirectory) {
|
|
|
|
bResult = DisplayFullDirectoryInfo(hFile);
|
|
|
|
if (!bResult) {
|
|
|
|
printf("\nError displaying directory information.\n");
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Otherwise we query information about the streams associated with the
|
|
// file.
|
|
//
|
|
} else {
|
|
|
|
bResult = DisplayStreamInfo(hFile);
|
|
|
|
if (!bResult) {
|
|
|
|
printf("\nError displaying stream information.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|