desktop/source/lib/init.cxx             |   12 -
 include/osl/file.h                      |   48 ------
 include/osl/file.hxx                    |   52 ------
 include/rtl/alloc.h                     |    8 -
 sal/CppunitTest_sal_osl_file_details.mk |   43 +++++
 sal/Library_sal.mk                      |    1 
 sal/Module_sal.mk                       |    1 
 sal/inc/setallowedpaths.hxx             |   39 ++++
 sal/osl/unx/file.cxx                    |   19 --
 sal/osl/unx/file_impl.hxx               |   17 ++
 sal/qa/osl/file/forbidden.cxx           |  254 ++++++++++++++++++++++++++++++++
 sal/qa/osl/file/osl_File.cxx            |  144 ------------------
 sal/qa/rtl/alloc/rtl_alloc.cxx          |    4 
 sal/rtl/preinit.cxx                     |   51 ++++++
 sal/rtl/strimp.cxx                      |    2 
 sal/rtl/strimp.hxx                      |    2 
 sal/util/sal.map                        |    6 
 solenv/clang-format/excludelist         |    1 
 18 files changed, 425 insertions(+), 279 deletions(-)

New commits:
commit 242ccc31d5a2c8be900828523de145e173900514
Author:     Stephan Bergmann <stephan.bergm...@collabora.com>
AuthorDate: Wed Jul 2 16:31:28 2025 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Thu Jul 3 21:15:04 2025 +0200

    Avoid extending the sal UNO API
    
    ...with osl_setAllowedPaths and osl_isForbiddenPath from
    34f1a750a128e02aa3191e36a2c0b28371e96287 "sal: initial osl::File sand-boxing
    commit for Unix."  Instead:
    
    * For osl_setAllowedPaths, rather extend (in an ABI-compatible way, even) 
the
    already existing rtl_alloc_preInit, which took a sal_Bool (i.e., unsigned 
char)
    to take a sal_uInt8 (i.e., unsigned char) and let an argument "2" mean 
"call the
    (now sal-internal) setAllowedPaths with the value of the SAL_ALLOWED_PATHS 
env
    var".  (And SAL_ALLOWED_PATHS and SAL_ABORT_ON_FORBIDDEN remain undocumented
    internal env vars, whose semantics can be changed freely anytime.)
    
    * And osl_isForbiddenPath wasn't called from outside sal (other than in a
    CppunitTest, see next), anyway.
    
    The test code that had been added to CppunitTest_sal_osl (and which required
    access to osl_setAllowedPaths and osl_isForbiddenPath) is broken out into 
its
    own CppunitTest_sal_osl_file_details, which uses
    gb_CppunitTest_use_library_objects to access the (now sal-internal)
    setAllowedPaths and isForbidden.
    
    Change-Id: I6b48dce51cbb4acc8a44f0ee9d79d4f0d37cfa58
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187286
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 124289e9a2cd..5408a92bb24a 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -8271,12 +8271,8 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
     }
 
 #ifdef LINUX
-    {
-        const char *pAllowedPaths = getenv("SAL_ALLOWED_PATHS");
-        if (pAllowedPaths)
-            osl_setAllowedPaths(
-                OUString(pAllowedPaths, strlen(pAllowedPaths), 
RTL_TEXTENCODING_UTF8).pData);
-    }
+    // Enforce SAL_ALLOWED_PATHS:
+    rtl_alloc_preInit(2);
 #endif
 
     char* pAllowlist = ::getenv("LOK_HOST_ALLOWLIST");
@@ -8316,7 +8312,7 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
 
     if (eStage == PRE_INIT)
     {
-        rtl_alloc_preInit(true);
+        rtl_alloc_preInit(1);
 
         // Set the default timezone to the TZ envar, if set.
         const char* tz = ::getenv("TZ");
@@ -8623,7 +8619,7 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
 
     // staticize all strings.
     if (eStage == PRE_INIT)
-        rtl_alloc_preInit(false);
+        rtl_alloc_preInit(0);
 
     return bInitialized;
 }
