2020// DEALINGS IN THE SOFTWARE.
2121//
2222
23+ using DiscUtils . Streams ;
2324using System ;
25+ using System . Buffers ;
2426using System . Collections . Generic ;
2527using System . IO ;
2628using System . Threading ;
2729using System . Threading . Tasks ;
28- using DiscUtils . Streams ;
2930
3031namespace DiscUtils . Ntfs ;
3132
@@ -36,6 +37,8 @@ internal class ClusterBitmap : IDisposable
3637
3738 private long _nextDataCluster ;
3839
40+ private long ? _usedClusters ;
41+
3942 public ClusterBitmap ( File file )
4043 {
4144 _file = file ;
@@ -47,6 +50,35 @@ public ClusterBitmap(File file)
4750
4851 internal Bitmap Bitmap { get ; private set ; }
4952
53+ public long GetUsedClustersCount ( )
54+ {
55+ if ( _usedClusters is null )
56+ {
57+ long usedClusters = 0 ;
58+ long processed = 0 ;
59+
60+ var bufferSize = ( int ) Math . Min ( 4 * Sizes . OneMiB , Bitmap . Size ) ;
61+ var buffer = ArrayPool < byte > . Shared . Rent ( bufferSize ) ;
62+ try
63+ {
64+ while ( processed < Bitmap . Size )
65+ {
66+ var count = Bitmap . GetBytes ( processed , buffer , 0 , bufferSize ) ;
67+ usedClusters += BitCounter . Count ( buffer , 0 , count ) ;
68+ processed += count ;
69+ }
70+ }
71+ finally
72+ {
73+ ArrayPool < byte > . Shared . Return ( buffer ) ;
74+ }
75+
76+ _usedClusters = usedClusters ;
77+ }
78+
79+ return _usedClusters . Value ;
80+ }
81+
5082 public void Dispose ( )
5183 {
5284 if ( Bitmap != null )
@@ -142,6 +174,8 @@ public List<Range<long, long>> AllocateClusters(long count, long proposedStart,
142174 _fragmentedDiskMode = numFound / result . Count < 4 ;
143175 }
144176
177+ _usedClusters += total ;
178+
145179 return result ;
146180 }
147181
@@ -232,19 +266,25 @@ public async ValueTask<List<Range<long, long>>> AllocateClustersAsync(long count
232266 _fragmentedDiskMode = numFound / result . Count < 4 ;
233267 }
234268
269+ _usedClusters += total ;
270+
235271 return result ;
236272 }
237273
238274 internal void MarkAllocated ( long first , long count )
239275 {
240276 Bitmap . MarkPresentRange ( first , count ) ;
277+
278+ _usedClusters += count ;
241279 }
242280
243281 internal void FreeClusters ( IEnumerable < Range < long , long > > runs )
244282 {
245283 foreach ( var run in runs )
246284 {
247285 Bitmap . MarkAbsentRange ( run . Offset , run . Count ) ;
286+
287+ _usedClusters -= run . Count ;
248288 }
249289 }
250290
@@ -253,17 +293,23 @@ internal async ValueTask FreeClustersAsync(IEnumerable<Range<long, long>> runs,
253293 foreach ( var run in runs )
254294 {
255295 await Bitmap . MarkAbsentRangeAsync ( run . Offset , run . Count , cancellationToken ) . ConfigureAwait ( false ) ;
296+
297+ _usedClusters -= run . Count ;
256298 }
257299 }
258300
259301 internal void FreeClusters ( Range < long , long > run )
260302 {
261303 Bitmap . MarkAbsentRange ( run . Offset , run . Count ) ;
304+
305+ _usedClusters -= run . Count ;
262306 }
263307
264- internal ValueTask FreeClustersAsync ( Range < long , long > run , CancellationToken cancellationToken )
308+ internal async ValueTask FreeClustersAsync ( Range < long , long > run , CancellationToken cancellationToken )
265309 {
266- return Bitmap . MarkAbsentRangeAsync ( run . Offset , run . Count , cancellationToken ) ;
310+ await Bitmap . MarkAbsentRangeAsync ( run . Offset , run . Count , cancellationToken ) . ConfigureAwait ( false ) ;
311+
312+ _usedClusters -= run . Count ;
267313 }
268314
269315 /// <summary>
@@ -278,6 +324,8 @@ internal void SetTotalClusters(long numClusters)
278324 var actualClusters = Bitmap . SetTotalEntries ( numClusters ) ;
279325 if ( actualClusters != numClusters )
280326 {
327+ _usedClusters = null ;
328+
281329 MarkAllocated ( numClusters , actualClusters - numClusters ) ;
282330 }
283331 }
@@ -295,6 +343,9 @@ private long ExtendRun(long count, List<Range<long, long>> result, long start, l
295343 if ( numFound > 0 )
296344 {
297345 Bitmap . MarkPresentRange ( start , numFound ) ;
346+
347+ _usedClusters += numFound ;
348+
298349 result . Add ( new Range < long , long > ( start , numFound ) ) ;
299350 }
300351
@@ -314,6 +365,9 @@ private async ValueTask<long> ExtendRunAsync(long count, List<Range<long, long>>
314365 if ( numFound > 0 )
315366 {
316367 await Bitmap . MarkPresentRangeAsync ( start , numFound , cancellationToken ) . ConfigureAwait ( false ) ;
368+
369+ _usedClusters += numFound ;
370+
317371 result . Add ( new Range < long , long > ( start , numFound ) ) ;
318372 }
319373
0 commit comments