gem5/src/base/output.cc
Andreas Hansson 7661f1c2bf ext: Replace gzstream with iostream3 from zlib to avoid LGPL
This patch replaces the gzstream zlib wrapper with the iostream3
wrapper provided as part of zlib contributions. The main reason for
the switch is to avoid including LGPL in the default gem5
build. iostream3 is provided under a more permissive license:

The code is provided "as is", with the permission to use, copy,
modify, distribute and sell it for any purpose without fee.
2016-01-11 05:52:18 -05:00

273 lines
7.5 KiB
C++

/*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Chris Emmons
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <cassert>
#include <cerrno>
#include <climits>
#include <cstdlib>
#include <fstream>
#include <zfstream.h>
#include "base/misc.hh"
#include "base/output.hh"
using namespace std;
OutputDirectory simout;
/**
* @file This file manages creating / deleting output files for the simulator.
*/
OutputDirectory::OutputDirectory()
{}
OutputDirectory::~OutputDirectory()
{
for (map_t::iterator i = files.begin(); i != files.end(); i++) {
if (i->second)
delete i->second;
}
}
std::ostream *
OutputDirectory::checkForStdio(const string &name) const
{
if (name == "cerr" || name == "stderr")
return &cerr;
if (name == "cout" || name == "stdout")
return &cout;
return NULL;
}
ostream *
OutputDirectory::openFile(const string &filename,
ios_base::openmode mode, bool no_gz)
{
bool gz = !no_gz;
gz = gz && filename.find(".gz", filename.length()-3) < filename.length();
if (gz) {
gzofstream *file = new gzofstream(filename.c_str(), mode);
if (!file->is_open())
fatal("Cannot open file %s", filename);
assert(files.find(filename) == files.end());
files[filename] = file;
return file;
} else {
ofstream *file = new ofstream(filename.c_str(), mode);
if (!file->is_open())
fatal("Cannot open file %s", filename);
assert(files.find(filename) == files.end());
files[filename] = file;
return file;
}
}
void
OutputDirectory::close(ostream *openStream) {
map_t::iterator i;
for (i = files.begin(); i != files.end(); i++) {
if (i->second != openStream)
continue;
ofstream *fs = dynamic_cast<ofstream*>(i->second);
if (fs) {
fs->close();
delete i->second;
break;
} else {
gzofstream *gfs = dynamic_cast<gzofstream*>(i->second);
if (gfs) {
gfs->close();
delete i->second;
break;
}
}
}
if (i == files.end())
fatal("Attempted to close an unregistred file stream");
files.erase(i);
}
void
OutputDirectory::setDirectory(const string &d)
{
if (!dir.empty())
panic("Output directory already set!\n");
dir = d;
// guarantee that directory ends with a path separator
if (dir[dir.size() - 1] != PATH_SEPARATOR)
dir += PATH_SEPARATOR;
}
const string &
OutputDirectory::directory() const
{
if (dir.empty())
panic("Output directory not set!");
return dir;
}
string
OutputDirectory::resolve(const string &name) const
{
return (name[0] != PATH_SEPARATOR) ? dir + name : name;
}
ostream *
OutputDirectory::create(const string &name, bool binary, bool no_gz)
{
ostream *file = checkForStdio(name);
if (file)
return file;
string filename = resolve(name);
ios_base::openmode mode =
ios::trunc | (binary ? ios::binary : (ios::openmode)0);
file = openFile(filename, mode, no_gz);
return file;
}
ostream *
OutputDirectory::find(const string &name) const
{
ostream *file = checkForStdio(name);
if (file)
return file;
const string filename = resolve(name);
map_t::const_iterator i = files.find(filename);
if (i != files.end())
return (*i).second;
return NULL;
}
bool
OutputDirectory::isFile(const std::ostream *os)
{
return os && os != &cerr && os != &cout;
}
bool
OutputDirectory::isFile(const string &name) const
{
// definitely a file if in our data structure
if (find(name) != NULL) return true;
struct stat st_buf;
int st = stat(name.c_str(), &st_buf);
return (st == 0) && S_ISREG(st_buf.st_mode);
}
string
OutputDirectory::createSubdirectory(const string &name) const
{
const string new_dir = resolve(name);
if (new_dir.find(directory()) == string::npos)
fatal("Attempting to create subdirectory not in m5 output dir\n");
// if it already exists, that's ok; otherwise, fail if we couldn't create
if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST))
fatal("Failed to create new output subdirectory '%s'\n", new_dir);
return name + PATH_SEPARATOR;
}
void
OutputDirectory::remove(const string &name, bool recursive)
{
const string fname = resolve(name);
if (fname.find(directory()) == string::npos)
fatal("Attempting to remove file/dir not in output dir\n");
if (isFile(fname)) {
// close and release file if we have it open
map_t::iterator itr = files.find(fname);
if (itr != files.end()) {
delete itr->second;
files.erase(itr);
}
if (::remove(fname.c_str()) != 0)
fatal("Could not erase file '%s'\n", fname);
} else {
// assume 'name' is a directory
if (recursive) {
DIR *subdir = opendir(fname.c_str());
// silently ignore removal request for non-existent directory
if ((!subdir) && (errno == ENOENT))
return;
// fail on other errors
if (!subdir) {
perror("opendir");
fatal("Error opening directory for recursive removal '%s'\n",
fname);
}
struct dirent *de = readdir(subdir);
while (de != NULL) {
// ignore files starting with a '.'; user must delete those
// manually if they really want to
if (de->d_name[0] != '.')
remove(name + PATH_SEPARATOR + de->d_name, recursive);
de = readdir(subdir);
}
closedir(subdir);
}
// try to force recognition that we deleted the files in the directory
sync();
if (::remove(fname.c_str()) != 0) {
perror("Warning! 'remove' failed. Could not erase directory.");
}
}
}