1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 #include <map>
26 #include <mutex>
27 #include <iostream>
28 #include <sstream>
29 #include <fstream>
30 #include <dirent.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include "fsutil.h"
35 #include "strutil.h"
36 //#define TRACEMEM
37 #ifdef TRACEMEM
38
39 struct item{
40 const char * tag;
41 void *ptr;
42 size_t size;
43 };
44 #define HEAP 100000
45 #define HEAPSIZE (HEAP*sizeof(item))
46 static item *items = new item[HEAP];
47 static int itemc =0;
48 static long heapUsage = 0;
49 const char *grabTag = "general";
50
51 std::recursive_mutex heapRecursiveMutex;
52
53 void lockheap() {
54 // std::cerr << "about to acquire lock " << index(std::this_thread::get_id()) << std::endl;
55 while (!heapRecursiveMutex.try_lock()) {
56 // std::cerr << "Looks like we are contended!" << std::endl;
57 // std::cerr.flush();
58 ::usleep(1000);
59 }
60 // recursiveMutex.lock();
61 // std::cerr << "got lock " << index(std::this_thread::get_id()) << std::endl;
62
63 }
64
65 void unlockheap() {
66 heapRecursiveMutex.unlock();
67 //std::cerr << "just released lock " << index(std::this_thread::get_id()) << std::endl;
68 }
69
70 void *grab(const char *tag, size_t bytes){
71
72 if (bytes == HEAPSIZE){
73 return malloc(bytes);
74 }
75
76 if (itemc == 0){
77 ::memset(items, 0, HEAPSIZE);
78 }
79 lockheap();
80 items[itemc].size =bytes;
81 items[itemc].tag =tag;
82 heapUsage+=bytes;
83 // std::cout << "allocating slot "<<itemc<< " " << bytes<< " from "<< tag << std::endl;
84 void *ptr = items[itemc++].ptr =malloc(bytes);
85 unlockheap();
86 return ptr;
87 }
88
89 void * operator new(size_t bytes){
90 return grab(grabTag, bytes);
91 }
92 void operator delete(void *bytes){
93
94 for (int i=0; i< itemc; i++){
95 if (items[i].ptr == bytes){
96 // std::cout << "freeing "<<items[i].size<<" from "<<i<< " " << items[i].tag << std::endl;
97 lockheap();
98 heapUsage-=items[i].size;
99 free(bytes);
100 items[i].ptr = nullptr;
101 items[i].size=0;
102
103 unlockheap();
104 std::cout << "delta "<<heapUsage<< std::endl;
105 return;
106 }
107 }
108
109 std::cout << "no allocation for "<< (long)bytes<<std::endl;
110 }
111 #endif
112 void fsutil::visit(const std::string &dirName, bool recurse, std::function<void(bool dir, std::string name)> visitor) {
113 DIR *d;
114 if ((d = opendir(dirName.c_str())) != nullptr) {
115 struct dirent *ent;
116 while ((ent = readdir(d)) != nullptr) {
117 std::string name = dirName + "/" + ent->d_name;
118 if (ent->d_type & DT_REG) {
119 visitor(false, name);
120 } else if (std::strcmp(ent->d_name, ".") != 0 && std::strcmp(ent->d_name, "..") != 0 &&
121 ent->d_type & DT_DIR) {
122 visitor(true, name);
123 if (recurse) {
124 visit(name, recurse, visitor);
125 }
126 }
127 }
128 closedir(d);
129 }
130 }
131
132 void fsutil::forEachFileName(const std::string &dirName, std::function<void(std::string name)> visitor) {
133 DIR *d;
134 if ((d = opendir(dirName.c_str())) != nullptr) {
135 struct dirent *ent;
136 while ((ent = readdir(d)) != nullptr) {
137 std::string name = dirName + "/" + ent->d_name;
138 if (ent->d_type & DT_REG) {
139 visitor(name);
140 }
141 }
142 closedir(d);
143 }
144 }
145
146 void fsutil::forEachDirName(const std::string &dirName, std::function<void(std::string name)> visitor) {
147 DIR *d;
148 if ((d = opendir(dirName.c_str())) != nullptr) {
149 struct dirent *ent;
150 while ((ent = readdir(d)) != nullptr) {
151 std::string name = dirName + "/" + ent->d_name;
152 if (ent->d_type & DT_DIR && std::strcmp(ent->d_name, ".") != 0 && std::strcmp(ent->d_name, "..") != 0) {
153 visitor(name);
154 }
155 closedir(d);
156 }
157 }
158 }
159
160 void fsutil::forEachLine(const std::string &fileName, std::function<void(std::string name)> visitor) {
161 std::size_t current, previous = 0;
162 std::string content = getFile(fileName);
163 current = content.find('\n');
164 while (current != std::string::npos) {
165 visitor(std::string(content, previous, current - previous));
166 previous = current + 1;
167 current = content.find('\n', previous);
168 }
169 }
170
171 #define BUF_SIZE 4096
172
173 void fsutil::send(int from, size_t bytes, int to) {
174 char buf[BUF_SIZE];
175 size_t bytesRead;
176 size_t totalSent = 0;
177 size_t bytesSent;
178 while (bytes > 0
179 && (((bytesRead = read(from, buf, ((bytes < BUF_SIZE) ? bytes : BUF_SIZE)))) > 0)
180 && (((bytesSent = ::write(to, buf, bytesRead))) > 0)) {
181 bytes -= bytesRead;
182 totalSent += bytesRead;
183 }
184 if (bytesSent == 0) {
185 perror("sendfile: send() transferred 0 bytes");
186 }
187 }
188
189 void fsutil::send(const std::string &fileName, int to) {
190 int fd = ::open(fileName.c_str(), O_RDONLY);
191 size_t bytes = fsutil::size(fileName);
192 send(fd, bytes, to);
193 ::close(fd);
194 }
195
196
197 size_t fsutil::size(const std::string &fileName) {
198 struct stat st;
199 stat(fileName.c_str(), &st);
200 return st.st_size;
201 }
202
203 bool fsutil::isDir(const std::string &dirName) {
204 struct stat buffer;
205 return (stat(dirName.c_str(), &buffer) == 0 && S_ISDIR(buffer.st_mode));
206 }
207
208 bool fsutil::removeFile(const std::string &dirName) {
209 struct stat buffer;
210 if (stat(dirName.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode)) {
211 std::cerr << "removing file '" + dirName << "'" << std::endl;
212 return (::unlink(dirName.c_str()) == 0);
213 }
214 return false;
215 }
216
217 bool fsutil::isFile(const std::string &fileName) {
218 struct stat buffer;
219 return (stat(fileName.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode));
220 }
221
222 bool fsutil::isFileOrLink(const std::string &fileName) {
223 struct stat buffer;
224 return (stat(fileName.c_str(), &buffer) == 0 && (S_ISREG(buffer.st_mode) || (S_ISLNK(buffer.st_mode))));
225 }
226
227 bool fsutil::isFile(const std::string &dirName, const std::string &fileName) {
228 std::string path = dirName + "/" + fileName;
229 return isFile(path);
230 }
231
232 bool fsutil::isFileOrLink(const std::string &dirName, const std::string &fileName) {
233 std::string path = dirName + "/" + fileName;
234 return isFileOrLink(path);
235 }
236
237 bool fsutil::hasFileSuffix(const std::string &fileName, const std::string &suffix) {
238 return strutil::endsWith(fileName, suffix);
239 }
240
241 std::string fsutil::getFileNameEndingWith(const std::string &dir, const std::string &suffix) {
242 std::vector<std::string> matches;
243 visit(dir, false, [&](auto dir, auto n) { if (!dir && hasFileSuffix(n, suffix)) matches.push_back(n); });
244 if (matches.size() == 0) {
245 std::cout << "no file: *" << suffix << std::endl;
246 } else if (matches.size() > 1) {
247 std::cout << "many : *" << suffix << std::endl;
248 } else {
249 return *matches.begin();
250 }
251 return "";
252 }
253
254 void fsutil::mkdir_p(char *path) {
255 char *sep = std::strrchr(path, '/');
256 if (sep != NULL) {
257 *sep = 0;
258 mkdir_p(path);
259 *sep = '/';
260 }
261 if (mkdir(path, 0777) && errno != EEXIST) {
262 printf("error while trying to create '%s'\n%m\n", path);
263 }
264 }
265
266 std::string fsutil::getFile(const std::string &path) {
267 std::stringstream buf;
268 std::ifstream input(path.c_str());
269 buf << input.rdbuf();
270 return buf.str();
271 }
272
273 BufferCursor *fsutil::getFileBufferCursor(const std::string &path) {
274 size_t s = size(path);
275 // read directly into buffer! buffer(path.c_str());
276 char *buf = (char *) malloc(s + 1);
277 BufferCursor *buffer = new BufferCursor(buf, s + 1);
278 int fd = open(path.c_str(), O_RDONLY);
279 ::read(fd, buffer->getStart(), buffer->getSize());
280 close(fd);
281 return buffer;
282 }
283
284 void fsutil::putFile(const std::string &path, const std::string &content) {
285 std::ofstream out(path);
286 out << content;
287 out.close();
288 }
289
290 void fsutil::putFileBufferCursor(const std::string &path, BufferCursor *buffer) {
291 std::cerr << "who the hell called putFileBUffer" << std::endl;
292 ::exit(1);
293 }