Browse Source

Bug 1523: Failure when INI file cannot be opened

https://winscp.net/tracker/1523

Source commit: 6549953dc304424256eac517bf6137600d5d6d27
Martin Prikryl 8 years ago
parent
commit
4b27e2e834

+ 4 - 4
source/core/Configuration.cpp

@@ -163,12 +163,12 @@ THierarchicalStorage * TConfiguration::CreateScpStorage(bool & SessionList)
   }
   else if (Storage == stNul)
   {
-    Result = new TIniFileStorage(INI_NUL);
+    Result = TIniFileStorage::CreateFromPath(INI_NUL);
   }
   else
   {
     UnicodeString StorageName = IniFileStorageName;
-    Result = new TIniFileStorage(StorageName);
+    Result = TIniFileStorage::CreateFromPath(StorageName);
   }
 
   if ((FOptionsStorage.get() != NULL) && (FOptionsStorage->Count > 0))
@@ -327,7 +327,7 @@ void __fastcall TConfiguration::Export(const UnicodeString & FileName)
   THierarchicalStorage * ExportStorage = NULL;
   try
   {
-    ExportStorage = new TIniFileStorage(FileName);
+    ExportStorage = TIniFileStorage::CreateFromPath(FileName);
     ExportStorage->AccessMode = smReadWrite;
     ExportStorage->Explicit = true;
 
@@ -356,7 +356,7 @@ void __fastcall TConfiguration::Import(const UnicodeString & FileName)
   THierarchicalStorage * ImportStorage = NULL;
   try
   {
-    ImportStorage = new TIniFileStorage(FileName);
+    ImportStorage = TIniFileStorage::CreateFromPath(FileName);
     ImportStorage->AccessMode = smRead;
 
     Storage = CreateConfigStorage();

+ 11 - 2
source/core/HierarchicalStorage.cpp

@@ -1181,8 +1181,17 @@ void __fastcall TCustomIniFileStorage::WriteBinaryData(const UnicodeString Name,
   DoWriteBinaryData(Name, Buffer, Size);
 }
 //===========================================================================
-__fastcall TIniFileStorage::TIniFileStorage(const UnicodeString AStorage):
-  TCustomIniFileStorage(AStorage, new TMemIniFile(AStorage))
+TIniFileStorage * __fastcall TIniFileStorage::CreateFromPath(const UnicodeString AStorage)
+{
+  // The code was originally inline in the parent contructor call in the TIniFileStorage::TIniFileStorage [public originally].
+  // But if the TMemIniFile contructor throws (e.g. because the INI file is locked), the exception causes access violation.
+  // Moving the code to a factory solves this.
+  TMemIniFile * IniFile = new TMemIniFile(AStorage);
+  return new TIniFileStorage(AStorage, IniFile);
+}
+//---------------------------------------------------------------------------
+__fastcall TIniFileStorage::TIniFileStorage(const UnicodeString AStorage, TCustomIniFile * IniFile):
+  TCustomIniFileStorage(AStorage, IniFile)
 {
   FOriginal = new TStringList();
   dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(FOriginal);

+ 2 - 1
source/core/HierarchicalStorage.h

@@ -202,12 +202,13 @@ protected:
 class TIniFileStorage : public TCustomIniFileStorage
 {
 public:
-  __fastcall TIniFileStorage(const UnicodeString FileName);
+  static TIniFileStorage * __fastcall CreateFromPath(const UnicodeString AStorage);
   virtual __fastcall ~TIniFileStorage();
 
   virtual void __fastcall Flush();
 
 private:
+  __fastcall TIniFileStorage(const UnicodeString FileName, TCustomIniFile * IniFile);
   TStrings * FOriginal;
   void __fastcall ApplyOverrides();
 };

+ 1 - 1
source/core/SessionData.cpp

@@ -3997,7 +3997,7 @@ void __fastcall TStoredSessionList::ImportFromFilezilla(
 //---------------------------------------------------------------------
 void __fastcall TStoredSessionList::Export(const UnicodeString FileName)
 {
-  THierarchicalStorage * Storage = new TIniFileStorage(FileName);
+  THierarchicalStorage * Storage = TIniFileStorage::CreateFromPath(FileName);
   try
   {
     Storage->AccessMode = smReadWrite;

+ 1 - 1
source/windows/WinConfiguration.cpp

@@ -869,7 +869,7 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool & SessionList)
   THierarchicalStorage * Result;
   if (SessionList && !FTemporarySessionFile.IsEmpty())
   {
-    Result = new TIniFileStorage(FTemporarySessionFile);
+    Result = TIniFileStorage::CreateFromPath(FTemporarySessionFile);
     // This is session-list specific store, so the only instance,
     // we do not reset the SessionList argument
     // (compare TConfiguration::CreateScpStorage)