diff --git a/include/osl/file.h b/include/osl/file.h
index 98ad568550b9..07d2beb2ae1f 100644
--- a/include/osl/file.h
+++ b/include/osl/file.h
@@ -960,54 +960,6 @@ SAL_DLLPUBLIC oslFileError SAL_CALL osl_readFile(
 SAL_DLLPUBLIC oslFileError SAL_CALL osl_isEndOfFile(
         oslFileHandle Handle, sal_Bool *pIsEOF );
 
-/** Resets the list of paths and associated permissions for osl
-
-    @param[in] pustrFileURLs
-    Contains a ':' delimited list of control strings and paths.
-    Control segments are a short path that refers to the following
-    segments and contain either:
-
-    r: read-only paths follow (the default)
-    w: read & write paths follow
-    x: executable paths follow
-
-    Any real paths (ie. having resolved all symlinks)
-    accessed outside of these paths will cause an
-    osl_File_E_ACCESS error in the relevant method calls.
-
-    This method is Unix specific.
-
-    @see osl_isForbiddenPath
-
-    @since LibreOffice 7.7
-*/
-SAL_DLLPUBLIC void SAL_CALL osl_setAllowedPaths(
-    rtl_uString *pustrFileURLs
-    );
-
-/**
-   Determine if the passed in path is not contained inside
-   the allowed paths, or if no allowed paths are set it
-   will not forbid any access.
-
-   @param[in] pustrFileURL
-   A URL (or path) that we want to check if it is forbidden
-   to access.
-
-   @param[in] nFlags
-   Flags to determine what type of access is requested,
-   osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'.
-
-   This method is Unix specific.
-
-   @see osl_setAllowedPaths
-
-   @since LibreOffice 7.7
- */
-SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath(
-    rtl_uString *pustrFileURL, int nFlags
-    );
-
 /** Write a number of bytes to a file.
 
     Writes a number of bytes to a file.
diff --git a/include/osl/file.hxx b/include/osl/file.hxx
index 787da4f98f31..1f1121d547e2 100644
--- a/include/osl/file.hxx
+++ b/include/osl/file.hxx
@@ -312,58 +312,6 @@ public:
 
         return static_cast< RC >( osl_createTempFile(pustr_dir_url, pHandle, 
ppustr_tmp_file_url) );
     }
-
-
-    /** Resets the list of paths and associated permissions for osl
-
-        @param[in] rPaths
-        Contains a ':' delimited list of control strings and paths.
-        Control segments are a short path that refers to the following
-        segments and contain either:
-
-        r: read-only paths follow (the default)
-        w: read & write paths follow
-        x: executable paths follow
-
-        Any real paths (ie. having resolved all symlinks)
-        accessed outside of these paths will cause an
-        osl_File_E_ACCESS error in the relevant method calls.
-
-        This method is Unix specific.
-
-        @see osl_isForbiddenPath
-
-        @since LibreOffice 7.7
-    */
-
-    static void setAllowedPaths(const ::rtl::OUString& rPaths)
-    {
-        osl_setAllowedPaths(rPaths.pData);
-    }
-
-    /**
-       Determine if the passed in path is not contained inside
-       the allowed paths, or if no allowed paths are set it
-       will not forbid any access.
-
-       @param[in] pustrFileURL
-       A URL (or path) that we want to check if it is forbidden
-       to access.
-
-       @param[in] nFlags
-       Flags to determine what type of access is requested,
-       osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'.
-
-       This method is Unix specific.
-
-       @see osl_setAllowedPaths
-
-       @since LibreOffice 7.7
-    */
-    static bool isForbidden(const ::rtl::OUString& rPath, int nFlags)
-    {
-        return osl_isForbiddenPath(rPath.pData, nFlags);
-    }
 };
 
 
