@@ -32,7 +32,7 @@ public static unsafe class FileAccessServer
3232 private static List < IEmulator > Emulators { get ; } = new ( ) ;
3333
3434 private static readonly ConcurrentDictionary < IntPtr , FileInformation > HandleToInfoMap = new ( ) ;
35- private static readonly ConcurrentDictionary < string , FileInformation ? > PathToVirtualFileMap = new ( StringComparer . OrdinalIgnoreCase ) ;
35+ private static readonly ConcurrentDictionary < string , FileInformation > PathToVirtualFileMap = new ( StringComparer . OrdinalIgnoreCase ) ;
3636 private static readonly ConcurrentDictionary < string , IntPtr > PathToHandleMap = new ( StringComparer . OrdinalIgnoreCase ) ;
3737
3838 private static readonly object ThreadLock = new ( ) ;
@@ -148,44 +148,11 @@ private static int QueryFullAttributesFileImpl(OBJECT_ATTRIBUTES* attributes, FI
148148
149149 var path = Strings . TrimWindowsPrefixes ( attributes ->ObjectName ) ;
150150
151- SafeFileHandle ? safeHandle = null ;
152-
153- if ( ! PathToHandleMap . TryGetValue ( path , out var hfile ) || ! HandleToInfoMap . TryGetValue ( hfile , out var info ) )
154- {
155- // We haven't tried to create an emulated file for this yet, try it
156- if ( ! PathToVirtualFileMap . TryGetValue ( path , out info ) )
157- {
158- // Prevent recursion
159- PathToVirtualFileMap [ path ] = null ;
160-
161- // There is a virtual file but no handle exists for it, we need to make one
162- try
163- {
164- safeHandle = File . OpenHandle ( path ) ;
165- }
166- catch ( Exception e )
167- {
168- // If we couldn't make the handle this probably isn't a file we can emulate
169- return result ;
170- }
171-
172- hfile = safeHandle . DangerousGetHandle ( ) ;
173-
174- // We tried to make one but failed, this file isn't emulated
175- if ( ! HandleToInfoMap . TryGetValue ( hfile , out info ) )
176- {
177- safeHandle . Close ( ) ;
178- return result ;
179- }
180- }
181-
182- // We've tried to create an emulated file for this before but failed, this file isn't emulated
183- if ( info == null )
184- return result ;
185- }
151+ if ( ! TryGetFileInfoFromPath ( path , out var hfile , out var info , out var newFileHandle ) )
152+ return result ;
186153
187154 var oldSize = information ->EndOfFile ;
188- var newSize = info . File . GetFileSize ( hfile , info ) ;
155+ var newSize = info ! . File . GetFileSize ( hfile , info ) ;
189156 if ( newSize != - 1 )
190157 information ->EndOfFile = newSize ;
191158
@@ -200,8 +167,7 @@ private static int QueryFullAttributesFileImpl(OBJECT_ATTRIBUTES* attributes, FI
200167 }
201168
202169 // Clean up if we needed to make a new handle
203- if ( safeHandle != null )
204- safeHandle . Close ( ) ;
170+ newFileHandle ? . Close ( ) ;
205171
206172 return result ;
207173 }
@@ -212,16 +178,19 @@ private static int QueryAttributesFileImpl(OBJECT_ATTRIBUTES* attributes, FILE_B
212178 var result = _getFileAttributesHook . OriginalFunction . Value . Invoke ( attributes , information ) ;
213179 var path = Strings . TrimWindowsPrefixes ( attributes ->ObjectName ) ;
214180
215- if ( ! PathToHandleMap . TryGetValue ( path , out var hfile ) || ! HandleToInfoMap . TryGetValue ( hfile , out var info ) )
181+ if ( ! TryGetFileInfoFromPath ( path , out var hfile , out var info , out var newFileHandle ) )
216182 return result ;
217183
218- if ( info . File . TryGetLastWriteTime ( hfile , info , out var newWriteTime ) )
184+ if ( info ! . File . TryGetLastWriteTime ( hfile , info , out var newWriteTime ) )
219185 {
220186 var oldWriteTime = information ->LastWriteTime . ToDateTime ( ) ;
221187 information ->LastWriteTime = new LARGE_INTEGER ( newWriteTime ! . Value . ToFileTimeUtc ( ) ) ;
222188 _logger . Info ( "[FileAccessServer] File Last Write Override | Old: {0}, New: {1} | {2}" , oldWriteTime ,
223189 newWriteTime , path ) ;
224190 }
191+
192+ // Clean up if we needed to make a new handle
193+ newFileHandle ? . Close ( ) ;
225194
226195 return result ;
227196 }
@@ -329,7 +298,7 @@ private static NT_STATUS NtCreateFileImpl(IntPtr* handle, FileAccess access, OBJ
329298 _logger . Debug ( "[FileAccessServer] Accessing: {0}, {1}, Route: {2}" , hndl , newFilePath , _currentRoute . FullPath ) ;
330299
331300 // Try Accept New File (virtual override)
332- if ( PathToVirtualFileMap . TryGetValue ( newFilePath , out var fileInfo ) && fileInfo != null )
301+ if ( PathToVirtualFileMap . TryGetValue ( newFilePath , out var fileInfo ) )
333302 {
334303 // Reuse of emulated file (backed by stream) is safe because file access is single threaded.
335304 lock ( ThreadLock )
@@ -349,7 +318,8 @@ private static NT_STATUS NtCreateFileImpl(IntPtr* handle, FileAccess access, OBJ
349318
350319 lock ( ThreadLock )
351320 {
352- HandleToInfoMap [ hndl ] = new ( newFilePath , 0 , emulatedFile ) ;
321+ fileInfo = new ( newFilePath , 0 , emulatedFile ) ;
322+ HandleToInfoMap [ hndl ] = fileInfo ;
353323 PathToHandleMap [ newFilePath ] = hndl ;
354324 }
355325 return ntStatus ;
@@ -363,6 +333,50 @@ private static NT_STATUS NtCreateFileImpl(IntPtr* handle, FileAccess access, OBJ
363333 }
364334 }
365335
336+ /// <summary>
337+ /// Tries to get the FileInformation for an emulated file based on its path.
338+ /// If a file at the specified path has never been created before this will attempt to create it, making the emulated file.
339+ /// </summary>
340+ /// <param name="path">The path to the file to try and get information for</param>
341+ /// <param name="hfile">The handle to the emulated file if there was one</param>
342+ /// <param name="fileInfo">The FileInformation for the emulated file if there is one, null otherwise</param>
343+ /// <param name="newFileHandle">A safe handle to the new file that was created, if one had to be created. Make sure to close this when you are done with the file info!</param>
344+ /// <returns>True if the file information for an emulated file with the specified path was found, false otherwise.</returns>
345+ private static bool TryGetFileInfoFromPath ( string path , out IntPtr hfile , out FileInformation ? fileInfo , out SafeFileHandle ? newFileHandle )
346+ {
347+ newFileHandle = null ;
348+ fileInfo = null ;
349+
350+ // We haven't tried to create an emulated file for this yet, try it
351+ if ( ! PathToHandleMap . TryGetValue ( path , out hfile ) || ( hfile != INVALID_HANDLE_VALUE && ! HandleToInfoMap . TryGetValue ( hfile , out fileInfo ) ) )
352+ {
353+ // Prevent recursion
354+ PathToHandleMap [ path ] = INVALID_HANDLE_VALUE ;
355+
356+ // There is a virtual file but no handle exists for it, we need to make one
357+ try
358+ {
359+ newFileHandle = File . OpenHandle ( path ) ;
360+ }
361+ catch ( Exception e )
362+ {
363+ // If we couldn't make the handle this probably isn't a file we can emulate
364+ return false ;
365+ }
366+
367+ hfile = newFileHandle . DangerousGetHandle ( ) ;
368+
369+ // We tried to make one but failed, this file isn't emulated
370+ if ( ! HandleToInfoMap . TryGetValue ( hfile , out fileInfo ) )
371+ {
372+ newFileHandle . Close ( ) ;
373+ return false ;
374+ }
375+ }
376+
377+ return fileInfo != null ;
378+ }
379+
366380 /// <summary>
367381 /// Determines if the given handle refers to a directory.
368382 /// </summary>
0 commit comments