Kea 2.7.5
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 <cstdio>
14#include <cstdlib>
15#include <fstream>
16#include <string>
17
18#include <dirent.h>
19#include <fcntl.h>
20
21using namespace isc::util::str;
22using namespace std;
23
24namespace isc {
25namespace util {
26namespace file {
27
28string
29getContent(string const& file_name) {
30 if (!exists(file_name)) {
31 isc_throw(BadValue, "Expected a file at path '" << file_name << "'");
32 }
33 if (!isFile(file_name)) {
34 isc_throw(BadValue, "Expected '" << file_name << "' to be a regular file");
35 }
36 ifstream file(file_name, ios::in);
37 if (!file.is_open()) {
38 isc_throw(BadValue, "Cannot open '" << file_name);
39 }
40 string content;
41 file >> content;
42 return (content);
43}
44
45bool
46exists(string const& path) {
47 struct stat statbuf;
48 return (::stat(path.c_str(), &statbuf) == 0);
49}
50
51bool
52isDir(string const& path) {
53 struct stat statbuf;
54 if (::stat(path.c_str(), &statbuf) < 0) {
55 return (false);
56 }
57 return ((statbuf.st_mode & S_IFMT) == S_IFDIR);
58}
59
60bool
61isFile(string const& path) {
62 struct stat statbuf;
63 if (::stat(path.c_str(), &statbuf) < 0) {
64 return (false);
65 }
66 return ((statbuf.st_mode & S_IFMT) == S_IFREG);
67}
68
69Umask::Umask(mode_t mask) : orig_umask_(umask(S_IWGRP | S_IWOTH)) {
70 umask(orig_umask_ | mask);
71}
72
74 umask(orig_umask_);
75}
76
77bool
78isSocket(string const& path) {
79 struct stat statbuf;
80 if (::stat(path.c_str(), &statbuf) < 0) {
81 return (false);
82 }
83 return ((statbuf.st_mode & S_IFMT) == S_IFSOCK);
84}
85
86Path::Path(string const& full_name) {
87 if (!full_name.empty()) {
88 bool dir_present = false;
89 // Find the directory.
90 size_t last_slash = full_name.find_last_of('/');
91 if (last_slash != string::npos) {
92 // Found the last slash, so extract directory component and
93 // set where the scan for the last_dot should terminate.
94 parent_path_ = full_name.substr(0, last_slash);
95 if (last_slash == full_name.size()) {
96 // The entire string was a directory, so exit and don't
97 // do any more searching.
98 return;
99 }
100
101 // Found a directory so note the fact.
102 dir_present = true;
103 }
104
105 // Now search backwards for the last ".".
106 size_t last_dot = full_name.find_last_of('.');
107 if ((last_dot == string::npos) || (dir_present && (last_dot < last_slash))) {
108 // Last "." either not found or it occurs to the left of the last
109 // slash if a directory was present (so it is part of a directory
110 // name). In this case, the remainder of the string after the slash
111 // is the name part.
112 stem_ = full_name.substr(last_slash + 1);
113 return;
114 }
115
116 // Did find a valid dot, so it and everything to the right is the
117 // extension...
118 extension_ = full_name.substr(last_dot);
119
120 // ... and the name of the file is everything in between.
121 if ((last_dot - last_slash) > 1) {
122 stem_ = full_name.substr(last_slash + 1, last_dot - last_slash - 1);
123 }
124 }
125}
126
127string
128Path::str() const {
129 return (parent_path_ + ((parent_path_.empty() || parent_path_ == "/") ? string() : "/") + stem_ + extension_);
130}
131
132string
134 return (parent_path_);
135}
136
137string
138Path::stem() const {
139 return (stem_);
140}
141
142string
144 return (extension_);
145}
146
147string
149 return (stem_ + extension_);
150}
151
152Path&
153Path::replaceExtension(string const& replacement) {
154 string const trimmed_replacement(trim(replacement));
155 if (trimmed_replacement.empty()) {
156 extension_ = string();
157 } else {
158 size_t const last_dot(trimmed_replacement.find_last_of('.'));
159 if (last_dot == string::npos) {
160 extension_ = "." + trimmed_replacement;
161 } else {
162 extension_ = trimmed_replacement.substr(last_dot);
163 }
164 }
165 return (*this);
166}
167
168Path&
169Path::replaceParentPath(string const& replacement) {
170 string const trimmed_replacement(trim(replacement));
171 if (trimmed_replacement.empty()) {
172 parent_path_ = string();
173 } else if (trimmed_replacement == "/") {
174 parent_path_ = trimmed_replacement;
175 } else if (trimmed_replacement.at(trimmed_replacement.size() - 1) == '/') {
176 parent_path_ = trimmed_replacement.substr(0, trimmed_replacement.size() - 1);
177 } else {
178 parent_path_ = trimmed_replacement;
179 }
180 return (*this);
181}
182
184 char dir[]("/tmp/kea-tmpdir-XXXXXX");
185 char const* dir_name = mkdtemp(dir);
186 if (!dir_name) {
187 isc_throw(Unexpected, "mkdtemp failed " << dir << ": " << strerror(errno));
188 }
189 dir_name_ = string(dir_name);
190}
191
193 DIR *dir(opendir(dir_name_.c_str()));
194 if (!dir) {
195 return;
196 }
197
198 struct dirent *i;
199 string filepath;
200 while ((i = readdir(dir))) {
201 if (strcmp(i->d_name, ".") == 0 || strcmp(i->d_name, "..") == 0) {
202 continue;
203 }
204
205 filepath = dir_name_ + '/' + i->d_name;
206 remove(filepath.c_str());
207 }
208 closedir(dir);
209 rmdir(dir_name_.c_str());
210}
211
213 return dir_name_;
214}
215
216} // namespace file
217} // namespace util
218} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
#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:29
bool isFile(string const &path)
Check if there is a file at the given path.
Definition filesystem.cc:61
bool exists(string const &path)
Check if there is a file or directory at the given path.
Definition filesystem.cc:46
bool isSocket(string const &path)
Definition filesystem.cc:78
bool isDir(string const &path)
Check if there is a directory at the given path.
Definition filesystem.cc:52
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:73
Path(std::string const &path)
Constructor.
Definition filesystem.cc:86
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:69