diff --git a/include/rtl/alloc.h b/include/rtl/alloc.h
index 1dc9cefacb0d..bfcc9a02b186 100644
--- a/include/rtl/alloc.h
+++ b/include/rtl/alloc.h
@@ -298,8 +298,8 @@ SAL_DLLPUBLIC void SAL_CALL rtl_cache_free (
  * at the end of LibreOfficeKit pre-initialization to enable
  * various optimizations.
  *
- * Its function is to annotate a section @start = true
- * to end (@start = false) via. two calls. Inside this
+ * Its function is to annotate a section @mode = 1
+ * to end (@mode = 0) via. two calls. Inside this
  * section string allocators are replaced with ones which cause the
  * strings to be staticized at the end of the section.
  *
@@ -313,6 +313,8 @@ SAL_DLLPUBLIC void SAL_CALL rtl_cache_free (
  * This method is not thread-safe, nor intended for use in
  * a threaded context, cf. previous constraints.
  *
+ * Further @mode values may have further meanings, which may change at any 
time.
+ *
  * It is almost certainly not the method that you want,
  * use with extraordinary care referring to the
  * implementation.
@@ -320,7 +322,7 @@ SAL_DLLPUBLIC void SAL_CALL rtl_cache_free (
  * @since LibreOffice 6.1
  */
 SAL_DLLPUBLIC void SAL_CALL rtl_alloc_preInit (
-    sal_Bool start
+    sal_uInt8 mode
 ) SAL_THROW_EXTERN_C();
 /** @endcond */
 
diff --git a/sal/CppunitTest_sal_osl_file_details.mk 
b/sal/CppunitTest_sal_osl_file_details.mk
new file mode 100644
index 000000000000..acfed31c0135
--- /dev/null
+++ b/sal/CppunitTest_sal_osl_file_details.mk
@@ -0,0 +1,43 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,sal_osl_file_details))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sal_osl_file_details, \
+    sal/qa/osl/file/forbidden \
+))
+
+$(eval $(call gb_CppunitTest_add_libs,sal_osl_file_details, \
+    $(if $(filter LINUX,$(OS)), \
+        -ldl \
+        -lrt \
+    ) \
+    $(if $(filter SOLARIS,$(OS)), \
+        -lnsl \
+        -lsocket \
+    ) \
+    $(if $(filter HAIKU,$(OS)), \
+        -lnetwork \
+    ) \
+    $(BACKTRACE_LIBS) \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sal_osl_file_details, \
+    $$(INCLUDE) \
+    -I$(SRCDIR)/sal/inc \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sal_osl_file_details, \
+    dtoa \
+    zlib \
+))
+
+$(eval $(call gb_CppunitTest_use_library_objects,sal_osl_file_details,sal))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sal/Library_sal.mk b/sal/Library_sal.mk
index a7026e8327d8..94e7fe10c5ca 100644
--- a/sal/Library_sal.mk
+++ b/sal/Library_sal.mk
@@ -109,6 +109,7 @@ $(eval $(call gb_Library_add_exception_objects,sal,\
        sal/rtl/hash \
        sal/rtl/locale \
        sal/rtl/math \
+       sal/rtl/preinit \
        sal/rtl/random \
        sal/rtl/rtl_process \
        sal/rtl/strbuf \
diff --git a/sal/Module_sal.mk b/sal/Module_sal.mk
index 854d46a8e6d4..242dc3297c31 100644
--- a/sal/Module_sal.mk
+++ b/sal/Module_sal.mk
@@ -31,6 +31,7 @@ $(eval $(call gb_Module_add_check_targets,sal,\
        $(if $(filter WNT,$(OS)),CppunitTest_sal_retry_if_failed) \
        CppunitTest_sal_osl_security \
        CppunitTest_sal_osl \
+       CppunitTest_sal_osl_file_details \
        CppunitTest_sal_rtl \
        CppunitTest_sal_types \
        $(if $(COM_IS_CLANG),$(if 
$(COMPILER_EXTERNAL_TOOL)$(COMPILER_PLUGIN_TOOL),, \
diff --git a/sal/inc/setallowedpaths.hxx b/sal/inc/setallowedpaths.hxx
new file mode 100644
index 000000000000..110b7cc1a46d
--- /dev/null
+++ b/sal/inc/setallowedpaths.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#if defined UNX
+/** Resets the list of paths and associated permissions for osl
+
+    @param[in] aPaths
+    Contains a ':' delimited list of control strings and paths.
+    Control segments are a short path that refers to the following
+    segments and contain either:
+
+    r: read-only paths follow (the default)
+    w: read & write paths follow
+    x: executable paths follow
+
+    Any real paths (ie. having resolved all symlinks)
+    accessed outside of these paths will cause an
+    osl_File_E_ACCESS error in the relevant method calls.
+
+    This method is Unix specific.
+
+    @see isForbidden in sal/osl/unx/file_impl.hxx
+*/
+void setAllowedPaths(std::u16string_view aPaths);
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx
index 96f4633e42b0..45adb8b8be42 100644
--- a/sal/osl/unx/file.cxx
+++ b/sal/osl/unx/file.cxx
@@ -26,6 +26,8 @@
 #include <rtl/string.hxx>
 #include <o3tl/string_view.hxx>
 
+#include <setallowedpaths.hxx>
+
 #include "system.hxx"
 #include "createfilehandlefromfd.hxx"
 #include "file_error_transl.hxx"
@@ -844,20 +846,16 @@ static OString getParentFolder(std::string_view rFilePath)
     return folderPath;
 }
 
-SAL_DLLPUBLIC void osl_setAllowedPaths(
-        rtl_uString *pustrFilePaths
+void setAllowedPaths(
+        std::u16string_view aPaths
     )
 {
     allowedPathsRead.clear();
     allowedPathsReadWrite.clear();
     allowedPathsExecute.clear();
 
-    if (!pustrFilePaths)
-        return;
-
     char eType = 'r';
     sal_Int32 nIndex = 0;
-    OUString aPaths(pustrFilePaths);
     do
     {
         OString aPath = rtl::OUStringToOString(
@@ -965,15 +963,6 @@ bool isForbidden(const OString &filePath, int nFlags)
     return !allowed;
 }
 
-SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath(
-    rtl_uString *pustrFileURL, int nFlags
-    )
-{
-    return isForbidden(
-        rtl::OUStringToOString(OUString(pustrFileURL),
-                               RTL_TEXTENCODING_UTF8), nFlags);
-}
-
 #ifdef HAVE_O_EXLOCK
 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
diff --git a/sal/osl/unx/file_impl.hxx b/sal/osl/unx/file_impl.hxx
index 64504296955d..f0aec40c59cd 100644
--- a/sal/osl/unx/file_impl.hxx
+++ b/sal/osl/unx/file_impl.hxx
@@ -40,6 +40,23 @@ struct DirectoryItem_Impl
     oslFileType getFileType() const;
 };
 
+/**
+   Determine if the passed in path is not contained inside
+   the allowed paths, or if no allowed paths are set it
+   will not forbid any access.
+
+   @param[in] filePath
+   A URL (or path) that we want to check if it is forbidden
+   to access.
+
+   @param[in] nFlags
+   Flags to determine what type of access is requested,
+   osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'.
+
+   This method is Unix specific.
+
+   @see setAllowedPaths in sal/inc/setallowedpaths.hxx
+*/
 bool isForbidden(const OString &filePath, int nFlags);
 
 oslFileError openFile(
diff --git a/sal/qa/osl/file/forbidden.cxx b/sal/qa/osl/file/forbidden.cxx
new file mode 100644
index 000000000000..d474fbbc39db
--- /dev/null
+++ b/sal/qa/osl/file/forbidden.cxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <cppunit/plugin/TestPlugIn.h>
+
+#if (defined UNX)
+
+#include <stdio.h>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <osl/file.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include <setallowedpaths.hxx>
+
+#include "../../../osl/unx/file_impl.hxx"
+
+using namespace osl;
+
+namespace osl::qa {
+
+static bool isForbidden(OUString const & path, sal_uInt32 flags) {
+    OString utf8;
+    auto const ok = path.convertToString(&utf8, RTL_TEXTENCODING_UTF8, 
RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | 
RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
+    CPPUNIT_ASSERT(ok);
+    return ::isForbidden(utf8, flags);
+}
+
+}
+
+namespace osl_Forbidden
+{
+
+    class Forbidden : public CppUnit::TestFixture
+    {
+        OUString maScratchBad;
+        OUString maScratchGood;
+    public:
+        void setUp() override
+        {
+            // create a directory to play in
+            createTestDirectory(aTmpName3);
+            OUString aBadURL = aTmpName3 + "/bad";
+            OUString aGoodURL = aTmpName3 + "/good";
+            createTestDirectory(aBadURL);
+            createTestDirectory(aGoodURL);
+            File::getSystemPathFromFileURL(aBadURL, maScratchBad);
+            File::getSystemPathFromFileURL(aGoodURL, maScratchGood);
+        }
+
+        void tearDown() override
+        {
+            setAllowedPaths(u"");
+            OUString aBadURL = aTmpName3 + "/bad";
+            OUString aGoodURL = aTmpName3 + "/good";
+            deleteTestDirectory(aBadURL);
+            deleteTestDirectory(aGoodURL);
+            deleteTestDirectory(aTmpName3);
+        }
+
+        void forbidden()
+        {
+            setAllowedPaths(maScratchGood);
+
+            // check some corner cases first
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, osl::qa::isForbidden(".", 
osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, osl::qa::isForbidden("", 
osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, osl::qa::isForbidden("a", 
osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, osl::qa::isForbidden("/", 
osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from non-existent should be 
allowed",
+                                         false, 
osl::qa::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Read));
+
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchBad, osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed",
+                                         false, 
osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Write));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("create in good should be forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Create));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchGood, 0x80));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchBad + "/notthere", osl_File_OpenFlag_Write));
+
+            setAllowedPaths(Concat2View("w:" + maScratchGood + ":x:" + 
maScratchBad));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchBad, osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", 
// w implies 'r'
+                                         false, 
osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be allowed",
+                                         false, 
osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Write));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchGood, 0x80));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from bad should be allowed",
+                                         false, 
osl::qa::isForbidden(maScratchBad, 0x80));
+
+            setAllowedPaths(Concat2View(":r:" + maScratchBad));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden",
+                                         true, 
osl::qa::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden 2",
+                                         true, 
osl::qa::isForbidden(maScratchGood + "/notthere/file", 
osl_File_OpenFlag_Write));
+
+            setAllowedPaths(Concat2View(":r:" + maScratchBad + ":w:" + 
maScratchGood + "/notthere"));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
allowed",
+                                         false, 
osl::qa::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
allowed 2",
+                                         false, 
osl::qa::isForbidden(maScratchGood + "/notthere/file", 
osl_File_OpenFlag_Write));
+        }
+
+/*
+        void open()
+        {
+            setAllowedPaths(maScratchGood);
+            File testFile(maScratchBad + "/open");
+            auto nError1 = testFile.open(osl_File_OpenFlag_Read | 
osl_File_OpenFlag_Write);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("disabled path allowed", 
osl::FileBase::E_ACCES, nError1);
+            deleteTestFile(testFile.getURL());
+        }
+
+        void copy()
+        {
+            setAllowedPaths("w:" + maScratchGood);
+            File testGood(maScratchGood + "/good");
+            File testGoodTo(maScratchGood + "/good_to");
+            File testBad(maScratchBad + "/bad");
+
+            auto nError1 = testGood.open(osl_File_OpenFlag_Create);
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1);
+
+            auto nErrorCopy = File::copy(maScratchGood + "/good", 
maScratchGood + "/good_to");
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nErrorCopy);
+
+            auto nErrorCopyBad = File::copy(maScratchGood + "/good_to", 
maScratchBad + "/bad");
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_ACCES, nErrorCopyBad);
+
+            deleteTestFile(maScratchGood + "/good_to");
+            deleteTestFile(maScratchGood + "/good");
+        }
+
+        void nextTests()
+        {
+            // more entry points to test
+#if 0
+            auto nError1 = File::move(aTmpName4, aCanURL1);
+            auto nError2 = File::remove(aTmpName4);
+            auto nError3 = File::setAttributes(aTmpName6, 
osl_File_Attribute_ReadOnly);
+            bool bOk = osl_getSystemTime(pTV_current);
+            CPPUNIT_ASSERT(bOk);
+            auto nError4 = File::setTime(aTmpName6, *pTV_current, 
*pTV_current, *pTV_current);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError2).getStr(), 
osl::FileBase::E_None, nError2);
+#endif
+        }
+*/
+        CPPUNIT_TEST_SUITE(Forbidden);
+        CPPUNIT_TEST(forbidden);
+//        CPPUNIT_TEST(open);
+//        CPPUNIT_TEST(copy);
+//        CPPUNIT_TEST(nextTests);
+        CPPUNIT_TEST_SUITE_END();
+
+    //TODO: The following parts are mainly copied from 
sal/qa/osl/file/osl_File.cxx and
+    // sal/qa/osl/file/osl_File_Const.h (but the latter cannot be included 
directly, as its use of
+    // static C++ objects would cause issues with the use of 
gb_CppunitTest_use_library_objects in
+    // this test's sal/CppunitTest_sal_osl_file_details.mk):
+    private:
+        static OUString getTempDirectoryURL_()
+        {
+            OUString aDir;
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("couldn't get system temp URL",
+                osl::FileBase::E_None, osl::FileBase::getTempDirURL(aDir));
+            // This resolves symlinks in the temp path if any
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None,
+                                 osl::FileBase::getAbsoluteFileURL(aDir, aDir, 
aDir));
+            return aDir;
+        }
+
+        OUString aTempDirectoryURL;
+
+        OUString aTmpName3;
+
+        /** simple version to judge if a file name or directory name is a URL 
or a system path, just to see if it
+            is start with "file:///";.
+        */
+        static bool isURL(const OUString& pathname)
+        {
+            return pathname.startsWith(u"file:///");
+        }
+
+        /** create a temp test directory using OUString name of full qualified 
URL or system path.
+        */
+        static void createTestDirectory(const OUString& dirname)
+        {
+            OUString aPathURL   = dirname.copy(0);
+            osl::FileBase::RC nError;
+
+            if (!isURL(dirname))
+                osl::FileBase::getFileURLFromSystemPath(dirname, aPathURL); // 
convert if not full qualified URL
+            nError = Directory::create(aPathURL);
+            if ((nError != osl::FileBase::E_None) && (nError != 
osl::FileBase::E_EXIST))
+                printf("createTestDirectory failed: %d!
", int(nError));
+        }
+
+        /** delete a temp test directory using OUString name of full qualified 
URL or system path.
+        */
+        static void deleteTestDirectory(const OUString& dirname)
+        {
+            OUString aPathURL = dirname.copy(0);
+            if (!isURL(dirname))
+                osl::FileBase::getFileURLFromSystemPath(dirname, aPathURL); // 
convert if not full qualified URL
+
+            Directory testDir(aPathURL);
+            if (testDir.isOpen())
+                testDir.close();  // close if still open.
+
+            osl::FileBase::RC nError = Directory::remove(aPathURL);
+
+            OString strError = "In deleteTestDirectory function: remove 
Directory " +
+                OUStringToOString(aPathURL, RTL_TEXTENCODING_ASCII_US) + " -> 
result: " + OString::number(nError);
+            CPPUNIT_ASSERT_MESSAGE(strError.getStr(), (osl::FileBase::E_None 
== nError) || (nError == osl::FileBase::E_NOENT));
+        }
+
+    public:
+        Forbidden():
+            aTempDirectoryURL(getTempDirectoryURL_()),
+            aTmpName3( aTempDirectoryURL + "/tmpdir" )
+        {}
+    };
+
+    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Forbidden::Forbidden, 
"osl_Forbidden");
+
+    CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_Forbidden");
+}
+#endif
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sal/qa/osl/file/osl_File.cxx b/sal/qa/osl/file/osl_File.cxx
index d768c151ddaf..159f32ad7410 100644
--- a/sal/qa/osl/file/osl_File.cxx
+++ b/sal/qa/osl/file/osl_File.cxx
@@ -1313,150 +1313,6 @@ namespace osl_FileBase
     CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_osl::FileBase");
 }
 
-#if (defined UNX)
-
-namespace osl_Forbidden
-{
-
-    class Forbidden : public CppUnit::TestFixture
-    {
-        OUString maScratchBad;
-        OUString maScratchGood;
-    public:
-        void setUp() override
-        {
-            // create a directory to play in
-            createTestDirectory(aTmpName3);
-            OUString aBadURL = aTmpName3 + "/bad";
-            OUString aGoodURL = aTmpName3 + "/good";
-            createTestDirectory(aBadURL);
-            createTestDirectory(aGoodURL);
-            File::getSystemPathFromFileURL(aBadURL, maScratchBad);
-            File::getSystemPathFromFileURL(aGoodURL, maScratchGood);
-        }
-
-        void tearDown() override
-        {
-            osl_setAllowedPaths(nullptr);
-            OUString aBadURL = aTmpName3 + "/bad";
-            OUString aGoodURL = aTmpName3 + "/good";
-            deleteTestDirectory(aBadURL);
-            deleteTestDirectory(aGoodURL);
-            deleteTestDirectory(aTmpName3);
-        }
-
-        void forbidden()
-        {
-            File::setAllowedPaths(maScratchGood);
-
-            // check some corner cases first
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
-                                         true, File::isForbidden(".", 
osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
-                                         true, File::isForbidden("", 
osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
-                                         true, File::isForbidden("a", 
osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
-                                         true, File::isForbidden("/", 
osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from non-existent should be 
allowed",
-                                         false, 
File::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Read));
-
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
-                                         true, File::isForbidden(maScratchBad, 
osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed",
-                                         false, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be forbidden",
-                                         true, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Write));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("create in good should be forbidden",
-                                         true, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Create));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden",
-                                         true, 
File::isForbidden(maScratchGood, 0x80));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden",
-                                         true, File::isForbidden(maScratchBad 
+ "/notthere", osl_File_OpenFlag_Write));
-
-            File::setAllowedPaths("w:" + maScratchGood + ":x:" + maScratchBad);
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
-                                         true, File::isForbidden(maScratchBad, 
osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", 
// w implies 'r'
-                                         false, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Read));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be allowed",
-                                         false, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Write));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden",
-                                         true, 
File::isForbidden(maScratchGood, 0x80));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from bad should be allowed",
-                                         false, 
File::isForbidden(maScratchBad, 0x80));
-
-            File::setAllowedPaths(":r:" + maScratchBad);
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden",
-                                         true, File::isForbidden(maScratchGood 
+ "/notthere", osl_File_OpenFlag_Write));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden 2",
-                                         true, File::isForbidden(maScratchGood 
+ "/notthere/file", osl_File_OpenFlag_Write));
-
-            File::setAllowedPaths(":r:" + maScratchBad + ":w:" + maScratchGood 
+ "/notthere");
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
allowed",
-                                         false, 
File::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write));
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
allowed 2",
-                                         false, 
File::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Write));
-        }
-
-/*
-        void open()
-        {
-            File::setAllowedPaths(maScratchGood);
-            File testFile(maScratchBad + "/open");
-            auto nError1 = testFile.open(osl_File_OpenFlag_Read | 
osl_File_OpenFlag_Write);
-            CPPUNIT_ASSERT_EQUAL_MESSAGE("disabled path allowed", 
osl::FileBase::E_ACCES, nError1);
-            deleteTestFile(testFile.getURL());
-        }
-
-        void copy()
-        {
-            File::setAllowedPaths("w:" + maScratchGood);
-            File testGood(maScratchGood + "/good");
-            File testGoodTo(maScratchGood + "/good_to");
-            File testBad(maScratchBad + "/bad");
-
-            auto nError1 = testGood.open(osl_File_OpenFlag_Create);
-            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1);
-
-            auto nErrorCopy = File::copy(maScratchGood + "/good", 
maScratchGood + "/good_to");
-            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nErrorCopy);
-
-            auto nErrorCopyBad = File::copy(maScratchGood + "/good_to", 
maScratchBad + "/bad");
-            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_ACCES, nErrorCopyBad);
-
-            deleteTestFile(maScratchGood + "/good_to");
-            deleteTestFile(maScratchGood + "/good");
-        }
-
-        void nextTests()
-        {
-            // more entry points to test
-#if 0
-            auto nError1 = File::move(aTmpName4, aCanURL1);
-            auto nError2 = File::remove(aTmpName4);
-            auto nError3 = File::setAttributes(aTmpName6, 
osl_File_Attribute_ReadOnly);
-            bool bOk = osl_getSystemTime(pTV_current);
-            CPPUNIT_ASSERT(bOk);
-            auto nError4 = File::setTime(aTmpName6, *pTV_current, 
*pTV_current, *pTV_current);
-            CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError2).getStr(), 
osl::FileBase::E_None, nError2);
-#endif
-        }
-*/
-        CPPUNIT_TEST_SUITE(Forbidden);
-        CPPUNIT_TEST(forbidden);
-//        CPPUNIT_TEST(open);
-//        CPPUNIT_TEST(copy);
-//        CPPUNIT_TEST(nextTests);
-        CPPUNIT_TEST_SUITE_END();
-    };
-
-    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Forbidden::Forbidden, 
"osl_Forbidden");
-
-    CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_Forbidden");
-}
-#endif
-
 namespace osl_FileStatus
 {
     //  testing the method
diff --git a/sal/qa/rtl/alloc/rtl_alloc.cxx b/sal/qa/rtl/alloc/rtl_alloc.cxx
index 0e743cae3c11..f63d3f1275aa 100644
--- a/sal/qa/rtl/alloc/rtl_alloc.cxx
+++ b/sal/qa/rtl/alloc/rtl_alloc.cxx
@@ -157,7 +157,7 @@ public:
         const char sample[] = "Hello World";
         std::vector<OUString> aStrings;
 
-        rtl_alloc_preInit(true);
+        rtl_alloc_preInit(1);
 
         OUString aFoo(o3tl::nonStaticString(u"foo"));
 
@@ -182,7 +182,7 @@ public:
         }
 
         // should static-ize all the strings.
