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 "fsutil.h" 28 #include "strutil.h" 29 //#define TRACEMEM 30 #ifdef TRACEMEM 31 32 struct item{ 33 const char * tag; 34 void *ptr; 35 size_t size; 36 }; 37 #define HEAP 100000 38 #define HEAPSIZE (HEAP*sizeof(item)) 39 static item *items = new item[HEAP]; 40 static int itemc =0; 41 static long heapUsage = 0; 42 const char *grabTag = "general"; 43 44 std::recursive_mutex heapRecursiveMutex; 45 46 void lockheap() { 47 // std::cerr << "about to acquire lock " << index(std::this_thread::get_id()) << std::endl; 48 while (!heapRecursiveMutex.try_lock()) { 49 // std::cerr << "Looks like we are contended!" << std::endl; 50 // std::cerr.flush(); 51 ::usleep(1000); 52 } 53 // recursiveMutex.lock(); 54 // std::cerr << "got lock " << index(std::this_thread::get_id()) << std::endl; 55 56 } 57 58 void unlockheap() { 59 heapRecursiveMutex.unlock(); 60 //std::cerr << "just released lock " << index(std::this_thread::get_id()) << std::endl; 61 } 62 63 void *grab(const char *tag, size_t bytes){ 64 65 if (bytes == HEAPSIZE){ 66 return malloc(bytes); 67 } 68 69 if (itemc == 0){ 70 ::memset(items, 0, HEAPSIZE); 71 } 72 lockheap(); 73 items[itemc].size =bytes; 74 items[itemc].tag =tag; 75 heapUsage+=bytes; 76 // std::cout << "allocating slot "<<itemc<< " " << bytes<< " from "<< tag << std::endl; 77 void *ptr = items[itemc++].ptr =malloc(bytes); 78 unlockheap(); 79 return ptr; 80 } 81 82 void * operator new(size_t bytes){ 83 return grab(grabTag, bytes); 84 } 85 void operator delete(void *bytes){ 86 87 for (int i=0; i< itemc; i++){ 88 if (items[i].ptr == bytes){ 89 // std::cout << "freeing "<<items[i].size<<" from "<<i<< " " << items[i].tag << std::endl; 90 lockheap(); 91 heapUsage-=items[i].size; 92 free(bytes); 93 items[i].ptr = nullptr; 94 items[i].size=0; 95 96 unlockheap(); 97 std::cout << "delta "<<heapUsage<< std::endl; 98 return; 99 } 100 } 101 102 std::cout << "no allocation for "<< (long)bytes<<std::endl; 103 } 104 #endif 105 void fsutil::visit(const std::string &dirName, bool recurse, std::function<void(bool dir, std::string name)> visitor) { 106 DIR *d; 107 if ((d = opendir(dirName.c_str())) != nullptr) { 108 struct dirent *ent; 109 while ((ent = readdir(d)) != nullptr) { 110 std::string name = dirName + "/" + ent->d_name; 111 if (ent->d_type & DT_REG) { 112 visitor(false, name); 113 } else if (std::strcmp(ent->d_name, ".") != 0 && std::strcmp(ent->d_name, "..") != 0 && 114 ent->d_type & DT_DIR) { 115 visitor(true, name); 116 if (recurse) { 117 visit(name, recurse, visitor); 118 } 119 } 120 } 121 closedir(d); 122 } 123 } 124 125 void fsutil::forEachFileName(const std::string &dirName, std::function<void(std::string name)> visitor) { 126 DIR *d; 127 if ((d = opendir(dirName.c_str())) != nullptr) { 128 struct dirent *ent; 129 while ((ent = readdir(d)) != nullptr) { 130 std::string name = dirName + "/" + ent->d_name; 131 if (ent->d_type & DT_REG) { 132 visitor(name); 133 } 134 } 135 closedir(d); 136 } 137 } 138 139 void fsutil::forEachDirName(const std::string &dirName, std::function<void(std::string name)> visitor) { 140 DIR *d; 141 if ((d = opendir(dirName.c_str())) != nullptr) { 142 struct dirent *ent; 143 while ((ent = readdir(d)) != nullptr) { 144 std::string name = dirName + "/" + ent->d_name; 145 if (ent->d_type & DT_DIR && std::strcmp(ent->d_name, ".") != 0 && std::strcmp(ent->d_name, "..") != 0) { 146 visitor(name); 147 148 } 149 closedir(d); 150 } 151 } 152 } 153 154 void fsutil::forEachLine(const std::string &fileName, std::function<void(std::string name)> visitor) { 155 std::size_t current, previous = 0; 156 std::string content = getFile(fileName); 157 current = content.find('\n'); 158 while (current != std::string::npos) { 159 visitor(std::string(content, previous, current - previous)); 160 previous = current + 1; 161 current = content.find('\n', previous); 162 } 163 } 164 165 #define BUF_SIZE 4096 166 167 void fsutil::send(int from, size_t bytes, int to) { 168 char buf[BUF_SIZE]; 169 size_t bytesRead; 170 size_t totalSent = 0; 171 size_t bytesSent; 172 while (bytes > 0 173 && (((bytesRead = read(from, buf, ((bytes < BUF_SIZE) ? bytes : BUF_SIZE)))) > 0) 174 && (((bytesSent = ::write(to, buf, bytesRead))) > 0)) { 175 bytes -= bytesRead; 176 totalSent += bytesRead; 177 } 178 if (bytesSent == 0) { 179 perror("sendfile: send() transferred 0 bytes"); 180 } 181 } 182 183 void fsutil::send(const std::string &fileName, int to) { 184 int fd = ::open(fileName.c_str(), O_RDONLY); 185 size_t bytes = fsutil::size(fileName); 186 send(fd, bytes, to); 187 ::close(fd); 188 } 189 190 191 size_t fsutil::size(const std::string &fileName) { 192 193 struct stat st; 194 stat(fileName.c_str(), &st); 195 return st.st_size; 196 } 197 198 bool fsutil::isDir(const std::string &dirName) { 199 struct stat buffer; 200 return (stat(dirName.c_str(), &buffer) == 0 && S_ISDIR(buffer.st_mode)); 201 } 202 203 bool fsutil::removeFile(const std::string &dirName) { 204 struct stat buffer; 205 if (stat(dirName.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode)){ 206 std::cerr << "removing file '"+dirName<<"'"<<std::endl; 207 return (::unlink(dirName.c_str()) == 0); 208 } 209 return false; 210 } 211 212 bool fsutil::isFile(const std::string &fileName) { 213 struct stat buffer; 214 return (stat(fileName.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode)); 215 } 216 bool fsutil::isFileOrLink(const std::string &fileName) { 217 struct stat buffer; 218 return (stat(fileName.c_str(), &buffer) == 0 && (S_ISREG(buffer.st_mode) || (S_ISLNK(buffer.st_mode)))); 219 } 220 221 bool fsutil::isFile(const std::string &dirName, const std::string &fileName) { 222 std::string path = dirName + "/" + fileName; 223 return isFile(path); 224 } 225 bool fsutil::isFileOrLink(const std::string &dirName, const std::string &fileName) { 226 std::string path = dirName + "/" + fileName; 227 return isFileOrLink(path); 228 } 229 230 bool fsutil::hasFileSuffix(const std::string &fileName, const std::string &suffix) { 231 return strutil::endsWith(fileName, suffix); 232 } 233 234 std::string fsutil::getFileNameEndingWith(const std::string &dir, const std::string &suffix) { 235 std::vector<std::string> matches; 236 visit(dir, false, [&](auto dir, auto n) { if (!dir && hasFileSuffix(n, suffix)) matches.push_back(n); }); 237 if (matches.size() == 0) { 238 std::cout << "no file: *" << suffix << std::endl; 239 } else if (matches.size() > 1) { 240 std::cout << "many : *" << suffix << std::endl; 241 } else { 242 return *matches.begin(); 243 } 244 return ""; 245 } 246 247 void fsutil::mkdir_p(char *path) { 248 char *sep = std::strrchr(path, '/'); 249 if (sep != NULL) { 250 *sep = 0; 251 mkdir_p(path); 252 *sep = '/'; 253 } 254 if (mkdir(path, 0777) && errno != EEXIST) { 255 printf("error while trying to create '%s'\n%m\n", path); 256 } 257 } 258 259 std::string fsutil::getFile(const std::string &path) { 260 std::stringstream buf; 261 std::ifstream input(path.c_str()); 262 buf << input.rdbuf(); 263 return buf.str(); 264 } 265 266 BufferCursor *fsutil::getFileBufferCursor(const std::string &path) { 267 size_t s = size(path); 268 // read directly into buffer! buffer(path.c_str()); 269 char *buf = (char *)malloc(s+1); 270 BufferCursor *buffer = new BufferCursor(buf, s + 1); 271 int fd = open(path.c_str(), O_RDONLY); 272 ::read(fd, buffer->getStart(), buffer->getSize()); 273 close(fd); 274 return buffer; 275 } 276 277 void fsutil::putFile(const std::string &path, const std::string &content) { 278 std::ofstream out(path); 279 out << content; 280 out.close(); 281 } 282 283 void fsutil::putFileBufferCursor(const std::string &path, BufferCursor *buffer) { 284 std::cerr << "who the hell called putFileBUffer" << std::endl; 285 ::exit(1); 286 }