浏览代码

Individual configuration storage sections can be set read-only

Source commit: 832ea7efbd56d8520fb2073c95705db4bec6d3c3
Martin Prikryl 6 年之前
父节点
当前提交
7861d4c851
共有 2 个文件被更改,包括 178 次插入12 次删除
  1. 164 10
      source/core/HierarchicalStorage.cpp
  2. 14 2
      source/core/HierarchicalStorage.h

+ 164 - 10
source/core/HierarchicalStorage.cpp

@@ -102,6 +102,9 @@ UnicodeString __fastcall UnMungeIniName(const UnicodeString & Str)
   }
 }
 //===========================================================================
+UnicodeString AccessValueName(L"Access");
+UnicodeString DefaultAccessString(L"inherit");
+//---------------------------------------------------------------------------
 __fastcall THierarchicalStorage::THierarchicalStorage(const UnicodeString & AStorage)
 {
   FStorage = AStorage;
@@ -113,6 +116,8 @@ __fastcall THierarchicalStorage::THierarchicalStorage(const UnicodeString & ASto
   // data written in Unicode/UTF8 can be read by all versions back to 5.0.
   ForceAnsi = false;
   MungeStringValues = true;
+  FFakeReadOnlyOpens = 0;
+  FRootAccess = -1;
 }
 //---------------------------------------------------------------------------
 __fastcall THierarchicalStorage::~THierarchicalStorage()
@@ -154,13 +159,86 @@ UnicodeString __fastcall THierarchicalStorage::MungeKeyName(const UnicodeString
 {
   UnicodeString Result = MungeStr(Key, ForceAnsi, false);
   // if there's already ANSI-munged subkey, keep ANSI munging
-  if ((Result != Key) && !ForceAnsi && DoKeyExists(Key, true))
+  if ((Result != Key) && !ForceAnsi && CanRead() && DoKeyExists(Key, true))
   {
     Result = MungeStr(Key, true, false);
   }
   return Result;
 }
 //---------------------------------------------------------------------------
+UnicodeString __fastcall THierarchicalStorage::DoReadRootAccessString()
+{
+  UnicodeString Result;
+  if (OpenRootKey(false))
+  {
+    Result = ReadAccessString();
+    CloseSubKey();
+  }
+  else
+  {
+    Result = DefaultAccessString;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+UnicodeString __fastcall THierarchicalStorage::ReadAccessString()
+{
+  UnicodeString Result;
+  if (!FKeyHistory.empty())
+  {
+    Result = ReadString(AccessValueName, DefaultAccessString);
+  }
+  else
+  {
+    Result = DoReadRootAccessString();
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+unsigned int __fastcall THierarchicalStorage::ReadAccess(unsigned int CurrentAccess)
+{
+  UnicodeString Access = ReadAccessString();
+  unsigned int Result = 0;
+  while (!Access.IsEmpty())
+  {
+    UnicodeString Token = CutToChar(Access, L',', true);
+    if (SameText(Token, L"inherit"))
+    {
+      Result |= CurrentAccess;
+    }
+    else if (SameText(Token, "read"))
+    {
+      Result |= hsaRead;
+    }
+    else if (SameText(Token, "full"))
+    {
+      Result |= hsaRead | hsaWrite;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+unsigned int __fastcall THierarchicalStorage::GetCurrentAccess()
+{
+  unsigned int Result;
+  if (!FKeyHistory.empty())
+  {
+    // We must have resolved root access when opening the sub key the latest.
+    DebugAssert(FRootAccess >= 0);
+    Result = FKeyHistory.back().Access;
+  }
+  else
+  {
+    if (FRootAccess < 0)
+    {
+      FRootAccess = hsaRead; // Prevent recursion to allow reading the access
+      FRootAccess = ReadAccess(hsaRead | hsaWrite);
+    }
+    Result = FRootAccess;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 bool __fastcall THierarchicalStorage::OpenSubKeyPath(const UnicodeString & KeyPath, bool CanCreate)
 {
   DebugAssert(!KeyPath.IsEmpty() && (KeyPath[KeyPath.Length()] != L'\\'));
@@ -197,14 +275,32 @@ bool __fastcall THierarchicalStorage::OpenSubKey(const UnicodeString & Key, bool
 {
   UnicodeString MungedKey = MungeKeyName(Key);
 
-  bool Result = DoOpenSubKey(MungedKey, CanCreate);
+  bool Result;
+  unsigned int InheritAccess;
+  unsigned int Access;
+  // For the first open, CanWrite > GetCurrentAccess > ReadAccess has a (needed) side effect of caching root access.
+  if (!CanWrite() && CanCreate && !KeyExists(MungedKey))
+  {
+    InheritAccess = Access = 0; // do not even try to read the access, as the key is actually not opened
+    FFakeReadOnlyOpens++;
+    Result = true;
+  }
+  else
+  {
+    Access = hsaRead; // allow reading the access
+    InheritAccess = GetCurrentAccess();
+    Result = DoOpenSubKey(MungedKey, CanCreate);
+  }
 
   if (Result)
   {
     TKeyEntry Entry;
     Entry.Key = IncludeTrailingBackslash(CurrentSubKey + MungedKey);
     Entry.Levels = 1;
+    Entry.Access = Access;
     FKeyHistory.push_back(Entry);
+    // Read the real access only now, that the key is finally opened (it's in FKeyHistory)
+    FKeyHistory.back().Access = ReadAccess(InheritAccess);
   }
 
   return Result;
@@ -236,7 +332,14 @@ void __fastcall THierarchicalStorage::CloseSubKey()
 
   DebugAssert(FKeyHistory.back().Levels == 1);
   FKeyHistory.pop_back();
-  DoCloseSubKey();
+  if (FFakeReadOnlyOpens > 0)
+  {
+    FFakeReadOnlyOpens--;
+  }
+  else
+  {
+    DoCloseSubKey();
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall THierarchicalStorage::CloseAll()
@@ -259,14 +362,26 @@ void __fastcall THierarchicalStorage::ClearSubKeys()
 //---------------------------------------------------------------------------
 void __fastcall THierarchicalStorage::RecursiveDeleteSubKey(const UnicodeString & Key)
 {
-  if (CanWrite())
+  bool CanWriteParent = CanWrite();
+  if (OpenSubKey(Key, false))
   {
-    if (OpenSubKey(Key, false))
+    bool CanWriteKey = CanWrite();
+    ClearSubKeys();
+
+    // Cannot delete the key itself, but can delete its contents, so at least delete the values
+    // (which would otherwise be deleted implicitly by DoDeleteSubKey)
+    if (!CanWriteParent && CanWrite())
     {
-      ClearSubKeys();
-      CloseSubKey();
+      ClearValues();
+    }
+
+    CloseSubKey();
+
+    // Only if all subkeys were successfully deleted in ClearSubKeys
+    if (CanWriteParent && HasSubKeys())
+    {
+      DoDeleteSubKey(Key);
     }
-    DoDeleteSubKey(Key);
   }
 }
 //---------------------------------------------------------------------------
@@ -362,9 +477,17 @@ void __fastcall THierarchicalStorage::WriteValues(TStrings * Strings, bool Maint
   }
 }
 //---------------------------------------------------------------------------
+bool __fastcall THierarchicalStorage::HasAccess(unsigned int Access)
+{
+  return
+    FLAGSET(GetCurrentAccess(), Access) &&
+    // There should never be any kind of access to a non-existent key
+    DebugAlwaysTrue(FFakeReadOnlyOpens == 0);
+}
+//---------------------------------------------------------------------------
 bool __fastcall THierarchicalStorage::CanRead()
 {
-  return true;
+  return HasAccess(hsaRead);
 }
 //---------------------------------------------------------------------------
 void __fastcall THierarchicalStorage::GetSubKeyNames(TStrings * Strings)
@@ -384,6 +507,19 @@ void __fastcall THierarchicalStorage::GetValueNames(TStrings * Strings)
   if (CanRead())
   {
     DoGetValueNames(Strings);
+
+    int Index = 0;
+    while (Index < Strings->Count)
+    {
+      if (SameText(Strings->Strings[Index], AccessValueName))
+      {
+        Strings->Delete(Index);
+      }
+      else
+      {
+        Index++;
+      }
+    }
   }
   else
   {
@@ -531,7 +667,7 @@ RawByteString __fastcall THierarchicalStorage::ReadStringAsBinaryData(const Unic
 //---------------------------------------------------------------------------
 bool __fastcall THierarchicalStorage::CanWrite()
 {
-  return true;
+  return HasAccess(hsaWrite);
 }
 //---------------------------------------------------------------------------
 void __fastcall THierarchicalStorage::WriteBool(const UnicodeString & Name, bool Value)
@@ -986,6 +1122,9 @@ bool __fastcall TCustomIniFileStorage::OpenSubKey(const UnicodeString & Key, boo
 {
   bool Result;
 
+  // To cache root access in advance, otherwise we end up calling outselves, what TAutoFlag does not like
+  GetCurrentAccess();
+
   {
     TAutoFlag Flag(FOpeningSubKey);
     Result = THierarchicalStorage::OpenSubKey(Key, CanCreate);
@@ -1357,6 +1496,21 @@ void __fastcall TCustomIniFileStorage::DoWriteBinaryData(const UnicodeString & N
   }
   DoWriteStringRawInternal(Name, BytesToHex(RawByteString(static_cast<const char*>(Buffer), Size)));
 }
+//---------------------------------------------------------------------------
+UnicodeString __fastcall TCustomIniFileStorage::DoReadRootAccessString()
+{
+  UnicodeString Result;
+  if (OpenSubKey(L"_", false))
+  {
+    Result = ReadAccessString();
+    CloseSubKey();
+  }
+  else
+  {
+    Result = DefaultAccessString;
+  }
+  return Result;
+}
 //===========================================================================
 TIniFileStorage * __fastcall TIniFileStorage::CreateFromPath(const UnicodeString & AStorage)
 {

+ 14 - 2
source/core/HierarchicalStorage.h

@@ -69,10 +69,12 @@ public:
   __property bool Temporary = { read = GetTemporary };
 
 protected:
+  enum THierarchicalStorageAccess { hsaRead = 0x01, hsaWrite = 0x02 };
   struct TKeyEntry
   {
     UnicodeString Key;
     int Levels;
+    unsigned int Access;
   };
 
   UnicodeString FStorage;
@@ -82,6 +84,8 @@ protected:
   bool FForceSave;
   bool FMungeStringValues;
   bool FForceAnsi;
+  int FFakeReadOnlyOpens;
+  int FRootAccess;
 
   UnicodeString __fastcall GetCurrentSubKey();
   UnicodeString __fastcall GetCurrentSubKeyMunged();
@@ -117,9 +121,15 @@ protected:
 
   virtual size_t __fastcall DoBinaryDataSize(const UnicodeString & Name) = 0;
 
+  virtual UnicodeString __fastcall DoReadRootAccessString();
+
   size_t __fastcall BinaryDataSize(const UnicodeString & Name);
-  bool __fastcall CanRead();
-  bool __fastcall CanWrite();
+  UnicodeString __fastcall ReadAccessString();
+  unsigned int __fastcall ReadAccess(unsigned int CurrentAccess);
+  inline bool __fastcall HasAccess(unsigned int Access);
+  inline bool __fastcall CanRead();
+  inline bool __fastcall CanWrite();
+  unsigned int __fastcall GetCurrentAccess();
 };
 //---------------------------------------------------------------------------
 class TRegistryStorage : public THierarchicalStorage
@@ -217,6 +227,8 @@ protected:
   virtual UnicodeString __fastcall DoReadStringRaw(const UnicodeString & Name, const UnicodeString & Default);
   virtual size_t __fastcall DoReadBinaryData(const UnicodeString & Name, void * Buffer, size_t Size);
 
+  virtual UnicodeString __fastcall DoReadRootAccessString();
+
   void __fastcall CacheSections();
   void __fastcall ResetCache();
   bool __fastcall DoKeyExistsInternal(const UnicodeString & SubKey);