// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Runtime.InteropServices;
namespace Internal.IO
{
internal static partial class File
{
internal static bool InternalExists(string fullPath)
{
Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true);
return (errorCode == 0) && (data.dwFileAttributes != -1)
&& ((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
}
///
/// Returns 0 on success, otherwise a Win32 error code. Note that
/// classes should use -1 as the uninitialized state for dataInitialized.
///
/// Return the error code for not found errors?
internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound)
{
int errorCode = Interop.Errors.ERROR_SUCCESS;
using (DisableMediaInsertionPrompt.Create())
{
if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
{
errorCode = Marshal.GetLastWin32Error();
if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED)
{
// Files that are marked for deletion will not let you GetFileAttributes,
// ERROR_ACCESS_DENIED is given back without filling out the data struct.
// FindFirstFile, however, will. Historically we always gave back attributes
// for marked-for-deletion files.
var findData = new Interop.Kernel32.WIN32_FIND_DATA();
using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData))
{
if (handle.IsInvalid)
{
errorCode = Marshal.GetLastWin32Error();
}
else
{
errorCode = Interop.Errors.ERROR_SUCCESS;
data.PopulateFrom(ref findData);
}
}
}
}
}
if (errorCode != Interop.Errors.ERROR_SUCCESS && !returnErrorOnNotFound)
{
switch (errorCode)
{
case Interop.Errors.ERROR_FILE_NOT_FOUND:
case Interop.Errors.ERROR_PATH_NOT_FOUND:
case Interop.Errors.ERROR_NOT_READY: // Removable media not ready
// Return default value for backward compatibility
data.dwFileAttributes = -1;
return Interop.Errors.ERROR_SUCCESS;
}
}
return errorCode;
}
}
}