Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
outputdirectory.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "location.h"
7
8#include <QtCore/qfileinfo.h>
9
10#include <utility>
11
12QT_BEGIN_NAMESPACE
13
14using namespace Qt::StringLiterals;
15
16/*!
17 \class OutputDirectory
18 \internal
19 \brief Represents an output directory that has been verified to exist.
20
21 OutputDirectory is a simple value type that wraps a QString representing
22 a filesystem path to a directory. Instances are created via
23 OutputDirectory::ensure() and OutputDirectory::ensureSubdir() after
24 ensuring the directory exists.
25
26 This class provides a type-safe way to pass around directory paths that
27 are known to be valid. This reduces the need for repeated existence checks.
28
29 \section1 Guarantees
30
31 Instances created via ensure() or ensureSubdir() provide the following
32 guarantees:
33
34 \list
35 \li path() refers to an existing directory.
36 \li Directory creation failures terminate QDoc via Location::fatal().
37 \li All paths are normalized using QDir::cleanPath().
38 \li ensureSubdir() accepts multi-segment relative paths
39 (such as "images/used-in-examples").
40 \li ensureSubdir() prevents path traversal attacks using ".."
41 components.
42 \endlist
43
44 \note The public constructor doesn't perform existence checks and is
45 intended primarily for internal use by the factory methods. Avoid
46 direct construction in favor of ensure() or ensureSubdir().
47
48 \note These methods are designed for single-threaded use during QDoc's
49 generation phase and are not synchronized.
50
51 \sa OutputDirectory::ensure(), OutputDirectory::ensureSubdir()
52*/
53
54/*!
55 Constructs an OutputDirectory for the given \a path.
56
57 The \a path is normalized using QDir::cleanPath() and moved into the object.
58 This constructor is intentionally public to allow the static factory methods
59 to create instances, but users should not construct OutputDirectory
60 instances directly—they should use OutputDirectory::ensure() or
61 ensureSubdir() instead.
62*/
63OutputDirectory::OutputDirectory(QString path) noexcept
65{
66}
67
68/*!
69 Returns the absolute file path for a file named \a fileName within
70 this output directory.
71
72 For example, if the output directory is "/tmp/doc" and \e fileName is
73 "index.html", this returns "/tmp/doc/index.html".
74*/
75QString OutputDirectory::absoluteFilePath(QStringView fileName) const
76{
77 return QDir(m_path).absoluteFilePath(fileName.toString());
78}
79
80/*!
81 Ensures that an output directory exists at \a path and creates it if
82 necessary.
83
84 If \a path exists but is not a directory, or if the directory cannot be
85 created, reports a fatal error using \a location and terminates QDoc
86 execution.
87
88 Returns an OutputDirectory representing the created or existing directory.
89
90 \sa ensureSubdir()
91*/
92OutputDirectory OutputDirectory::ensure(QStringView path, const Location &location)
93{
94 const QString cleanPath = QDir::cleanPath(path.toString());
95
96 const QFileInfo fi(cleanPath);
97 if (fi.exists() && !fi.isDir())
98 location.fatal(u"'%1' exists and is not a directory"_s.arg(cleanPath));
99
100 QDir dir(cleanPath);
101 if (!dir.exists() && !dir.mkpath("."_L1))
102 location.fatal(u"Cannot create output directory '%1'"_s.arg(cleanPath));
103
104 return OutputDirectory(std::move(cleanPath));
105}
106
107/*!
108 Ensures that a subdirectory named \a subdirName exists within this
109 output directory, creating it if necessary.
110
111 The \a subdirName must be a relative path. Absolute paths and paths that
112 traverse outside the parent directory using ".." are rejected with a fatal
113 error to prevent accidental writes outside the output tree.
114
115 If the directory cannot be created, reports a fatal error using \a location
116 and terminates QDoc execution.
117
118 Returns an OutputDirectory representing the created or existing subdirectory.
119
120 \sa ensure()
121*/
123 const Location &location) const
124{
125 const QString subdirNameStr = subdirName.toString();
126
127 if (QDir::isAbsolutePath(subdirNameStr))
128 location.fatal(u"Subdirectory name must be relative, not absolute: '%1'"_s.arg(subdirNameStr));
129
130 const QString subdirPath = QDir(m_path).filePath(subdirNameStr);
131 const QString cleanSubdirPath = QDir::cleanPath(subdirPath);
132
133 const QString cleanParentPath = QDir::cleanPath(m_path);
134 const QDir parentDir(cleanParentPath);
135 const QString relativePath = parentDir.relativeFilePath(cleanSubdirPath);
136
137 if (relativePath.startsWith(".."_L1 + u'/') || relativePath == ".."_L1) {
138 location.fatal(u"Refusing to create subdirectory outside parent: '%1' (parent: '%2')"_s
139 .arg(cleanSubdirPath, cleanParentPath));
140 }
141
142 return ensure(cleanSubdirPath, location);
143}
144
145QT_END_NAMESPACE
The Location class provides a way to mark a location in a file.
Definition location.h:20
Represents an output directory that has been verified to exist.
OutputDirectory ensureSubdir(QStringView subdirName, const Location &location) const
Ensures that a subdirectory named subdirName exists within this output directory, creating it if nece...
QString absoluteFilePath(QStringView fileName) const
Returns the absolute file path for a file named fileName within this output directory.
OutputDirectory(QString path) noexcept
Constructs an OutputDirectory for the given path.