Repository navigation
Expand file tree
/
Copy pathMftEngine.cs
More file actions
192 lines (172 loc) · 7.36 KB
/
Copy pathMftEngine.cs
File metadata and controls
192 lines (172 loc) · 7.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
using System;
using System.Collections.Generic;
using System.IO; // Aggiunto per DirectoryInfo
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace DriveVision
{
public class FileNode
{
public ulong Id { get; set; }
public ulong ParentId { get; set; }
public string Nome { get; set; } = string.Empty;
public string PercorsoCompleto { get; set; } = string.Empty;
public long DimensioneByte { get; set; }
public double Percentuale { get; set; }
public bool IsDirectory { get; set; }
public List<FileNode> Figli { get; set; } = new List<FileNode>();
public string Tipo => IsDirectory ? Translator.Get("Cartella") : Translator.Get("File");
public string DimensioneFormattata
{
get
{
if (DimensioneByte == 0) return "0 B";
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
int order = 0;
double len = DimensioneByte;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
}
}
public class MftEngine
{
// Importiamo la funzione nativa dalla nostra DLL
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public delegate void FileFoundDelegate(ulong id, ulong parentId, string nome, long dimensione, byte isDirectory);
[DllImport("MftNativeEngine.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void AvviaScansioneNativa(string letteraDrive, FileFoundDelegate callback);
public FileNode? AvviaScansione(string letteraDrive)
{
var tuttiINodi = new Dictionary<ulong, FileNode>();
string baseDrive = letteraDrive.TrimEnd('\\');
string rootPath = baseDrive + "\\";
// 1. Definiamo come gestire ogni file che arriva dal C++
FileFoundDelegate ricevitoreDati = (id, parentId, nome, dimensione, isDirectory) =>
{
var node = new FileNode
{
Id = id,
ParentId = parentId,
Nome = nome,
IsDirectory = (isDirectory == 1),
DimensioneByte = 0
};
tuttiINodi[id] = node;
};
// 2. Chiamiamo il motore C++ (la scansione ora dura una frazione di secondo!)
try
{
AvviaScansioneNativa(baseDrive, ricevitoreDati);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Errore durante scansione nativa: {ex.Message}");
// IL NOSTRO PIANO B: Invece di restituire null, avvia la scansione lenta!
return EseguiScansioneStandardLenta(rootPath);
}
// 3. Costruiamo l'albero e calcoliamo le dimensioni (tutto in C# come prima)
FileNode root = CostruisciAlbero(tuttiINodi, rootPath);
List<FileNode> listaDiSoliFile = new List<FileNode>();
AssegnaPercorsiEstraiFile(root, rootPath, listaDiSoliFile);
// Usiamo il tuo metodo parallelo super veloce
RecuperaDimensioniParallelo(listaDiSoliFile);
CalcolaDimensioniCartelle(root);
return root;
}
private FileNode CostruisciAlbero(Dictionary<ulong, FileNode> nodi, string pathRadice)
{
FileNode root = new FileNode { Nome = pathRadice, IsDirectory = true, PercorsoCompleto = pathRadice };
foreach (var nodo in nodi.Values)
{
if (nodi.TryGetValue(nodo.ParentId, out FileNode? genitore))
genitore.Figli.Add(nodo);
else
root.Figli.Add(nodo);
}
return root;
}
private void AssegnaPercorsiEstraiFile(FileNode nodo, string percorsoAttuale, List<FileNode> listaFile)
{
foreach (var figlio in nodo.Figli)
{
figlio.PercorsoCompleto = percorsoAttuale + figlio.Nome;
if (figlio.IsDirectory)
{
figlio.PercorsoCompleto += "\\";
AssegnaPercorsiEstraiFile(figlio, figlio.PercorsoCompleto, listaFile);
}
else
{
listaFile.Add(figlio);
}
}
}
private void RecuperaDimensioniParallelo(List<FileNode> listaFile)
{
Parallel.ForEach(listaFile, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 }, file =>
{
// Ottiene la dimensione reale dei file interrogando l'SSD in parallelo
var fi = new System.IO.FileInfo(file.PercorsoCompleto);
try { file.DimensioneByte = fi.Length; } catch { file.DimensioneByte = 0; }
});
}
private void CalcolaDimensioniCartelle(FileNode nodo)
{
long dimensioneTotale = 0;
foreach (var figlio in nodo.Figli)
{
if (figlio.IsDirectory) CalcolaDimensioniCartelle(figlio);
dimensioneTotale += figlio.DimensioneByte;
}
nodo.DimensioneByte = dimensioneTotale;
if (dimensioneTotale > 0)
{
foreach (var figlio in nodo.Figli)
{
figlio.Percentuale = ((double)figlio.DimensioneByte / dimensioneTotale) * 100.0;
}
}
}
// ====================================================================
// METODI AGGIUNTI PER IL FALLBACK STANDARD (PIANO B)
// ====================================================================
private FileNode EseguiScansioneStandardLenta(string rootPath)
{
var root = new FileNode { Nome = rootPath, IsDirectory = true, PercorsoCompleto = rootPath };
EsploraCartellaStandard(root, new DirectoryInfo(rootPath));
// Usiamo il tuo stesso metodo per sommare le dimensioni alla fine
CalcolaDimensioniCartelle(root);
return root;
}
private void EsploraCartellaStandard(FileNode parentNode, DirectoryInfo dir)
{
try
{
foreach (var d in dir.GetDirectories())
{
var childNode = new FileNode { Nome = d.Name, IsDirectory = true, PercorsoCompleto = d.FullName + "\\" };
parentNode.Figli.Add(childNode);
EsploraCartellaStandard(childNode, d); // Ricorsione
}
foreach (var f in dir.GetFiles())
{
var childNode = new FileNode { Nome = f.Name, IsDirectory = false, PercorsoCompleto = f.FullName, DimensioneByte = f.Length };
parentNode.Figli.Add(childNode);
}
}
catch (UnauthorizedAccessException)
{
// Ignora silenziosamente le cartelle di sistema a cui non abbiamo accesso
}
catch (Exception)
{
// Ignora altri errori di lettura file
}
}
}
}