private static bool ShouldUseWinRT(string fullPath, bool isCreate)
{
// The purpose of this method is to determine if we can access a path
// via Win32 or if we need to fallback to WinRT.
// We prefer Win32 since it is faster, WinRT's APIs eventually just
// call into Win32 after all, but it doesn't provide access to,
// brokered paths (like Pictures or Documents) nor does it handle
// placeholder files. So we'd like to fall back to WinRT whenever
// we can't access a path, or if it known to be a placeholder file.
bool useWinRt = false;
do
{
// first use GetFileAttributesEx as it is faster than FindFirstFile and requires minimum permissions
Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
if (Interop.Kernel32.GetFileAttributesEx(fullPath, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
{
// got the attributes
if ((data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0 ||
(data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_REPARSE_POINT) == 0)
{
// we have a directory or a file that is not a reparse point
// useWinRt = false;
break;
}
else
{
// we need to get the find data to determine if it is a placeholder file
Interop.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(fullPath, ref findData))
{
if (!handle.IsInvalid)
{
// got the find data, use WinRT for placeholder files
Debug.Assert((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
Debug.Assert((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_REPARSE_POINT) != 0);
useWinRt = findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_FILE_PLACEHOLDER;
break;
}
}
}
}
int error = Marshal.GetLastWin32Error();
Debug.Assert(error != Interop.Errors.ERROR_SUCCESS);
if (error == Interop.Errors.ERROR_ACCESS_DENIED)
{
// The path was not accessible with Win32, so try WinRT
useWinRt = true;
break;
}
else if (error != Interop.Errors.ERROR_PATH_NOT_FOUND && error != Interop.Errors.ERROR_FILE_NOT_FOUND)
{
// We hit some error other than ACCESS_DENIED or NOT_FOUND,
// Default to Win32 to provide most accurate error behavior
break;
}
// error was ERROR_PATH_NOT_FOUND or ERROR_FILE_NOT_FOUND
// if we are creating a file/directory we cannot assume that Win32 will have access to
// the parent directory, so we walk up the path.
fullPath = PathHelpers.GetDirectoryNameInternal(fullPath);
// only walk up the path if we are creating a file/directory and not at the root
} while (isCreate && !String.IsNullOrEmpty(fullPath));
return useWinRt;
}
}