Kea 2.7.1
filesystem.cc
Go to the documentation of this file.
1// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <util/filesystem.h>
11#include <util/str.h>
12
13#include <algorithm>
14#include <cctype>
15#include <cerrno>
16#include <cstring>
17#include <fstream>
18#include <iostream>
19#include <string>
20
21#include <fcntl.h>
22
23using namespace isc::util::str;
24using namespace std;
25
26namespace isc {
27namespace util {
28namespace file {
29
30string
31getContent(string const& file_name) {
32 if (!exists(file_name)) {
33 isc_throw(BadValue, "Expected a file at path '" << file_name << "'");
34 }
35 if (!isFile(file_name)) {
36 isc_throw(BadValue, "Expected '" << file_name << "' to be a regular file");
37 }
38 ifstream file(file_name, ios::in);
39 if (!file.is_open()) {
40 isc_throw(BadValue, "Cannot open '" << file_name);
41 }
42 string content;
43 file >> content;
44 return (content);
45}
46
47bool
48exists(string const& path) {
49 struct stat statbuf;
50 return (::stat(path.c_str(), &statbuf) == 0);
51}
52
53bool
54isDir(string const& path) {
55 struct stat statbuf;
56 if (::stat(path.c_str(), &statbuf) < 0) {
57 return (false);
58 }
59 return ((statbuf.st_mode & S_IFMT) == S_IFDIR);
60}
61
62bool
63isFile(string const& path) {
64 struct stat statbuf;
65 if (::stat(path.c_str(), &statbuf) < 0) {
66 return (false);
67 }
68 return ((statbuf.st_mode & S_IFMT) == S_IFREG);
69}
70
71Umask::Umask(mode_t mask) : orig_umask_(umask(S_IWGRP | S_IWOTH)) {
72 umask(orig_umask_ | mask);
73}
74
76 umask(orig_umask_);
77}
78
79Path::Path(string const& full_name) {
80 if (!full_name.empty()) {
81 bool dir_present = false;
82 // Find the directory.
83 size_t last_slash = full_name.find_last_of('/');
84 if (last_slash != string::npos) {
85 // Found the last slash, so extract directory component and
86 // set where the scan for the last_dot should terminate.
87 parent_path_ = full_name.substr(0, last_slash + 1);
88 if (last_slash == full_name.size()) {
89 // The entire string was a directory, so exit not and don't
90 // do any more searching.
91 return;
92 }
93
94 // Found a directory so note the fact.
95 dir_present = true;
96 }
97
98 // Now search backwards for the last ".".
99 size_t last_dot = full_name.find_last_of('.');
100 if ((last_dot == string::npos) || (dir_present && (last_dot < last_slash))) {
101 // Last "." either not found or it occurs to the left of the last
102 // slash if a directory was present (so it is part of a directory
103 // name). In this case, the remainder of the string after the slash
104 // is the name part.
105 stem_ = full_name.substr(last_slash + 1);
106 return;
107 }
108
109 // Did find a valid dot, so it and everything to the right is the
110 // extension...
111 extension_ = full_name.substr(last_dot);
112
113 // ... and the name of the file is everything in between.
114 if ((last_dot - last_slash) > 1) {
115 stem_ = full_name.substr(last_slash + 1, last_dot - last_slash - 1);
116 }
117 }
118}
119
120string
121Path::str() const {
122 return (parent_path_ + stem_ + extension_);
123}
124
125string
127 return (parent_path_);
128}
129
130string
131Path::stem() const {
132 return (stem_);
133}
134
135string
137 return (extension_);
138}
139
140string
142 return (stem_ + extension_);
143}
144
145Path&
146Path::replaceExtension(string const& replacement) {
147 string const trimmed_replacement(trim(replacement));
148 if (trimmed_replacement.empty()) {
149 extension_ = string();
150 } else {
151 size_t const last_dot(trimmed_replacement.find_last_of('.'));
152 if (last_dot == string::npos) {
153 extension_ = "." + trimmed_replacement;
154 } else {
155 extension_ = trimmed_replacement.substr(last_dot);
156 }
157 }
158 return (*this);
159}
160
161Path&
162Path::replaceParentPath(string const& replacement) {
163 string const trimmed_replacement(trim(replacement));
164 if (trimmed_replacement.empty()) {
165 parent_path_ = string();
166 } else if (trimmed_replacement.at(trimmed_replacement.size() - 1) == '/') {
167 parent_path_ = trimmed_replacement;
168 } else {
169 parent_path_ = trimmed_replacement + '/';
170 }
171 return (*this);
172}
173
174} // namespace file
175} // namespace util
176} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
string getContent(string const &file_name)
Get the content of a regular file.
Definition filesystem.cc:31
bool isFile(string const &path)
Check if there is a file at the given path.
Definition filesystem.cc:63
bool exists(string const &path)
Check if there is a file or directory at the given path.
Definition filesystem.cc:48
bool isDir(string const &path)
Check if there is a directory at the given path.
Definition filesystem.cc:54
string trim(const string &input)
Trim leading and trailing spaces.
Definition str.cc:32
Defines the logger used by the top-level component of kea-lfc.
Paths on a filesystem.
Definition filesystem.h:70
Path(std::string const &path)
Constructor.
Definition filesystem.cc:79
Path & replaceParentPath(std::string const &replacement=std::string())
Trims {replacement} and replaces this instance's parent path with it.
std::string extension() const
Get the extension of the file.
Path & replaceExtension(std::string const &replacement=std::string())
Identifies the extension in {replacement}, trims it, and replaces this instance's extension with it.
std::string stem() const
Get the base name of the file without the extension.
std::string parentPath() const
Get the parent path.
std::string filename() const
Get the name of the file, extension included.
std::string str() const
Get the path in textual format.
Umask(mode_t mask)
Constructor.
Definition filesystem.cc:71