/* * filesystem.cc * * This file is part of NEST. * * Copyright (C) 2004 The NEST Initiative * * NEST is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * NEST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NEST. If not, see <http://www.gnu.org/licenses/>. * */ #include <cassert> #include "filesystem.h" #include "arraydatum.h" #include "stringdatum.h" #include <errno.h> #include <dirent.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <fstream> #include <ctime> #include "compose.hpp" void FilesystemModule::init(SLIInterpreter *i) { i->createcommand("FileNames_", &filenamesfunction); i->createcommand("SetDirectory_", &setdirectoryfunction); i->createcommand("Directory", &directoryfunction); i->createcommand("MoveFile_", &movefilefunction); i->createcommand("CopyFile_", ©filefunction); i->createcommand("DeleteFile_", &deletefilefunction); i->createcommand("MakeDirectory_", &makedirectoryfunction); i->createcommand("RemoveDirectory_", &removedirectoryfunction); i->createcommand("tmpnam",&tmpnamfunction); i->createcommand("CompareFiles_s_s", &comparefilesfunction); } const std::string FilesystemModule::name(void) const { return std::string("Filesystem access"); } const std::string FilesystemModule::commandstring(void) const { return std::string("/filesystem /C++ ($Revision: 9952 $) provide-component /filesystem /SLI (7610) require-component"); } void FilesystemModule::FileNamesFunction::execute(SLIInterpreter *i) const { StringDatum *sd=dynamic_cast<StringDatum *>(i->OStack.top().datum()); assert(sd !=NULL); dirent *TheEntry; DIR *TheDirectory=opendir(sd->c_str()); if (TheDirectory!=NULL) { ArrayDatum* a=new ArrayDatum(); i->EStack.pop(); i->OStack.pop(); while ((TheEntry=readdir(TheDirectory))!=NULL) { Token string_token(new StringDatum(TheEntry->d_name)); a->push_back_move(string_token); } Token array_token(a); i->OStack.push_move(array_token); } else i->raiseerror(i->BadIOError); } void FilesystemModule::SetDirectoryFunction::execute(SLIInterpreter *i) const //string -> boolean { StringDatum *sd=dynamic_cast<StringDatum *>(i->OStack.top().datum()); assert(sd !=NULL); int s=chdir(sd->c_str()); i->OStack.pop(); if (!s) {i->OStack.push(i->baselookup(i->true_name));} else {i->OStack.push(i->baselookup(i->false_name));}; i->EStack.pop(); } /* BeginDocumentation Name: Directory - Return current working directory Synopsis: Directory -> string Description: Returns name of current working directory. This is where all ls, filestream etc. operations are done per default. Parameters: string : Name of current working directory Examples: Directory = -> /home/MyAccount/SNiFF/synod2 Bugs: - Author: Hehl FirstVersion: Oct 12th 1999 Remarks: SeeAlso: FileNames, SetDirectory, MakeDirectory, RemoveDirectory, cd, ls */ void FilesystemModule::DirectoryFunction::execute(SLIInterpreter *i) const { const int SIZE=256; //incremental buffer size, somewhat arbitrary! int size=SIZE; char *path_buffer = new char[size]; while (getcwd(path_buffer,size-1) == NULL) { //try again with a bigger buffer! if (errno != ERANGE) i->raiseerror(i->BadIOError); //size wasn't reason delete[]path_buffer; size+=SIZE; path_buffer = new char[size]; assert(path_buffer!=NULL); } Token sd(new StringDatum(path_buffer)); delete[](path_buffer); i->OStack.push_move(sd); i->EStack.pop(); } void FilesystemModule::MoveFileFunction::execute(SLIInterpreter *i) const //string string -> boolean { StringDatum *src=dynamic_cast<StringDatum *>(i->OStack.pick(1).datum()); StringDatum *dst=dynamic_cast<StringDatum *>(i->OStack.pick(0).datum()); assert(src !=NULL); assert(dst !=NULL); int s=link(src->c_str(),dst->c_str()); if (!s) { s=unlink(src->c_str()); if (s) //failed to remove old link: undo everything { int t=unlink(dst->c_str()); assert(t==0); //link was just created after all! }; }; i->OStack.pop(2); if (!s) {i->OStack.push(i->baselookup(i->true_name));} else {i->OStack.push(i->baselookup(i->false_name));}; i->EStack.pop(); } void FilesystemModule::CopyFileFunction::execute(SLIInterpreter *i) const //string string -> - { StringDatum *src=dynamic_cast<StringDatum *>(i->OStack.pick(1).datum()); StringDatum *dst=dynamic_cast<StringDatum *>(i->OStack.pick(0).datum()); assert(src !=NULL); assert(dst !=NULL); std::ofstream deststream(dst->c_str()); if(!deststream) { i->message(SLIInterpreter::M_ERROR, "CopyFile","Could not create destination file."); i->raiseerror(i->BadIOError); return; } std::ifstream sourcestream(src->c_str()); if(!sourcestream) { i->message(SLIInterpreter::M_ERROR, "CopyFile","Could not open source file."); i->raiseerror(i->BadIOError); return; } // copy while file in one call (see Josuttis chap 13.9 (File Access), p. 631) deststream << sourcestream.rdbuf(); if(!deststream) { i->message(SLIInterpreter::M_ERROR, "CopyFile","Error copying file."); i->raiseerror(i->BadIOError); return; } i->OStack.pop(2); i->EStack.pop(); } //closes files automatically void FilesystemModule::DeleteFileFunction::execute(SLIInterpreter *i) const //string -> boolean { StringDatum *sd=dynamic_cast<StringDatum *>(i->OStack.top().datum()); assert(sd !=NULL); int s=unlink(sd->c_str()); i->OStack.pop(); if (!s) {i->OStack.push(i->baselookup(i->true_name));} else {i->OStack.push(i->baselookup(i->false_name));}; i->EStack.pop(); } void FilesystemModule::MakeDirectoryFunction::execute(SLIInterpreter *i) const //string -> Boolean { StringDatum *sd=dynamic_cast<StringDatum *>(i->OStack.top().datum()); assert(sd !=NULL); int s= mkdir(sd->c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP); i->OStack.pop(); if (!s) {i->OStack.push(i->baselookup(i->true_name));} else {i->OStack.push(i->baselookup(i->false_name));}; i->EStack.pop(); } void FilesystemModule::RemoveDirectoryFunction::execute(SLIInterpreter *i) const //string -> Boolean { StringDatum *sd=dynamic_cast<StringDatum *>(i->OStack.top().datum()); assert(sd !=NULL); int s= rmdir(sd->c_str()); i->OStack.pop(); if (!s) {i->OStack.push(i->baselookup(i->true_name));} else {i->OStack.push(i->baselookup(i->false_name));}; i->EStack.pop(); } /* BeginDocumentation Name: tmpnam - Generate a string that is a valid non-existing file-name. Synopsis: tpmnam -> filename Description: This command is a thin wrapper around the POSIX.1 tmpnam() kernel function. The tmpnam function generates a string that is a valid filename and that is not the name of an existing file. The tmpnam function generates a different name each time it is called, (up to a number of times that is defined by the compiler macro TMP_MAX). Author: R. Kupper References: Donald Lewin, "The POSIX Programmer's Guide" */ void FilesystemModule::TmpNamFunction::execute(SLIInterpreter *i) const { static unsigned int seed=std::time(0); int rng= rand_r(&seed); char *env=getenv("TMPDIR"); std::string tmpdir("/tmp"); if(env) tmpdir=std::string(env); std::string tempfile; do { tempfile=tmpdir+String::compose("/nest-tmp-%1",rng); rng=rand_r(&seed); // draw new number with seed as state } while(std::ifstream(tempfile.c_str())); Token filename_t(new StringDatum(tempfile)); i->OStack.push_move(filename_t); i->EStack.pop(); } /* BeginDocumentation Name: CompareFiles - Compare two files for equality. Synopsis: filenameA filenameB CompareFiles -> bool Description: This command compares the two files named and returns true if they have identical content. Files are read in binary mode. FileOpenError is raised if one of the files cannot be opened. Author: Hans E Plesser */ void FilesystemModule::CompareFilesFunction::execute(SLIInterpreter *i) const { i->assert_stack_load(2); StringDatum const * const flA = dynamic_cast<StringDatum *>(i->OStack.pick(1).datum()); StringDatum const * const flB = dynamic_cast<StringDatum *>(i->OStack.pick(0).datum()); assert(flA); assert(flB); std::ifstream as(flA->c_str(), std::ifstream::in | std::ifstream::binary); std::ifstream bs(flB->c_str(), std::ifstream::in | std::ifstream::binary); if ( ! ( as.good() && bs.good() ) ) { as.close(); bs.close(); throw IOError(); } bool equal = true; while ( equal && as.good() && bs.good() ) { const int ac = as.get(); const int bc = bs.get(); if ( ! ( as.fail() || bs.fail() ) ) equal = ac == bc; } if ( as.fail() != bs.fail() ) equal = false; // different lengths as.close(); bs.close(); i->OStack.pop(2); if ( equal ) i->OStack.push(i->baselookup(i->true_name)); else i->OStack.push(i->baselookup(i->false_name)); i->EStack.pop(); }