@@ -979,7 +979,11 @@ internal bool GetPhysicalFileFromServer(string serverPath, string pdbIndexPath,
979979 {
980980 m_log . WriteLine ( "FindSymbolFilePath: In task, sending HTTP request {0}" , fullUri ) ;
981981
982- var responseTask = HttpClient . GetAsync ( fullUri , HttpCompletionOption . ResponseHeadersRead ) ;
982+ // Tell the symbol server that we support MSFZ symbols
983+ var request = new HttpRequestMessage ( HttpMethod . Get , fullUri ) ;
984+ request . Headers . Add ( "Accept" , "application/msfz0" ) ;
985+
986+ var responseTask = HttpClient . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead ) ;
983987 responseTask . Wait ( ) ;
984988 var response = responseTask . Result . EnsureSuccessStatusCode ( ) ;
985989
@@ -1094,6 +1098,55 @@ internal bool GetPhysicalFileFromServer(string serverPath, string pdbIndexPath,
10941098 return successful && File . Exists ( fullDestPath ) ;
10951099 }
10961100
1101+ /// <summary>
1102+ /// Checks if the file at the given path is an MSFZ file by checking for the "Microsoft MSFZ Container" header
1103+ /// </summary>
1104+ private bool IsMsfzFile ( string filePath )
1105+ {
1106+ try
1107+ {
1108+ if ( ! File . Exists ( filePath ) )
1109+ {
1110+ return false ;
1111+ }
1112+
1113+ const string msfzHeader = "Microsoft MSFZ Container" ;
1114+ var headerBytes = Encoding . UTF8 . GetBytes ( msfzHeader ) ;
1115+
1116+ using ( var stream = File . OpenRead ( filePath ) )
1117+ {
1118+ if ( stream . Length < headerBytes . Length )
1119+ {
1120+ return false ;
1121+ }
1122+
1123+ // Read the header in one operation
1124+ var buffer = new byte [ headerBytes . Length ] ;
1125+ int bytesRead = stream . Read ( buffer , 0 , buffer . Length ) ;
1126+ if ( bytesRead < headerBytes . Length )
1127+ {
1128+ return false ;
1129+ }
1130+
1131+ // Compare the header
1132+ for ( int i = 0 ; i < headerBytes . Length ; i ++ )
1133+ {
1134+ if ( buffer [ i ] != headerBytes [ i ] )
1135+ {
1136+ return false ;
1137+ }
1138+ }
1139+
1140+ return true ;
1141+ }
1142+ }
1143+ catch ( Exception e )
1144+ {
1145+ m_log . WriteLine ( "IsMsfzFile: Error checking file {0}: {1}" , filePath , e . Message ) ;
1146+ return false ;
1147+ }
1148+ }
1149+
10971150 /// <summary>
10981151 /// Build the full uri from server path and pdb index path
10991152 /// </summary>
@@ -1209,16 +1262,29 @@ private long CopyStreamToFile(Stream fromStream, string fromUri, string fullDest
12091262 /// <returns>targetPath or null if the file cannot be found.</returns>
12101263 private string GetFileFromServer ( string urlForServer , string fileIndexPath , string targetPath )
12111264 {
1265+ // First check if the file exists in the normal cache location
12121266 if ( File . Exists ( targetPath ) )
12131267 {
12141268 m_log . WriteLine ( "FindSymbolFilePath: Found in cache {0}" , targetPath ) ;
12151269 return targetPath ;
12161270 }
12171271
1272+ // Also check if an MSFZ version exists in the msfz0 subdirectory
1273+ var directory = Path . GetDirectoryName ( targetPath ) ;
1274+ var fileName = Path . GetFileName ( targetPath ) ;
1275+ var msfzDirectory = Path . Combine ( directory , "msfz0" ) ;
1276+ var msfzTargetPath = Path . Combine ( msfzDirectory , fileName ) ;
1277+
1278+ if ( File . Exists ( msfzTargetPath ) )
1279+ {
1280+ m_log . WriteLine ( "FindSymbolFilePath: Found MSFZ file in cache {0}" , msfzTargetPath ) ;
1281+ return msfzTargetPath ;
1282+ }
1283+
12181284 // Fail quickly if instructed to
12191285 if ( ( Options & SymbolReaderOptions . CacheOnly ) != 0 )
12201286 {
1221- m_log . WriteLine ( "FindSymbolFilePath: no file at cache location {0} and cacheOnly set, giving up." , targetPath ) ;
1287+ m_log . WriteLine ( "FindSymbolFilePath: no file at cache location {0} or {1} and cacheOnly set, giving up." , targetPath , msfzTargetPath ) ;
12221288 return null ;
12231289 }
12241290
@@ -1228,6 +1294,9 @@ private string GetFileFromServer(string urlForServer, string fileIndexPath, stri
12281294 return null ;
12291295 }
12301296
1297+ // Download to a .new file first
1298+ var tempTargetPath = targetPath + ".new" ;
1299+
12311300 // Allows us to reject files that are not binary (sometimes you get redirected to a
12321301 // login script and we don't want to blindly accept that).
12331302 Predicate < string > onlyBinaryContent = delegate ( string contentType )
@@ -1241,11 +1310,37 @@ private string GetFileFromServer(string urlForServer, string fileIndexPath, stri
12411310 return ret ;
12421311 } ;
12431312
1244- // Just try to fetch the file directly
1313+ // Just try to fetch the file directly to .new location
12451314 m_log . WriteLine ( "FindSymbolFilePath: Searching Symbol Server {0}." , urlForServer ) ;
1246- if ( GetPhysicalFileFromServer ( urlForServer , fileIndexPath , targetPath , onlyBinaryContent ) )
1315+ if ( GetPhysicalFileFromServer ( urlForServer , fileIndexPath , tempTargetPath , onlyBinaryContent ) )
12471316 {
1248- return targetPath ;
1317+ // Check if the downloaded file is an MSFZ file and place it appropriately
1318+ if ( IsMsfzFile ( tempTargetPath ) )
1319+ {
1320+ // Create msfz0 directory and move file there
1321+ Directory . CreateDirectory ( msfzDirectory ) ;
1322+
1323+ // If MSFZ file already exists at destination, delete it first
1324+ if ( File . Exists ( msfzTargetPath ) )
1325+ {
1326+ FileUtilities . ForceDelete ( msfzTargetPath ) ;
1327+ }
1328+
1329+ FileUtilities . ForceMove ( tempTargetPath , msfzTargetPath ) ;
1330+ m_log . WriteLine ( "FindSymbolFilePath: Moved MSFZ file from {0} to {1}" , tempTargetPath , msfzTargetPath ) ;
1331+ return msfzTargetPath ;
1332+ }
1333+ else
1334+ {
1335+ // Regular PDB file - move to target location
1336+ if ( File . Exists ( targetPath ) )
1337+ {
1338+ FileUtilities . ForceDelete ( targetPath ) ;
1339+ }
1340+
1341+ FileUtilities . ForceMove ( tempTargetPath , targetPath ) ;
1342+ return targetPath ;
1343+ }
12491344 }
12501345
12511346 // The rest of this compressed file/file pointers stuff is only for remote servers.
@@ -1259,18 +1354,47 @@ private string GetFileFromServer(string urlForServer, string fileIndexPath, stri
12591354 var compressedFilePath = targetPath . Substring ( 0 , targetPath . Length - 1 ) + "_" ;
12601355 if ( GetPhysicalFileFromServer ( urlForServer , compressedSigPath , compressedFilePath , onlyBinaryContent ) )
12611356 {
1262- // Decompress it
1263- m_log . WriteLine ( "FindSymbolFilePath: Expanding {0} to {1}" , compressedFilePath , targetPath ) ;
1264- var commandLine = "Expand " + Command . Quote ( compressedFilePath ) + " " + Command . Quote ( targetPath ) ;
1357+ // Decompress to temporary path first
1358+ var tempExpandPath = targetPath + ".expanding" ;
1359+ m_log . WriteLine ( "FindSymbolFilePath: Expanding {0} to {1}" , compressedFilePath , tempExpandPath ) ;
1360+ var commandLine = "Expand " + Command . Quote ( compressedFilePath ) + " " + Command . Quote ( tempExpandPath ) ;
12651361 var options = new CommandOptions ( ) . AddNoThrow ( ) ;
12661362 var command = Command . Run ( commandLine , options ) ;
12671363 if ( command . ExitCode != 0 )
12681364 {
12691365 m_log . WriteLine ( "FindSymbolFilePath: Failure executing: {0}" , commandLine ) ;
1366+ FileUtilities . ForceDelete ( tempExpandPath ) ;
12701367 return null ;
12711368 }
1272- File . Delete ( compressedFilePath ) ;
1273- return targetPath ;
1369+ FileUtilities . ForceDelete ( compressedFilePath ) ;
1370+
1371+ // Check if the decompressed file is an MSFZ file and move it to the appropriate location
1372+ if ( IsMsfzFile ( tempExpandPath ) )
1373+ {
1374+ // Create msfz0 directory and move file there
1375+ Directory . CreateDirectory ( msfzDirectory ) ;
1376+
1377+ // If MSFZ file already exists at destination, delete it first
1378+ if ( File . Exists ( msfzTargetPath ) )
1379+ {
1380+ FileUtilities . ForceDelete ( msfzTargetPath ) ;
1381+ }
1382+
1383+ FileUtilities . ForceMove ( tempExpandPath , msfzTargetPath ) ;
1384+ m_log . WriteLine ( "FindSymbolFilePath: Moved decompressed MSFZ file from {0} to {1}" , tempExpandPath , msfzTargetPath ) ;
1385+ return msfzTargetPath ;
1386+ }
1387+ else
1388+ {
1389+ // Regular PDB file - move to target location
1390+ if ( File . Exists ( targetPath ) )
1391+ {
1392+ FileUtilities . ForceDelete ( targetPath ) ;
1393+ }
1394+
1395+ FileUtilities . ForceMove ( tempExpandPath , targetPath ) ;
1396+ return targetPath ;
1397+ }
12741398 }
12751399
12761400 // See if we have a file that tells us to redirect elsewhere.
0 commit comments