From 057ce40200753d0c336aaa2cbe69de5007f0c68e Mon Sep 17 00:00:00 2001 From: silverweed Date: Wed, 26 Nov 2025 09:48:08 +0100 Subject: [PATCH 1/2] [io] TDirectoryFile: propagate returnExistingDirectory to sub-calls --- io/io/src/TDirectoryFile.cxx | 2 +- io/io/test/TFileTests.cxx | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/io/io/src/TDirectoryFile.cxx b/io/io/src/TDirectoryFile.cxx index d4f33a9c12a6e..3269367180cc4 100644 --- a/io/io/src/TDirectoryFile.cxx +++ b/io/io/src/TDirectoryFile.cxx @@ -1287,7 +1287,7 @@ TDirectory *TDirectoryFile::mkdir(const char *name, const char *title, Bool_t re tmpdir = (TDirectoryFile*)mkdir(workname.Data(),title); if (!tmpdir) return nullptr; } - return tmpdir->mkdir(slash + 1); + return tmpdir->mkdir(slash + 1, "", returnExistingDirectory); } TDirectory::TContext ctxt(this); diff --git a/io/io/test/TFileTests.cxx b/io/io/test/TFileTests.cxx index 16c58e8fd46a6..a9397a1c65b94 100644 --- a/io/io/test/TFileTests.cxx +++ b/io/io/test/TFileTests.cxx @@ -5,6 +5,8 @@ #include "gtest/gtest.h" +#include + #include "TFile.h" #include "TMemFile.h" #include "TDirectory.h" @@ -280,6 +282,21 @@ TEST(TDirectoryFile, SeekParent) EXPECT_EQ(dir11->GetSeekParent(), 239); } +TEST(TDirectoryFile, RecursiveMkdir) +{ + TMemFile f("mkdirtest.root", "RECREATE"); + auto dir1 = f.mkdir("a/b/c"); + EXPECT_NE(dir1, nullptr); + { + ROOT::TestSupport::CheckDiagsRAII diags; + diags.requiredDiag(kError, "TDirectoryFile::mkdir","An object with name c exists already"); + auto dir2 = f.mkdir("a/b/c", "", /* returnExisting = */ false); + EXPECT_EQ(dir2, nullptr); + } + auto dir3 = f.mkdir("a/b/c", "", /* returnExisting = */ true); + EXPECT_EQ(dir3, dir1); +} + // https://its.cern.ch/jira/browse/ROOT-10581 TEST(TFile, PersistTObjectStdArray) { From bcfe688c5ed5f5ab8b0978eef4f11e731376203b Mon Sep 17 00:00:00 2001 From: silverweed Date: Wed, 26 Nov 2025 10:06:17 +0100 Subject: [PATCH 2/2] [io] in TDirectoryFile::mkdir, only apply `title` to the innermost dir. --- io/io/src/TDirectoryFile.cxx | 9 ++++++--- io/io/test/TFileTests.cxx | 11 +++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/io/io/src/TDirectoryFile.cxx b/io/io/src/TDirectoryFile.cxx index 3269367180cc4..34ae71942a592 100644 --- a/io/io/src/TDirectoryFile.cxx +++ b/io/io/src/TDirectoryFile.cxx @@ -1258,7 +1258,9 @@ TFile *TDirectoryFile::OpenFile(const char *name, Option_t *option,const char *f /// Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...". /// /// @param name the name or hierarchy of the subdirectory ("a" or "a/b/c") -/// @param title the title +/// @param title the title of the directory. For hierarchies, this is only applied +/// to the innermost directory (so if `name == "a/b/c"` and `title == "my dir"`, +/// only `c` will have the title `"my dir"`). /// @param returnExistingDirectory if key-name is already existing, the returned /// value points to preexisting sub-directory if true and to `nullptr` if false. /// @return a pointer to the created sub-directory, not to the top sub-directory @@ -1284,10 +1286,11 @@ TDirectory *TDirectoryFile::mkdir(const char *name, const char *title, Bool_t re TDirectoryFile *tmpdir = nullptr; GetObject(workname.Data(), tmpdir); if (!tmpdir) { - tmpdir = (TDirectoryFile*)mkdir(workname.Data(),title); + // We give all intermediate directories a default title, as `title` is only given to the innermost dir. + tmpdir = (TDirectoryFile *)mkdir(workname.Data(), workname.Data()); if (!tmpdir) return nullptr; } - return tmpdir->mkdir(slash + 1, "", returnExistingDirectory); + return tmpdir->mkdir(slash + 1, title, returnExistingDirectory); } TDirectory::TContext ctxt(this); diff --git a/io/io/test/TFileTests.cxx b/io/io/test/TFileTests.cxx index a9397a1c65b94..e33ddfc59ec66 100644 --- a/io/io/test/TFileTests.cxx +++ b/io/io/test/TFileTests.cxx @@ -285,7 +285,7 @@ TEST(TDirectoryFile, SeekParent) TEST(TDirectoryFile, RecursiveMkdir) { TMemFile f("mkdirtest.root", "RECREATE"); - auto dir1 = f.mkdir("a/b/c"); + auto dir1 = f.mkdir("a/b/c", "my dir"); EXPECT_NE(dir1, nullptr); { ROOT::TestSupport::CheckDiagsRAII diags; @@ -293,8 +293,15 @@ TEST(TDirectoryFile, RecursiveMkdir) auto dir2 = f.mkdir("a/b/c", "", /* returnExisting = */ false); EXPECT_EQ(dir2, nullptr); } - auto dir3 = f.mkdir("a/b/c", "", /* returnExisting = */ true); + auto dir3 = f.mkdir("a/b/c", "foobar", /* returnExisting = */ true); EXPECT_EQ(dir3, dir1); + EXPECT_STREQ(dir3->GetTitle(), "my dir"); + auto dirB = dir3->GetMotherDir(); + ASSERT_NE(dirB, nullptr); + EXPECT_STREQ(dirB->GetTitle(), "b"); + auto dirA = dirB->GetMotherDir(); + ASSERT_NE(dirA, nullptr); + EXPECT_STREQ(dirA->GetTitle(), "a"); } // https://its.cern.ch/jira/browse/ROOT-10581