Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion src/Files.App/Utils/Shell/ShellFolderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

using FluentFTP.Helpers;
using System.IO;
using System.Text;
using Vanara.PInvoke;
using Vanara.Windows.Shell;

Expand Down Expand Up @@ -42,6 +44,52 @@ private static T TryGetProperty<T>(this ShellItemPropertyStore sip, Ole32.PROPER
return value;
}

private static string? GetOriginalPathFromRecycleBinFile(string? physicalPath)
{
if (string.IsNullOrEmpty(physicalPath))
return null;

var fileNameFromPath = Path.GetFileName(physicalPath);

if (!fileNameFromPath.StartsWith("$R", StringComparison.OrdinalIgnoreCase) &&
!fileNameFromPath.StartsWith("$I", StringComparison.OrdinalIgnoreCase))
return null;

try
{
string directory = Path.GetDirectoryName(physicalPath)!;

string iFileName = fileNameFromPath.StartsWith("$R", StringComparison.OrdinalIgnoreCase) ?
"$I" + fileNameFromPath.RemovePrefix("$R") : fileNameFromPath.ToString();

string filePath = Path.Combine(directory, iFileName);

if (!File.Exists(filePath) && !Directory.Exists(filePath))
return null;


using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var reader = new BinaryReader(stream, Encoding.Unicode);

// From the 24th to the 28th, contains the number of characters for the originalPath.
reader.BaseStream.Seek(24, SeekOrigin.Begin);
int pathCharCount = reader.ReadInt32();

// From the 28th byte, that's where the OriginalPath is.
// Windows is UTF-16, so each character takes 2 bytes, hence the multiplication.
byte[] pathBytes = reader.ReadBytes(pathCharCount * 2);
string originalPath = Encoding.Unicode.GetString(pathBytes).TrimEnd('\0');

return originalPath;
}
catch
{

}

return null;
}

public static ShellFileItem GetShellFileItem(ShellItem folderItem)
{
if (folderItem is null)
Expand All @@ -57,6 +105,8 @@ public static ShellFileItem GetShellFileItem(ShellItem folderItem)
// True path on disk
parsingPath ??= folderItem.FileSystemPath;

string? recycleBinFileOriginalPath = GetOriginalPathFromRecycleBinFile(folderItem.FileSystemPath);

if (parsingPath is null || !Path.IsPathRooted(parsingPath))
{
parsingPath = parsingPath switch
Expand Down Expand Up @@ -110,7 +160,9 @@ public static ShellFileItem GetShellFileItem(ShellItem folderItem)
string fileSize = fileSizeBytes is not null ? folderItem.Properties.GetPropertyString(Ole32.PROPERTYKEY.System.Size) : null;
var fileType = folderItem.Properties.TryGetProperty<string>(Ole32.PROPERTYKEY.System.ItemTypeText);

return new(isFolder, parsingPath, fileName, filePath, recycleDate, modifiedDate, createdDate, fileSize, fileSizeBytes ?? 0, fileType, folderItem.PIDL.GetBytes());
string finalFilePath = string.IsNullOrEmpty(recycleBinFileOriginalPath) ? filePath : recycleBinFileOriginalPath;

return new(isFolder, parsingPath, fileName, finalFilePath, recycleDate, modifiedDate, createdDate, fileSize, fileSizeBytes ?? 0, fileType, folderItem.PIDL.GetBytes());
}

public static ShellLinkItem GetShellLinkItem(ShellLink linkItem)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,12 @@ public static bool IsShellPath(string path)

public static ShellStorageFolder FromShellItem(ShellFileItem item)
{
if (item.RecyclePath.Contains("$Recycle.Bin", StringComparison.OrdinalIgnoreCase))
return new BinStorageFolder(item);

if (item is ShellLinkItem linkItem)
return new ShortcutStorageFolder(linkItem);

if (item.RecyclePath.Contains("$Recycle.Bin", StringComparison.OrdinalIgnoreCase))
return new BinStorageFolder(item);

return new ShellStorageFolder(item);
}
Expand Down
Loading