1/* 2 * Copyright (c) 2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 * Chris Emmons 30 */ 31 32#include <sys/stat.h> 33#include <sys/types.h> 34#include <dirent.h> 35 36#include <cassert> 37#include <cerrno> 38#include <climits> 39#include <cstdlib> 40#include <fstream> 41 42#include <gzstream.hh> 43 44#include "base/misc.hh" 45#include "base/output.hh" 46 47using namespace std; 48 49OutputDirectory simout; 50 51/** 52 * @file This file manages creating / deleting output files for the simulator. 53 */ 54OutputDirectory::OutputDirectory() 55{} 56 57OutputDirectory::~OutputDirectory() 58{ 59 for (map_t::iterator i = files.begin(); i != files.end(); i++) { 60 if (i->second) 61 delete i->second; 62 } 63} 64 65std::ostream * 66OutputDirectory::checkForStdio(const string &name) const 67{ 68 if (name == "cerr" || name == "stderr") 69 return &cerr; 70 71 if (name == "cout" || name == "stdout") 72 return &cout; 73 74 return NULL; 75} 76 77ostream * 78OutputDirectory::openFile(const string &filename, 79 ios_base::openmode mode) 80{ 81 if (filename.find(".gz", filename.length()-3) < filename.length()) { 82 ogzstream *file = new ogzstream(filename.c_str(), mode); 83 if (!file->is_open()) 84 fatal("Cannot open file %s", filename); 85 assert(files.find(filename) == files.end()); 86 files[filename] = file; 87 return file; 88 } else { 89 ofstream *file = new ofstream(filename.c_str(), mode); 90 if (!file->is_open()) 91 fatal("Cannot open file %s", filename); 92 assert(files.find(filename) == files.end()); 93 files[filename] = file; 94 return file; 95 } 96} 97 98void 99OutputDirectory::close(ostream *openStream) { 100 map_t::iterator i; 101 for (i = files.begin(); i != files.end(); i++) { 102 if (i->second != openStream) 103 continue; 104 105 ofstream *fs = dynamic_cast<ofstream*>(i->second); 106 if (fs) { 107 fs->close(); 108 delete i->second; 109 break; 110 } else { 111 ogzstream *gfs = dynamic_cast<ogzstream*>(i->second); 112 if (gfs) { 113 gfs->close(); 114 delete i->second; 115 break; 116 } 117 } 118 } 119 120 if (i == files.end()) 121 fatal("Attempted to close an unregistred file stream"); 122 123 files.erase(i); 124} 125 126void 127OutputDirectory::setDirectory(const string &d) 128{ 129 if (!dir.empty()) 130 panic("Output directory already set!\n"); 131 132 dir = d; 133 134 // guarantee that directory ends with a path separator 135 if (dir[dir.size() - 1] != PATH_SEPARATOR) 136 dir += PATH_SEPARATOR; 137} 138 139const string & 140OutputDirectory::directory() const 141{ 142 if (dir.empty()) 143 panic("Output directory not set!"); 144 145 return dir; 146} 147 148inline string 149OutputDirectory::resolve(const string &name) const 150{ 151 return (name[0] != PATH_SEPARATOR) ? dir + name : name; 152} 153 154ostream * 155OutputDirectory::create(const string &name, bool binary) 156{ 157 ostream *file = checkForStdio(name); 158 if (file) 159 return file; 160 161 string filename = resolve(name); 162 ios_base::openmode mode =
| 1/* 2 * Copyright (c) 2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 * Chris Emmons 30 */ 31 32#include <sys/stat.h> 33#include <sys/types.h> 34#include <dirent.h> 35 36#include <cassert> 37#include <cerrno> 38#include <climits> 39#include <cstdlib> 40#include <fstream> 41 42#include <gzstream.hh> 43 44#include "base/misc.hh" 45#include "base/output.hh" 46 47using namespace std; 48 49OutputDirectory simout; 50 51/** 52 * @file This file manages creating / deleting output files for the simulator. 53 */ 54OutputDirectory::OutputDirectory() 55{} 56 57OutputDirectory::~OutputDirectory() 58{ 59 for (map_t::iterator i = files.begin(); i != files.end(); i++) { 60 if (i->second) 61 delete i->second; 62 } 63} 64 65std::ostream * 66OutputDirectory::checkForStdio(const string &name) const 67{ 68 if (name == "cerr" || name == "stderr") 69 return &cerr; 70 71 if (name == "cout" || name == "stdout") 72 return &cout; 73 74 return NULL; 75} 76 77ostream * 78OutputDirectory::openFile(const string &filename, 79 ios_base::openmode mode) 80{ 81 if (filename.find(".gz", filename.length()-3) < filename.length()) { 82 ogzstream *file = new ogzstream(filename.c_str(), mode); 83 if (!file->is_open()) 84 fatal("Cannot open file %s", filename); 85 assert(files.find(filename) == files.end()); 86 files[filename] = file; 87 return file; 88 } else { 89 ofstream *file = new ofstream(filename.c_str(), mode); 90 if (!file->is_open()) 91 fatal("Cannot open file %s", filename); 92 assert(files.find(filename) == files.end()); 93 files[filename] = file; 94 return file; 95 } 96} 97 98void 99OutputDirectory::close(ostream *openStream) { 100 map_t::iterator i; 101 for (i = files.begin(); i != files.end(); i++) { 102 if (i->second != openStream) 103 continue; 104 105 ofstream *fs = dynamic_cast<ofstream*>(i->second); 106 if (fs) { 107 fs->close(); 108 delete i->second; 109 break; 110 } else { 111 ogzstream *gfs = dynamic_cast<ogzstream*>(i->second); 112 if (gfs) { 113 gfs->close(); 114 delete i->second; 115 break; 116 } 117 } 118 } 119 120 if (i == files.end()) 121 fatal("Attempted to close an unregistred file stream"); 122 123 files.erase(i); 124} 125 126void 127OutputDirectory::setDirectory(const string &d) 128{ 129 if (!dir.empty()) 130 panic("Output directory already set!\n"); 131 132 dir = d; 133 134 // guarantee that directory ends with a path separator 135 if (dir[dir.size() - 1] != PATH_SEPARATOR) 136 dir += PATH_SEPARATOR; 137} 138 139const string & 140OutputDirectory::directory() const 141{ 142 if (dir.empty()) 143 panic("Output directory not set!"); 144 145 return dir; 146} 147 148inline string 149OutputDirectory::resolve(const string &name) const 150{ 151 return (name[0] != PATH_SEPARATOR) ? dir + name : name; 152} 153 154ostream * 155OutputDirectory::create(const string &name, bool binary) 156{ 157 ostream *file = checkForStdio(name); 158 if (file) 159 return file; 160 161 string filename = resolve(name); 162 ios_base::openmode mode =
|
164 file = openFile(filename, mode); 165 166 return file; 167} 168 169ostream * 170OutputDirectory::find(const string &name) const 171{ 172 ostream *file = checkForStdio(name); 173 if (file) 174 return file; 175 176 const string filename = resolve(name); 177 map_t::const_iterator i = files.find(filename); 178 if (i != files.end()) 179 return (*i).second; 180 181 return NULL; 182} 183 184bool 185OutputDirectory::isFile(const std::ostream *os) 186{ 187 return os && os != &cerr && os != &cout; 188} 189 190bool 191OutputDirectory::isFile(const string &name) const 192{ 193 // definitely a file if in our data structure 194 if (find(name) != NULL) return true; 195 196 struct stat st_buf; 197 int st = stat(name.c_str(), &st_buf); 198 return (st == 0) && S_ISREG(st_buf.st_mode); 199} 200 201string 202OutputDirectory::createSubdirectory(const string &name) const 203{ 204 const string new_dir = resolve(name); 205 if (new_dir.find(directory()) == string::npos) 206 fatal("Attempting to create subdirectory not in m5 output dir\n"); 207 208 // if it already exists, that's ok; otherwise, fail if we couldn't create 209 if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST)) 210 fatal("Failed to create new output subdirectory '%s'\n", new_dir); 211 212 return name + PATH_SEPARATOR; 213} 214 215void 216OutputDirectory::remove(const string &name, bool recursive) 217{ 218 const string fname = resolve(name); 219 220 if (fname.find(directory()) == string::npos) 221 fatal("Attempting to remove file/dir not in output dir\n"); 222 223 if (isFile(fname)) { 224 // close and release file if we have it open 225 map_t::iterator itr = files.find(fname); 226 if (itr != files.end()) { 227 delete itr->second; 228 files.erase(itr); 229 } 230 231 if (::remove(fname.c_str()) != 0) 232 fatal("Could not erase file '%s'\n", fname); 233 } else { 234 // assume 'name' is a directory 235 if (recursive) { 236 DIR *dir = opendir(fname.c_str()); 237 238 // silently ignore removal request for non-existent directory 239 if ((!dir) && (errno == ENOENT)) 240 return; 241 242 // fail on other errors 243 if (!dir) { 244 perror("opendir"); 245 fatal("Error opening directory for recursive removal '%s'\n", 246 fname); 247 } 248 249 struct dirent *de = readdir(dir); 250 while (de != NULL) { 251 // ignore files starting with a '.'; user must delete those 252 // manually if they really want to 253 if (de->d_name[0] != '.') 254 remove(name + PATH_SEPARATOR + de->d_name, recursive); 255 256 de = readdir(dir); 257 } 258 } 259 260 // try to force recognition that we deleted the files in the directory 261 sync(); 262 263 if (::remove(fname.c_str()) != 0) { 264 perror("Warning! 'remove' failed. Could not erase directory."); 265 } 266 } 267}
| 164 file = openFile(filename, mode); 165 166 return file; 167} 168 169ostream * 170OutputDirectory::find(const string &name) const 171{ 172 ostream *file = checkForStdio(name); 173 if (file) 174 return file; 175 176 const string filename = resolve(name); 177 map_t::const_iterator i = files.find(filename); 178 if (i != files.end()) 179 return (*i).second; 180 181 return NULL; 182} 183 184bool 185OutputDirectory::isFile(const std::ostream *os) 186{ 187 return os && os != &cerr && os != &cout; 188} 189 190bool 191OutputDirectory::isFile(const string &name) const 192{ 193 // definitely a file if in our data structure 194 if (find(name) != NULL) return true; 195 196 struct stat st_buf; 197 int st = stat(name.c_str(), &st_buf); 198 return (st == 0) && S_ISREG(st_buf.st_mode); 199} 200 201string 202OutputDirectory::createSubdirectory(const string &name) const 203{ 204 const string new_dir = resolve(name); 205 if (new_dir.find(directory()) == string::npos) 206 fatal("Attempting to create subdirectory not in m5 output dir\n"); 207 208 // if it already exists, that's ok; otherwise, fail if we couldn't create 209 if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST)) 210 fatal("Failed to create new output subdirectory '%s'\n", new_dir); 211 212 return name + PATH_SEPARATOR; 213} 214 215void 216OutputDirectory::remove(const string &name, bool recursive) 217{ 218 const string fname = resolve(name); 219 220 if (fname.find(directory()) == string::npos) 221 fatal("Attempting to remove file/dir not in output dir\n"); 222 223 if (isFile(fname)) { 224 // close and release file if we have it open 225 map_t::iterator itr = files.find(fname); 226 if (itr != files.end()) { 227 delete itr->second; 228 files.erase(itr); 229 } 230 231 if (::remove(fname.c_str()) != 0) 232 fatal("Could not erase file '%s'\n", fname); 233 } else { 234 // assume 'name' is a directory 235 if (recursive) { 236 DIR *dir = opendir(fname.c_str()); 237 238 // silently ignore removal request for non-existent directory 239 if ((!dir) && (errno == ENOENT)) 240 return; 241 242 // fail on other errors 243 if (!dir) { 244 perror("opendir"); 245 fatal("Error opening directory for recursive removal '%s'\n", 246 fname); 247 } 248 249 struct dirent *de = readdir(dir); 250 while (de != NULL) { 251 // ignore files starting with a '.'; user must delete those 252 // manually if they really want to 253 if (de->d_name[0] != '.') 254 remove(name + PATH_SEPARATOR + de->d_name, recursive); 255 256 de = readdir(dir); 257 } 258 } 259 260 // try to force recognition that we deleted the files in the directory 261 sync(); 262 263 if (::remove(fname.c_str()) != 0) { 264 perror("Warning! 'remove' failed. Could not erase directory."); 265 } 266 } 267}
|