11 #include <sys/types.h> 22 #include <initializer_list> 28 #include <string_view> 29 #include <system_error> 30 #include <unordered_map> 34 #include "fcitx-utils/standardpaths_p.h" 42 #include "standardpaths_p.h" 48 const std::filesystem::path StandardPathsPrivate::constEmptyPath;
49 const std::vector<std::filesystem::path> StandardPathsPrivate::constEmptyPaths =
50 {std::filesystem::path()};
52 std::mutex StandardPathsPrivate::globalMutex_;
53 std::unique_ptr<StandardPaths> StandardPathsPrivate::global_;
57 constexpr std::string_view envListSeparator = isWindows() ?
";" :
":";
59 std::vector<std::filesystem::path> pathFromEnvironment() {
61 if (
auto pEnv = getEnvironment(
"PATH")) {
62 sEnv = std::move(*pEnv);
64 #if defined(_PATH_DEFPATH) 66 #elif defined(_CS_PATH) 67 size_t n = confstr(_CS_PATH,
nullptr, 0);
69 std::vector<char> data;
71 confstr(_CS_PATH, data.data(), data.size());
78 std::vector<std::filesystem::path> result;
79 result.reserve(paths.size());
80 for (
auto &path : paths) {
81 result.push_back(path);
89 const std::string &packageName,
90 const std::unordered_map<std::string, std::vector<std::filesystem::path>>
93 : d_ptr(
std::make_unique<StandardPathsPrivate>(packageName, builtInPath,
96 StandardPaths::~StandardPaths() =
default;
99 std::lock_guard<std::mutex> lock(StandardPathsPrivate::globalMutex_);
100 if (!StandardPathsPrivate::global_) {
101 bool skipFcitx = checkBoolEnvVar(
"SKIP_FCITX_PATH");
102 bool skipFcitxSystem = checkBoolEnvVar(
"SKIP_FCITX_SYSTEM_PATH");
103 bool skipUser = checkBoolEnvVar(
"SKIP_FCITX_USER_PATH");
106 options |= StandardPathsOption::SkipUserPath;
108 if (skipFcitxSystem) {
109 options |= StandardPathsOption::SkipSystemPath;
112 options |= StandardPathsOption::SkipBuiltInPath;
114 StandardPathsPrivate::global_ = std::make_unique<StandardPaths>(
116 std::unordered_map<std::string,
117 std::vector<std::filesystem::path>>{},
121 return *StandardPathsPrivate::global_;
124 std::filesystem::path
126 const std::filesystem::path &subPath) {
127 return StandardPathsPrivate::fcitxPath(path, subPath);
130 std::filesystem::path
131 StandardPaths::findExecutable(
const std::filesystem::path &name) {
132 if (name.is_absolute()) {
133 return fs::isexe(name.string()) ? name : std::filesystem::path();
136 for (
const auto &path : pathFromEnvironment()) {
137 auto fullPath = path / name;
145 bool StandardPaths::hasExecutable(
const std::filesystem::path &name) {
146 return !findExecutable(name).empty();
149 const std::filesystem::path &
153 return StandardPathsPrivate::constEmptyPath;
155 auto dirs = d->directories(type, StandardPathsMode::User);
156 return dirs.empty() ? StandardPathsPrivate::constEmptyPath : dirs[0];
159 std::span<const std::filesystem::path>
163 return d->directories(type, modes);
167 const std::filesystem::path &path,
170 std::filesystem::path retPath;
171 d->scanDirectories(type, path, modes,
172 [&retPath](
const std::filesystem::path &fullPath) {
174 if (!std::filesystem::exists(fullPath, ec)) {
183 std::vector<std::filesystem::path>
185 const std::filesystem::path &path,
188 std::vector<std::filesystem::path> retPaths;
189 d->scanDirectories(type, path, modes,
190 [&retPaths](std::filesystem::path fullPath) {
192 if (!std::filesystem::exists(fullPath, ec)) {
195 retPaths.push_back(std::move(fullPath));
201 std::map<std::filesystem::path, std::filesystem::path>
203 const StandardPathsFilterCallback &callback,
206 std::map<std::filesystem::path, std::filesystem::path> retPath;
209 [&retPath, &callback](
const std::filesystem::path &fullPath) {
211 for (
auto directoryIterator =
212 std::filesystem::directory_iterator(fullPath, ec);
213 directoryIterator != std::filesystem::directory_iterator();
214 directoryIterator.increment(ec)) {
218 if (retPath.contains(directoryIterator->path().filename())) {
221 if (callback(directoryIterator->path())) {
222 retPath[directoryIterator->path().filename()] =
223 directoryIterator->path();
232 const std::filesystem::path &path,
234 std::filesystem::path *outPath)
const {
237 d->scanDirectories(type, path, modes,
238 [&retFD, outPath](std::filesystem::path fullPath) {
244 *outPath = std::move(fullPath);
252 std::optional<int> flags,
253 std::optional<mode_t> mode) {
254 int f = flags.value_or(O_RDONLY);
256 auto openFunc = [](
auto path,
int flag,
auto... extra) {
259 return ::_wopen(path, flag, extra...);
261 return ::open(path, flag, extra...);
264 if (mode.has_value()) {
265 return UnixFD::own(openFunc(path.c_str(), f, mode.value()));
272 const std::filesystem::path &path,
274 std::vector<std::filesystem::path> *outPaths)
const {
276 std::vector<UnixFD> retFDs;
280 d->scanDirectories(type, path, modes,
281 [&retFDs, outPaths](std::filesystem::path fullPath) {
286 retFDs.push_back(std::move(fd));
288 outPaths->push_back(std::move(fullPath));
296 const std::filesystem::path &pathOrig,
297 const std::function<
bool(
int)> &callback)
const {
299 auto [file, path, fullPathOrig] = d->openUserTemp(type, pathOrig);
300 if (!file.isValid()) {
304 if (callback(file.fd())) {
307 ::_wchmod(path.c_str(), 0666 & ~(d->umask()));
311 fchmod(file.fd(), 0666 & ~(d->umask()));
315 std::filesystem::rename(path, fullPathOrig);
318 }
catch (
const std::exception &e) {
319 FCITX_ERROR() <<
"Failed to write file: " << fullPathOrig << e.what();
322 _wunlink(path.c_str());
324 unlink(path.c_str());
330 const std::filesystem::path &path,
334 int64_t timestamp = 0;
335 d->scanDirectories(type, path, modes,
336 [×tamp](
const std::filesystem::path &fullPath) {
338 timestamp = std::max(timestamp, time);
349 return d->options() & StandardPathsOption::SkipBuiltInPath;
354 return d->options() & StandardPathsOption::SkipUserPath;
359 return d->options() & StandardPathsOption::SkipSystemPath;
Class wrap around the unix fd.
std::vector< UnixFD > openAll(StandardPathsType type, const std::filesystem::path &path, StandardPathsModes modes=StandardPathsMode::Default, std::vector< std::filesystem::path > *outPath=nullptr) const
Open the all matched and file for read.
static const StandardPaths & global()
Return the global instance of StandardPath.
bool isValid() const noexcept
Check if fd is not empty.
std::vector< std::filesystem::path > locateAll(StandardPathsType type, const std::filesystem::path &path, StandardPathsModes modes=StandardPathsMode::Default) const
Check if path exists in all directories.
bool skipSystemPath() const
Whether this StandardPath is configured to Skip system path.
StandardPathsType
Enum for location type.
Simple file system related API for checking file status.
bool isexe(const std::string &path)
check whether path is an executable regular file.
bool skipBuiltInPath() const
Whether this StandardPath is configured to Skip built-in path.
bool safeSave(StandardPathsType type, const std::filesystem::path &pathOrig, const std::function< bool(int)> &callback) const
Save the file safely with write and rename to make sure the operation is atomic.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
std::span< const std::filesystem::path > directories(StandardPathsType type, StandardPathsModes modes=StandardPathsMode::Default) const
Get all directories in the order of priority.
StandardPathsOptions options() const
Get the options for the StandardPaths.
Utility class to handle unix file decriptor.
void syncUmask() const
Sync system umask to internal state.
bool skipUserPath() const
Whether this StandardPath is configured to Skip user path.
New Utility classes to handle application specific path.
UnixFD open(StandardPathsType type, const std::filesystem::path &path, StandardPathsModes modes=StandardPathsMode::Default, std::filesystem::path *outPath=nullptr) const
Open the first matched and succeeded file for read.
static UnixFD own(int fd)
Create a UnixFD by owning the fd.
static UnixFD openPath(const std::filesystem::path &path, std::optional< int > flags=std::nullopt, std::optional< mode_t > mode=std::nullopt)
Open the path.
StandardPaths(const std::string &packageName, const std::unordered_map< std::string, std::vector< std::filesystem::path >> &builtInPath, StandardPathsOptions options)
Allow to construct a StandardPath with customized internal value.
Class provides bit flag support for Enum.
int64_t modifiedTime(const std::filesystem::path &path)
Return modified time in seconds of given path.
const std::filesystem::path & userDirectory(StandardPathsType type) const
Get user writable directory for given type.
static std::filesystem::path fcitxPath(const char *path, const std::filesystem::path &subPath={})
Return fcitx specific path defined at compile time.
std::filesystem::path locate(StandardPathsType type, const std::filesystem::path &path, StandardPathsModes modes=StandardPathsMode::Default) const
Check if a file exists.