-        rtl_alloc_preInit(false);
+        rtl_alloc_preInit(0);
 
         for (size_t i = 0; i < aStrings.size(); ++i)
             CPPUNIT_ASSERT_MESSAGE( "static after.", 
(aStrings[i].pData->refCount & SAL_STRING_STATIC_FLAG) );
diff --git a/sal/rtl/preinit.cxx b/sal/rtl/preinit.cxx
new file mode 100644
index 000000000000..d1c6c1478d5a
--- /dev/null
+++ b/sal/rtl/preinit.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rtl/alloc.h>
+#include <rtl/textenc.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+
+#include <setallowedpaths.hxx>
+
+#include "strimp.hxx"
+
+void SAL_CALL rtl_alloc_preInit(sal_uInt8 mode) SAL_THROW_EXTERN_C()
+{
+    switch (mode)
+    {
+        case 0:
+            alloc_preInit(false);
+            break;
+        case 1:
+            alloc_preInit(true);
+            break;
+#if defined UNX
+        case 2:
+        {
+            const char* pAllowedPaths = getenv("SAL_ALLOWED_PATHS");
+            if (pAllowedPaths)
+                setAllowedPaths(
+                    OUString(pAllowedPaths, strlen(pAllowedPaths), 
RTL_TEXTENCODING_UTF8));
+            break;
+        }
+#endif
+        default:
+            SAL_WARN("sal.rtl", "Unknown rtl_alloc_preInit mode " << 
unsigned(mode));
+            break;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sal/rtl/strimp.cxx b/sal/rtl/strimp.cxx
index 678bbb69c406..fac73cecf7b4 100644
--- a/sal/rtl/strimp.cxx
+++ b/sal/rtl/strimp.cxx
@@ -65,7 +65,7 @@ static void mark_static(void *addr, sal_Size /* size */)
     str->refCount |= SAL_STRING_STATIC_FLAG;
 }
 
-void SAL_CALL rtl_alloc_preInit (sal_Bool start) noexcept
+void alloc_preInit (bool start) noexcept
 {
     if (start)
     {
diff --git a/sal/rtl/strimp.hxx b/sal/rtl/strimp.hxx
index 5fd759313ed3..6691296aa3b8 100644
--- a/sal/rtl/strimp.hxx
+++ b/sal/rtl/strimp.hxx
@@ -60,6 +60,8 @@ typedef void  (*rtl_freeStringFn)(void *);
 extern rtl_allocateStringFn rtl_allocateString;
 extern rtl_freeStringFn rtl_freeString;
 
+void alloc_preInit(bool start) noexcept;
+
 // string lifetime instrumentation / diagnostics
 #if USE_SDT_PROBES
 #  define PROBE_SNAME(n,b) n ## _ ## b
diff --git a/sal/util/sal.map b/sal/util/sal.map
index 586a41ee997d..c5c3e4d55641 100644
--- a/sal/util/sal.map
+++ b/sal/util/sal.map
@@ -761,12 +761,6 @@ PRIVATE_1.8 { # LibreOffice 7.3
         rtl_uString_newReplaceStrAtUtf16L;
 } PRIVATE_1.7;
 
-PRIVATE_1.9 { # LibreOffice 7.7
-    global:
-        osl_setAllowedPaths;
-        osl_isForbiddenPath;
-} PRIVATE_1.8;
-
 PRIVATE_textenc.1 { # LibreOffice 3.6
     global:
         _ZN3sal6detail7textenc20convertCharToUnicode*;
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index 554233aad13e..1111f5117fc9 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -7530,6 +7530,7 @@ sal/qa/OStringBuffer/rtl_OStringBuffer.cxx
 sal/qa/OStringBuffer/rtl_String_Const.h
 sal/qa/inc/valueequal.hxx
 sal/qa/osl/condition/osl_Condition.cxx
+sal/qa/osl/file/forbidden.cxx
 sal/qa/osl/file/osl_File.cxx
 sal/qa/osl/file/osl_File_Const.h
 sal/qa/osl/file/osl_old_test_file.cxx

Reply via email to