Skip to content

Commit f2b09fc

Browse files
committed
Make path::replace_extension version-dependent.
We have changed v4 path::extension() to not return the filename if it starts with a dot, but we have not made path::replace_extension version-dependent, which made v3 behave like v4. Fixing this, and optimizing v4 path::replace_extension in the process.
1 parent 733eacf commit f2b09fc

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

doc/release_history.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
<h2>1.79.0</h2>
4343
<ul>
44+
<li><b>v3:</b> <code>path::replace_extension</code> now works in terms of <b>v3</b> definition of <code>path::extension</code> rather than <b>v4</b>.</li>
4445
<li>Fixed compilation of path appending and concatenation operators with arguments of types convertible to <code>path</code> or compatible string type. (<a href="https://github.com/boostorg/filesystem/issues/223">#223</a>)</li>
4546
<li>On POSIX systems that support <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html"><code>fdopendir</code></a> and <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html"><code>O_NOFOLLOW</code></a> and on Windows, <code>remove_all</code> is now protected against <a href="https://www.cve.org/CVERecord?id=CVE-2022-21658">CVE-2022-21658</a>. The vulnerability is a race condition that allows a third party process to replace a directory that is being concurrently processed by <code>remove_all</code> with a directory symlink and cause <code>remove_all</code> to follow the symlink and remove files in the linked directory instead of removing the symlink itself. (<a href="https://github.com/boostorg/filesystem/issues/224">#224</a>)</li>
4647
<li>On Windows, <code>directory_iterator</code> internal implementation has been reworked to better utilize modern Windows APIs, which may improve performance while handling symlinks.</li>

include/boost/filesystem/path.hpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,11 @@ class path :
701701
#endif
702702
BOOST_FILESYSTEM_DECL path& remove_filename();
703703
BOOST_FILESYSTEM_DECL path& remove_trailing_separator();
704-
BOOST_FILESYSTEM_DECL path& replace_extension(path const& new_extension = path());
704+
BOOST_FORCEINLINE path& replace_extension(path const& new_extension = path())
705+
{
706+
BOOST_FILESYSTEM_VERSIONED_SYM(replace_extension)(new_extension);
707+
return *this;
708+
}
705709
void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); }
706710

707711
// ----- observers -----
@@ -940,7 +944,16 @@ class path :
940944
BOOST_FILESYSTEM_DECL path stem_v3() const;
941945
BOOST_FILESYSTEM_DECL path stem_v4() const;
942946
BOOST_FILESYSTEM_DECL path extension_v3() const;
943-
BOOST_FILESYSTEM_DECL path extension_v4() const;
947+
path extension_v4() const
948+
{
949+
string_type::size_type extension_size = find_extension_v4_size();
950+
string_type::size_type pos = m_pathname.size() - extension_size;
951+
const value_type* p = m_pathname.c_str() + pos;
952+
return path(p, p + extension_size);
953+
}
954+
955+
BOOST_FILESYSTEM_DECL void replace_extension_v3(path const& new_extension);
956+
BOOST_FILESYSTEM_DECL void replace_extension_v4(path const& new_extension);
944957

945958
BOOST_FILESYSTEM_DECL path lexically_normal_v3() const;
946959
BOOST_FILESYSTEM_DECL path lexically_normal_v4() const;
@@ -964,6 +977,7 @@ class path :
964977
BOOST_FILESYSTEM_DECL path_detail::substring find_relative_path() const;
965978
BOOST_FILESYSTEM_DECL string_type::size_type find_parent_path_size() const;
966979
BOOST_FILESYSTEM_DECL string_type::size_type find_filename_v4_size() const;
980+
BOOST_FILESYSTEM_DECL string_type::size_type find_extension_v4_size() const;
967981

968982
private:
969983
/*

src/path.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,11 @@ BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator()
386386
return *this;
387387
}
388388

389-
BOOST_FILESYSTEM_DECL path& path::replace_extension(path const& new_extension)
389+
BOOST_FILESYSTEM_DECL void path::replace_extension_v3(path const& new_extension)
390390
{
391391
// erase existing extension, including the dot, if any
392-
m_pathname.erase(m_pathname.size() - extension().m_pathname.size());
392+
size_type ext_pos = m_pathname.size() - extension_v3().m_pathname.size();
393+
m_pathname.erase(m_pathname.begin() + ext_pos, m_pathname.end());
393394

394395
if (!new_extension.empty())
395396
{
@@ -398,8 +399,21 @@ BOOST_FILESYSTEM_DECL path& path::replace_extension(path const& new_extension)
398399
m_pathname.push_back(dot);
399400
m_pathname.append(new_extension.m_pathname);
400401
}
402+
}
401403

402-
return *this;
404+
BOOST_FILESYSTEM_DECL void path::replace_extension_v4(path const& new_extension)
405+
{
406+
// erase existing extension, including the dot, if any
407+
size_type ext_pos = m_pathname.size() - find_extension_v4_size();
408+
m_pathname.erase(m_pathname.begin() + ext_pos, m_pathname.end());
409+
410+
if (!new_extension.empty())
411+
{
412+
// append new_extension, adding the dot if necessary
413+
if (new_extension.m_pathname[0] != dot)
414+
m_pathname.push_back(dot);
415+
m_pathname.append(new_extension.m_pathname);
416+
}
403417
}
404418

405419
// decomposition -------------------------------------------------------------------//
@@ -565,9 +579,8 @@ BOOST_FILESYSTEM_DECL path path::extension_v3() const
565579
return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos);
566580
}
567581

568-
BOOST_FILESYSTEM_DECL path path::extension_v4() const
582+
BOOST_FILESYSTEM_DECL string_type::size_type path::find_extension_v4_size() const
569583
{
570-
path ext;
571584
const size_type size = m_pathname.size();
572585
size_type root_name_size = 0;
573586
find_root_directory_start(m_pathname.c_str(), size, root_name_size);
@@ -590,10 +603,10 @@ BOOST_FILESYSTEM_DECL path path::extension_v4() const
590603
}
591604

592605
if (ext_pos > filename_pos)
593-
ext.assign(m_pathname.c_str() + ext_pos, m_pathname.c_str() + size);
606+
return size - ext_pos;
594607
}
595608

596-
return ext;
609+
return 0u;
597610
}
598611

599612
// lexical operations --------------------------------------------------------------//

0 commit comments

Comments
 (0)