Kea 2.7.0
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#include <sys/stat.h>
23
24using namespace isc::util::str;
25using namespace std;
26
27namespace isc {
28namespace util {
29namespace file {
30
31string
32getContent(string const& file_name) {
33 if (!exists(file_name)) {
34 isc_throw(BadValue, "Expected a file at path '" << file_name << "'");
35 }
36 if (!isFile(file_name)) {
37 isc_throw(BadValue, "Expected '" << file_name << "' to be a regular file");
38 }
39 ifstream file(file_name, ios::in);
40 if (!file.is_open()) {
41 isc_throw(BadValue, "Cannot open '" << file_name);
42 }
43 string content;
44 file >> content;
45 return (content);
46}
47
48bool
49exists(string const& path) {
50 struct stat statbuf;
51 return (::stat(path.c_str(), &statbuf) == 0);
52}
53
54bool
55isDir(string const& path) {
56 struct stat statbuf;
57 if (::stat(path.c_str(), &statbuf) < 0) {
58 return (false);
59 }
60 return ((statbuf.st_mode & S_IFMT) == S_IFDIR);
61}
62
63bool
64isFile(string const& path) {
65 struct stat statbuf;
66 if (::stat(path.c_str(), &statbuf) < 0) {
67 return (false);
68 }
69 return ((statbuf.st_mode & S_IFMT) == S_IFREG);
70}
71
72Path::Path(string const& full_name) {
73 if (!full_name.empty()) {
74 bool dir_present = false;
75 // Find the directory.
76 size_t last_slash = full_name.find_last_of('/');
77 if (last_slash != string::npos) {
78 // Found the last slash, so extract directory component and
79 // set where the scan for the last_dot should terminate.
80 parent_path_ = full_name.substr(0, last_slash + 1);
81 if (last_slash == full_name.size()) {
82 // The entire string was a directory, so exit not and don't
83 // do any more searching.
84 return;
85 }
86
87 // Found a directory so note the fact.
88 dir_present = true;
89 }
90
91 // Now search backwards for the last ".".
92 size_t last_dot = full_name.find_last_of('.');
93 if ((last_dot == string::npos) || (dir_present && (last_dot < last_slash))) {
94 // Last "." either not found or it occurs to the left of the last
95 // slash if a directory was present (so it is part of a directory
96 // name). In this case, the remainder of the string after the slash
97 // is the name part.
98 stem_ = full_name.substr(last_slash + 1);
99 return;
100 }
101
102 // Did find a valid dot, so it and everything to the right is the
103 // extension...
104 extension_ = full_name.substr(last_dot);
105
106 // ... and the name of the file is everything in between.
107 if ((last_dot - last_slash) > 1) {
108 stem_ = full_name.substr(last_slash + 1, last_dot - last_slash - 1);
109 }
110 }
111}
112
113string
114Path::str() const {
115 return (parent_path_ + stem_ + extension_);
116}
117
118string
120 return (parent_path_);
121}
122
123string
124Path::stem() const {
125 return (stem_);
126}
127
128string
130 return (extension_);
131}
132
133string
135 return (stem_ + extension_);
136}
137
138Path&
139Path::replaceExtension(string const& replacement) {
140 string const trimmed_replacement(trim(replacement));
141 if (trimmed_replacement.empty()) {
142 extension_ = string();
143 } else {
144 size_t const last_dot(trimmed_replacement.find_last_of('.'));
145 if (last_dot == string::npos) {
146 extension_ = "." + trimmed_replacement;
147 } else {
148 extension_ = trimmed_replacement.substr(last_dot);
149 }
150 }
151 return (*this);
152}
153
154Path&
155Path::replaceParentPath(string const& replacement) {
156 string const trimmed_replacement(trim(replacement));
157 if (trimmed_replacement.empty()) {
158 parent_path_ = string();
159 } else if (trimmed_replacement.at(trimmed_replacement.size() - 1) == '/') {
160 parent_path_ = trimmed_replacement;
161 } else {
162 parent_path_ = trimmed_replacement + '/';
163 }
164 return (*this);
165}
166
167} // namespace file
168} // namespace util
169} // 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:32
bool isFile(string const &path)
Check if there is a file at the given path.
Definition filesystem.cc:64
bool exists(string const &path)
Check if there is a file or directory at the given path.
Definition filesystem.cc:49
bool isDir(string const &path)
Check if there is a directory at the given path.
Definition filesystem.cc:55
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:52
Path(std::string const &path)
Constructor.
Definition filesystem.cc:72
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.