1- using  System . Collections . Concurrent ; 
1+ // Copyright (c) 2024 Files Community 
2+ // Licensed under the MIT License. See the LICENSE. 
3+ 
4+ using  System . Collections . Concurrent ; 
25using  System . IO ; 
3- using  Vanara . PInvoke ; 
4- using  static   Vanara . PInvoke . Kernel32 ; 
6+ using  Windows . Win32 ; 
7+ using  Windows . Win32 . Storage . FileSystem ; 
58
69namespace  Files . App . Utils . Storage . Operations 
710{ 
@@ -22,7 +25,18 @@ public FileSizeCalculator(params string[] paths)
2225
2326		public  async  Task  ComputeSizeAsync ( CancellationToken  cancellationToken  =  default ) 
2427		{ 
25- 			await  Parallel . ForEachAsync ( _paths ,  cancellationToken ,  async  ( path ,  token )  =>  await  Task . Factory . StartNew ( ( )  => 
28+ 			await  Parallel . ForEachAsync ( 
29+ 				_paths , 
30+ 				cancellationToken , 
31+ 				async  ( path ,  token )  =>  await  Task . Factory . StartNew ( ( )  => 
32+ 					{ 
33+ 						ComputeSizeRecursively ( path ,  token ) ; 
34+ 					} , 
35+ 					token , 
36+ 					TaskCreationOptions . LongRunning , 
37+ 					TaskScheduler . Default ) ) ; 
38+ 
39+ 			unsafe  void  ComputeSizeRecursively ( string  path ,  CancellationToken  token ) 
2640			{ 
2741				var  queue  =  new  Queue < string > ( ) ; 
2842				if  ( ! Win32Helper . HasFileAttribute ( path ,  FileAttributes . Directory ) ) 
@@ -35,76 +49,78 @@ await Parallel.ForEachAsync(_paths, cancellationToken, async (path, token) => aw
3549
3650					while  ( queue . TryDequeue ( out  var  directory ) ) 
3751					{ 
38- 						using  var  hFile  =  FindFirstFileEx ( 
39- 							directory  +  "\\ *.*" , 
40- 							FINDEX_INFO_LEVELS . FindExInfoBasic , 
41- 							out  WIN32_FIND_DATA  findData , 
42- 							FINDEX_SEARCH_OPS . FindExSearchNameMatch , 
43- 							IntPtr . Zero , 
44- 							FIND_FIRST . FIND_FIRST_EX_LARGE_FETCH ) ; 
45- 
46- 						if  ( ! hFile . IsInvalid ) 
52+ 						WIN32_FIND_DATAW  findData  =  default ; 
53+ 
54+ 						fixed ( char *  pszFilePath  =  directory  +  "\\ *.*" ) 
4755						{ 
48- 							do 
56+ 							var  hFile  =  PInvoke . FindFirstFileEx ( 
57+ 								pszFilePath , 
58+ 								FINDEX_INFO_LEVELS . FindExInfoBasic , 
59+ 								& findData , 
60+ 								FINDEX_SEARCH_OPS . FindExSearchNameMatch , 
61+ 								null , 
62+ 								FIND_FIRST_EX_FLAGS . FIND_FIRST_EX_LARGE_FETCH ) ; 
63+ 
64+ 							if  ( ! hFile . IsNull ) 
4965							{ 
50- 								if   ( ( findData . dwFileAttributes   &   FileAttributes . ReparsePoint )   ==   FileAttributes . ReparsePoint ) 
51- 									 // Skip symbolic links and junctions 
52- 									continue ; 
66+ 								do 
67+ 								{ 
68+ 									FILE_FLAGS_AND_ATTRIBUTES   attributes   =   ( FILE_FLAGS_AND_ATTRIBUTES ) findData . dwFileAttributes ; 
5369
54- 								var  itemPath  =  Path . Combine ( directory ,  findData . cFileName ) ; 
70+ 									if  ( attributes . HasFlag ( FILE_FLAGS_AND_ATTRIBUTES . FILE_ATTRIBUTE_REPARSE_POINT ) ) 
71+ 										// Skip symbolic links and junctions 
72+ 										continue ; 
5573
56- 								if  ( ( findData . dwFileAttributes  &  FileAttributes . Directory )  !=  FileAttributes . Directory ) 
57- 								{ 
58- 									ComputeFileSize ( itemPath ) ; 
59- 								} 
60- 								else  if  ( findData . cFileName  !=  "."  &&  findData . cFileName  !=  ".." ) 
61- 								{ 
62- 									queue . Enqueue ( itemPath ) ; 
63- 								} 
74+ 									var  itemPath  =  Path . Combine ( directory ,  findData . cFileName . ToString ( ) ) ; 
75+ 
76+ 									if  ( attributes . HasFlag ( FILE_FLAGS_AND_ATTRIBUTES . FILE_ATTRIBUTE_DIRECTORY ) ) 
77+ 									{ 
78+ 										ComputeFileSize ( itemPath ) ; 
79+ 									} 
80+ 									else  if  ( findData . cFileName . ToString ( )  is  string  fileName  && 
81+ 										fileName . Equals ( "." ,  StringComparison . OrdinalIgnoreCase )  && 
82+ 										fileName . Equals ( ".." ,  StringComparison . OrdinalIgnoreCase ) ) 
83+ 									{ 
84+ 										queue . Enqueue ( itemPath ) ; 
85+ 									} 
6486
65- 								if  ( token . IsCancellationRequested ) 
66- 									break ; 
87+ 									if  ( token . IsCancellationRequested ) 
88+ 										break ; 
89+ 								} 
90+ 								while  ( PInvoke . FindNextFile ( hFile ,  & findData ) ) ; 
6791							} 
68- 							while  ( FindNextFile ( hFile ,  out  findData ) ) ; 
92+ 
93+ 							PInvoke . CloseHandle ( hFile ) ; 
6994						} 
7095					} 
7196				} 
72- 			} ,   token ,   TaskCreationOptions . LongRunning ,   TaskScheduler . Default ) ) ; 
97+ 			} 
7398		} 
7499
75100		private  long  ComputeFileSize ( string  path ) 
76101		{ 
77102			if  ( _computedFiles . TryGetValue ( path ,  out  var  size ) ) 
78- 			{ 
79103				return  size ; 
80- 			} 
81104
82- 			using  var  hFile  =  CreateFile ( 
105+ 			using  var  hFile  =  PInvoke . CreateFile ( 
83106				path , 
84- 				Kernel32 . FileAccess . FILE_READ_ATTRIBUTES , 
85- 				FileShare . Read , 
107+ 				( uint ) FILE_ACCESS_RIGHTS . FILE_READ_ATTRIBUTES , 
108+ 				FILE_SHARE_MODE . FILE_SHARE_READ , 
86109				null , 
87- 				FileMode . Open , 
110+ 				FILE_CREATION_DISPOSITION . OPEN_EXISTING , 
88111				0 , 
89112				null ) ; 
90113
91- 			if  ( ! hFile . IsInvalid ) 
92- 			{ 
93- 				if  ( GetFileSizeEx ( hFile ,  out  size )  &&  _computedFiles . TryAdd ( path ,  size ) ) 
94- 				{ 
95- 					Interlocked . Add ( ref  _size ,  size ) ; 
96- 				} 
97- 			} 
114+ 			if  ( ! hFile . IsInvalid  &&  PInvoke . GetFileSizeEx ( hFile ,  out  size )  &&  _computedFiles . TryAdd ( path ,  size ) ) 
115+ 				Interlocked . Add ( ref  _size ,  size ) ; 
98116
99117			return  size ; 
100118		} 
101119
102120		public  void  ForceComputeFileSize ( string  path ) 
103121		{ 
104122			if  ( ! Win32Helper . HasFileAttribute ( path ,  FileAttributes . Directory ) ) 
105- 			{ 
106123				ComputeFileSize ( path ) ; 
107- 			} 
108124		} 
109125
110126		public  bool  TryGetComputedFileSize ( string  path ,  out  long  size ) 
0 commit comments