1 /*
2    mkvmerge -- utility for splicing together matroska files
3    from component media subtypes
4 
5    Distributed under the GPL v2
6    see the file COPYING for details
7    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8 
9    Written by Moritz Bunkus <moritz@bunkus.org>.
10 */
11 
12 #include "common/common_pch.h"
13 
14 #include "common/path.h"
15 #include "common/strings/utf8.h"
16 
17 namespace mtx::fs {
18 
19 std::filesystem::path
to_path(std::string const & name)20 to_path(std::string const &name) {
21   return std::filesystem::path{to_wide(name)};
22 }
23 
24 std::filesystem::path
to_path(std::wstring const & name)25 to_path(std::wstring const &name) {
26   return std::filesystem::path{name};
27 }
28 
29 bool
is_absolute(std::filesystem::path const & p)30 is_absolute(std::filesystem::path const &p) {
31   auto p_s = p.u8string();
32 
33   if (   (p_s.substr(0, 2) == "//"s)
34       || (p_s.substr(0, 2) == "\\\\"s))
35     return true;
36 
37   return p.is_absolute();
38 }
39 
40 void
create_directories(std::filesystem::path const & path,std::error_code & error_code)41 create_directories(std::filesystem::path const &path,
42                    std::error_code &error_code) {
43   auto normalized_path = path.u8string();
44 
45   for (auto &c : normalized_path)
46     if (c == '/')
47       c = '\\';
48 
49   auto directory = mtx::fs::to_path(normalized_path);
50   error_code     = {};
51 
52   if (directory.empty() || std::filesystem::is_directory(directory))
53     return;
54 
55   auto is_unc = normalized_path.substr(0, 2) == "\\\\"s;
56 
57   std::vector<std::filesystem::path> to_check;
58 
59   // path                   | is_unc | parent_path        | parent_path.parent_path | to_check
60   // -----------------------+--------+--------------------+-------------------------+----------------------
61   // E:\moo\cow             | false  | E:\moo             | E:\                     | E:\moo\cow
62   // E:\moo                 | false  | E:\                | E:\                     | E:\moo
63   // E:\                    | false  | E:\                | E:\                     |
64   // \\server\share\moo\cow | true   | \\server\share\moo | \\server\share          | \\sever\share\moo\cow
65   // \\server\share\moo     | true   | \\server\share     | \\server                | \\sever\share\moo
66   // \\server\share         | true   | \\server           | \                       |
67   // \\server               | true   | \                  | \                       |
68 
69   while (   !directory.empty()
70          && (directory.parent_path() != directory)
71          && (   !is_unc
72              || (directory.parent_path().parent_path().u8string() != "\\"s))) {
73     to_check.emplace_back(directory);
74     directory = directory.parent_path();
75   }
76 
77   for (auto itr = to_check.rbegin(), end = to_check.rend(); itr != end; ++itr) {
78     if (std::filesystem::is_directory(*itr))
79       continue;
80 
81     std::filesystem::create_directory(*itr, error_code);
82 
83     if (error_code)
84       return;
85   }
86 }
87 
88 } // namespace mtx::fs
89