internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound)
{
int errorCode = Interop.Errors.ERROR_SUCCESS;
// Neither GetFileAttributes or FindFirstFile like trailing separators
path = path.TrimEnd(PathHelpers.DirectorySeparatorChars);
using (new DisableMediaInsertionPrompt())
{
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.fileAttributes = -1;
return(Interop.Errors.ERROR_SUCCESS);
}
}
return(errorCode);
}