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 }