<commit_before>#include "io_utar.h"
#include "logger.h"
#include <fstream>
#include <cmath>
#include <cstdint>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/algorithm/string.hpp>

namespace ncv
{
        // http://techoverflow.net/blog/2013/03/29/reading-tar-files-in-c/

        namespace
        {
                using std::int64_t;
                using std::uint64_t;

                ///
                /// \brief convert an ascii digit to the corresponding number (assuming it is an ASCII digit)
                ///
                uint64_t ascii_to_number(unsigned char num)
                {
                        return ((num) - 48);
                }

                ///
                /// \brief decode a TAR octal number. ignores everything after the first NUL or space character.
                ///
                uint64_t decode_tar_octal(const char* data, size_t size = 12)
                {
                        const unsigned char* currentPtr = (const unsigned char*)data + size;

                        const unsigned char* checkPtr = currentPtr;
                        for (; checkPtr >= (const unsigned char*) data; checkPtr --)
                        {
                                if ((*checkPtr) == 0 || (*checkPtr) == ' ')
                                {
                                        currentPtr = checkPtr - 1;
                                }
                        }

                        uint64_t sum = 0;
                        uint64_t currentMultiplier = 1;
                        for (; currentPtr >= (const unsigned char*)data; currentPtr --)
                        {
                                sum += ascii_to_number(*currentPtr) * currentMultiplier;
                                currentMultiplier *= 8;
                        }

                        return sum;
                }

                struct TARFileHeader
                {
                        char filename[100];
                        char mode[8];
                        char uid[8];
                        char gid[8];
                        char fileSize[12];
                        char lastModification[12];
                        char checksum[8];
                        char typeFlag;
                        char linkedFileName[100];
                        char ustarIndicator[6];
                        char ustarVersion[2];
                        char ownerUserName[32];
                        char ownerGroupName[32];
                        char deviceMajorNumber[8];
                        char deviceMinorNumber[8];
                        char filenamePrefix[155];
                        char padding[12];

                        size_t filesize() const
                        {
                                return decode_tar_octal(fileSize);
                        }
                };
        }

        namespace
        {
                bool io_untar(
                        boost::iostreams::filtering_istream& in, const io::untar_callback_t& callback,
                        const std::string& info_header, const std::string& error_header)
                {
                        char zeroBlock[512];
                        memset(zeroBlock, 0, 512);

                        bool nextEntryHasLongName = false;
                        while (in)
                        {
                                TARFileHeader header;
                                in.read((char*)&header, 512);
                                if (memcmp(&header, zeroBlock, 512) == 0)
                                {
                                        log_info() << info_header << "found TAR end.";
                                        break;
                                }

                                // compose the filename
                                std::string filename(header.filename, std::min((size_t)100, strlen(header.filename)));
                                const size_t prefixLength = strlen(header.filenamePrefix);
                                if (prefixLength > 0)
                                {
                                        filename =
                                        std::string(header.filenamePrefix, std::min((size_t)155, prefixLength)) +
                                        "/" +
                                        filename;
                                }

                                if (header.typeFlag == '0' || header.typeFlag == 0)
                                {
                                        // handle GNU TAR long filenames
                                        if (nextEntryHasLongName)
                                        {
                                                filename = std::string(header.filename);
                                                in.read((char*) &header, 512);
                                                nextEntryHasLongName = false;
                                        }

                                        const size_t size = header.filesize();
                                        log_info() << info_header << "found file <" << filename << "> (" << size << " bytes).";

                                        //Read the file into memory
                                        //  This won't work for very large files -- use streaming methods there!
                                        {
                                                std::vector<unsigned char> filedata(size);

                                                char* const pdata = reinterpret_cast<char*>(filedata.data());
                                                in.read(pdata, size);

                                                // decode archive type
                                                if (    boost::algorithm::iends_with(filename, ".tar.gz") ||
                                                        boost::algorithm::iends_with(filename, ".tgz"))
                                                {
                                                        boost::iostreams::filtering_istream in_;
                                                        in_.push(boost::iostreams::gzip_decompressor());
                                                        in_.push(boost::iostreams::basic_array_source<char>(pdata, filedata.size()));
                                                        if (!io_untar(in_, callback, info_header, error_header))
                                                        {
                                                                return false;
                                                        }
                                                }
                                                else if (boost::algorithm::iends_with(filename, ".tar.bz2"))
                                                {
                                                        boost::iostreams::filtering_istream in_;
                                                        in_.push(boost::iostreams::bzip2_decompressor());
                                                        in_.push(boost::iostreams::basic_array_source<char>(pdata, filedata.size()));
                                                        if (!io_untar(in_, callback, info_header, error_header))
                                                        {
                                                                return false;
                                                        }
                                                }
                                                else if (boost::algorithm::iends_with(filename, ".tar"))
                                                {
                                                        // no decompression filter needed
                                                        boost::iostreams::filtering_istream in_;
                                                        in_.push(boost::iostreams::basic_array_source<char>(pdata, filedata.size()));
                                                        if (!io_untar(in_, callback, info_header, error_header))
                                                        {
                                                                return false;
                                                        }
                                                }
                                                else
                                                {
                                                        callback(filename, filedata);
                                                }
                                        }

                                        // ignore padding
                                        const size_t paddingBytes = (512 - (size % 512)) % 512;
                                        in.ignore(paddingBytes);
                                }

                                else if (header.typeFlag == '5')
                                {
                                        log_info() << info_header << "found directory <" << filename << ">.";
                                }

                                else if(header.typeFlag == 'L')
                                {
                                        nextEntryHasLongName = true;
                                }

                                else
                                {
                                        log_info() << info_header << "found unhandled TAR entry type <" << header.typeFlag << ">.";
                                }
                        }

                        // OK
                        return true;
                }
        }

        bool io::untar(
                const std::string& path, const untar_callback_t& callback,
                const std::string& info_header, const std::string& error_header)
        {
                std::ifstream fin(path.c_str(), std::ios_base::in | std::ios_base::binary);
                if (!fin.is_open())
                {
                        log_error() << error_header << "failed to open file <" << path << ">!";
                        return false;
                }

                boost::iostreams::filtering_istream in;

                // decode archive type
                if (    boost::algorithm::iends_with(path, ".tar.gz") ||
                        boost::algorithm::iends_with(path, ".tgz"))
                {
                        in.push(boost::iostreams::gzip_decompressor());
                }
                else if (boost::algorithm::iends_with(path, ".tar.bz2"))
                {
                        in.push(boost::iostreams::bzip2_decompressor());
                }
                else if (boost::algorithm::iends_with(path, ".tar"))
                {
                        // no decompression filter needed
                }
                else if (boost::algorithm::iends_with(path, ".gz"))
                {
                        in.push(boost::iostreams::gzip_decompressor());
                        in.push(fin);

                        std::vector<unsigned char> filedata;

                        const size_t chunk = 4096;
                        char data[chunk];

                        std::streamsize read_size;
                        while ((read_size = boost::iostreams::read(in, data, chunk)) > 0)
                        {
                                filedata.insert(filedata.end(),
                                                reinterpret_cast<const unsigned char*>(data),
                                                reinterpret_cast<const unsigned char*>(data) + read_size);
                        }

                        callback(path, filedata);
                        return true;
                }
                else
                {
                        log_error() << error_header << "unknown file suffix <" << path << ">!";
                        return false;
                }

                in.push(fin);

                return io_untar(in, callback, info_header, error_header);
        }
}
<commit_msg>also handle tbz extensions<commit_after>#include "io_utar.h"
#include "logger.h"
#include <fstream>
#include <cmath>
#include <cstdint>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/algorithm/string.hpp>

namespace ncv
{
        // http://techoverflow.net/blog/2013/03/29/reading-tar-files-in-c/

        namespace
        {
                using std::int64_t;
                using std::uint64_t;

                ///
                /// \brief convert an ascii digit to the corresponding number (assuming it is an ASCII digit)
                ///
                uint64_t ascii_to_number(unsigned char num)
                {
                        return ((num) - 48);
                }

                ///
                /// \brief decode a TAR octal number. ignores everything after the first NUL or space character.
                ///
                uint64_t decode_tar_octal(const char* data, size_t size = 12)
                {
                        const unsigned char* currentPtr = (const unsigned char*)data + size;

                        const unsigned char* checkPtr = currentPtr;
                        for (; checkPtr >= (const unsigned char*) data; checkPtr --)
                        {
                                if ((*checkPtr) == 0 || (*checkPtr) == ' ')
                                {
                                        currentPtr = checkPtr - 1;
                                }
                        }

                        uint64_t sum = 0;
                        uint64_t currentMultiplier = 1;
                        for (; currentPtr >= (const unsigned char*)data; currentPtr --)
                        {
                                sum += ascii_to_number(*currentPtr) * currentMultiplier;
                                currentMultiplier *= 8;
                        }

                        return sum;
                }

                struct TARFileHeader
                {
                        char filename[100];
                        char mode[8];
                        char uid[8];
                        char gid[8];
                        char fileSize[12];
                        char lastModification[12];
                        char checksum[8];
                        char typeFlag;
                        char linkedFileName[100];
                        char ustarIndicator[6];
                        char ustarVersion[2];
                        char ownerUserName[32];
                        char ownerGroupName[32];
                        char deviceMajorNumber[8];
                        char deviceMinorNumber[8];
                        char filenamePrefix[155];
                        char padding[12];

                        size_t filesize() const
                        {
                                return decode_tar_octal(fileSize);
                        }
                };
        }

        namespace
        {
                bool io_untar(
                        boost::iostreams::filtering_istream& in, const io::untar_callback_t& callback,
                        const std::string& info_header, const std::string& error_header)
                {
                        char zeroBlock[512];
                        memset(zeroBlock, 0, 512);

                        bool nextEntryHasLongName = false;
                        while (in)
                        {
                                TARFileHeader header;
                                in.read((char*)&header, 512);
                                if (memcmp(&header, zeroBlock, 512) == 0)
                                {
                                        log_info() << info_header << "found TAR end.";
                                        break;
                                }

                                // compose the filename
                                std::string filename(header.filename, std::min((size_t)100, strlen(header.filename)));
                                const size_t prefixLength = strlen(header.filenamePrefix);
                                if (prefixLength > 0)
                                {
                                        filename =
                                        std::string(header.filenamePrefix, std::min((size_t)155, prefixLength)) +
                                        "/" +
                                        filename;
                                }

                                if (header.typeFlag == '0' || header.typeFlag == 0)
                                {
                                        // handle GNU TAR long filenames
                                        if (nextEntryHasLongName)
                                        {
                                                filename = std::string(header.filename);
                                                in.read((char*) &header, 512);
                                                nextEntryHasLongName = false;
                                        }

                                        const size_t size = header.filesize();
                                        log_info() << info_header << "found file <" << filename << "> (" << size << " bytes).";

                                        //Read the file into memory
                                        //  This won't work for very large files -- use streaming methods there!
                                        {
                                                std::vector<unsigned char> filedata(size);

                                                char* const pdata = reinterpret_cast<char*>(filedata.data());
                                                in.read(pdata, size);

                                                // decode archive type
                                                if (    boost::algorithm::iends_with(filename, ".tar.gz") ||
                                                        boost::algorithm::iends_with(filename, ".tgz"))
                                                {
                                                        boost::iostreams::filtering_istream in_;
                                                        in_.push(boost::iostreams::gzip_decompressor());
                                                        in_.push(boost::iostreams::basic_array_source<char>(pdata, filedata.size()));
                                                        if (!io_untar(in_, callback, info_header, error_header))
                                                        {
                                                                return false;
                                                        }
                                                }
                                                else if (boost::algorithm::iends_with(filename, ".tar.bz2") ||
                                                         boost::algorithm::iends_with(filename, ".tbz"))
                                                {
                                                        boost::iostreams::filtering_istream in_;
                                                        in_.push(boost::iostreams::bzip2_decompressor());
                                                        in_.push(boost::iostreams::basic_array_source<char>(pdata, filedata.size()));
                                                        if (!io_untar(in_, callback, info_header, error_header))
                                                        {
                                                                return false;
                                                        }
                                                }
                                                else if (boost::algorithm::iends_with(filename, ".tar"))
                                                {
                                                        // no decompression filter needed
                                                        boost::iostreams::filtering_istream in_;
                                                        in_.push(boost::iostreams::basic_array_source<char>(pdata, filedata.size()));
                                                        if (!io_untar(in_, callback, info_header, error_header))
                                                        {
                                                                return false;
                                                        }
                                                }
                                                else
                                                {
                                                        callback(filename, filedata);
                                                }
                                        }

                                        // ignore padding
                                        const size_t paddingBytes = (512 - (size % 512)) % 512;
                                        in.ignore(paddingBytes);
                                }

                                else if (header.typeFlag == '5')
                                {
                                        log_info() << info_header << "found directory <" << filename << ">.";
                                }

                                else if(header.typeFlag == 'L')
                                {
                                        nextEntryHasLongName = true;
                                }

                                else
                                {
                                        log_info() << info_header << "found unhandled TAR entry type <" << header.typeFlag << ">.";
                                }
                        }

                        // OK
                        return true;
                }
        }

        bool io::untar(
                const std::string& path, const untar_callback_t& callback,
                const std::string& info_header, const std::string& error_header)
        {
                std::ifstream fin(path.c_str(), std::ios_base::in | std::ios_base::binary);
                if (!fin.is_open())
                {
                        log_error() << error_header << "failed to open file <" << path << ">!";
                        return false;
                }

                boost::iostreams::filtering_istream in;

                // decode archive type
                if (    boost::algorithm::iends_with(path, ".tar.gz") ||
                        boost::algorithm::iends_with(path, ".tgz"))
                {
                        in.push(boost::iostreams::gzip_decompressor());
                }
                else if (boost::algorithm::iends_with(path, ".tar.bz2") ||
                         boost::algorithm::iends_with(path, ".tbz"))
                {
                        in.push(boost::iostreams::bzip2_decompressor());
                }
                else if (boost::algorithm::iends_with(path, ".tar"))
                {
                        // no decompression filter needed
                }
                else if (boost::algorithm::iends_with(path, ".gz"))
                {
                        in.push(boost::iostreams::gzip_decompressor());
                        in.push(fin);

                        std::vector<unsigned char> filedata;

                        const size_t chunk = 4096;
                        char data[chunk];

                        std::streamsize read_size;
                        while ((read_size = boost::iostreams::read(in, data, chunk)) > 0)
                        {
                                filedata.insert(filedata.end(),
                                                reinterpret_cast<const unsigned char*>(data),
                                                reinterpret_cast<const unsigned char*>(data) + read_size);
                        }

                        callback(path, filedata);
                        return true;
                }
                else
                {
                        log_error() << error_header << "unknown file suffix <" << path << ">!";
                        return false;
                }

                in.push(fin);

                return io_untar(in, callback, info_header, error_header);
        }
}
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <v8.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <malloc/malloc.h>
#endif
#include <zlib.h>

// zlib magic something
#define WBITS 16+MAX_WBITS
#define WBITS_RAW -15

#define CHUNK 1024*100
#define HEADER_SIZE 10
#define FOOTER_SIZE 8
#define SPACER_SIZE 6

using namespace v8;
using namespace node;

static Persistent<String> SYM_BODY;
static Persistent<String> SYM_LEFT;
static Persistent<String> SYM_RIGHT;
static Persistent<String> SYM_LAST;
static Persistent<String> SYM_TYPE;
static Persistent<String> SYM_OFFSETS;
static Persistent<String> SYM_LENGTH;
static Persistent<String> SYM_RAW_LENGTH;
static Persistent<String> SYM_CRC;
static Persistent<String> SYM_META;
static Persistent<String> SYM_BUFFERS;
static Persistent<String> SYM_HEADER;
static Persistent<String> SYM_ODD;

static Handle<Value> ThrowNodeError (const char* what = NULL) {
	return ThrowException(Exception::Error(String::New(what)));
}

static int meta_uncompress (char *dataIn, size_t bytesIn, int *dataType) {
	z_stream strmUncompress;

	strmUncompress.zalloc = Z_NULL;
	strmUncompress.zfree = Z_NULL;
	strmUncompress.opaque = Z_NULL;
	strmUncompress.avail_in = 0;
	strmUncompress.next_in = Z_NULL;

    //this can be further improved!
    //we should only do inflate if the the stream is compressed
    //and header skip should be done earlier
	if (inflateInit2(&strmUncompress, WBITS_RAW) != Z_OK) {
		return -1;
	}

    unsigned char *tmp = (unsigned char *) malloc(CHUNK);

    //skipping header
	strmUncompress.next_in = ((unsigned char *) dataIn) + HEADER_SIZE;
	strmUncompress.avail_in = bytesIn - HEADER_SIZE;

    //checking if stream is compressed, first byte - binary:
    //xxxxx001 - stream is NOT compressed
    //xxxxx011 - stream is compressed (using fixed huffman codes)
    //xxxxx111 - stream is compressed (using dynamic huffman codes)
    if ((*strmUncompress.next_in & 3) == 3 || (*strmUncompress.next_in & 5) == 5) {
        for (;;) {
            strmUncompress.avail_out = CHUNK;
            strmUncompress.next_out = tmp;

            int ret = inflate(&strmUncompress, Z_BLOCK);

            assert(ret != Z_STREAM_ERROR);

            switch (ret) {
                case Z_NEED_DICT:
                    ret = Z_DATA_ERROR;     /* and fall through */
                case Z_DATA_ERROR:
                case Z_MEM_ERROR:
                    inflateEnd(&strmUncompress);
                    if (tmp != NULL) {
                        free(tmp);
                    }

                    return -2;
            }

            if (strmUncompress.data_type & 128) {
                break;
            }
        }
        *dataType = strmUncompress.data_type;
    } else {
        *dataType = 128;
    }

	inflateEnd(&strmUncompress);

    return 0;

}

static int compress (char *dataIn, size_t bytesIn, int compressionLevel, char **dataOut, size_t *bytesOut) {
	size_t bytesDeflated = 0;

    if (compressionLevel < 0 || compressionLevel > 9) {
        compressionLevel = Z_DEFAULT_COMPRESSION;
    }

    z_stream strmCompress;
	strmCompress.zalloc = Z_NULL;
	strmCompress.zfree = Z_NULL;
	strmCompress.opaque = Z_NULL;

	if (deflateInit2(&strmCompress, compressionLevel, Z_DEFLATED, WBITS, 8L, Z_DEFAULT_STRATEGY) != Z_OK) {
		return -1;
	}

	bytesDeflated = deflateBound(&strmCompress, bytesIn);

	if (bytesDeflated < 1024) {
		bytesDeflated = 1024;
	}

	*dataOut = (char *) malloc(bytesDeflated);

	strmCompress.next_in = (Bytef *) dataIn;
	strmCompress.avail_in = bytesIn;
	strmCompress.next_out = (Bytef *) *dataOut;
	strmCompress.avail_out = bytesDeflated;

	if (deflate(&strmCompress, Z_NO_FLUSH) < Z_OK) {
		deflateReset(&strmCompress);
		return -2;
	}

	deflate(&strmCompress, Z_FINISH);

	*bytesOut = strmCompress.total_out;

	deflateReset(&strmCompress);

    return 0;
}

static Handle<Value> onet_compress (const Arguments &args) {
	HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

	if (args.Length() < 1) {
		return Undefined();
	}

	if (!Buffer::HasInstance(args[0])) {
		ThrowNodeError("First argument must be a Buffer");
		return Undefined();
	}

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int dataType = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        char msg[30];
        sprintf(msg, "Unable to compress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    status = meta_uncompress(dataOut, bytesOut, &dataType);

    if (status != 0) {
        char msg[30];
        sprintf(msg, "Unable to uncompress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    unsigned int dataLength = bytesOut - HEADER_SIZE - FOOTER_SIZE - 1;

    Local<Object> result = Object::New();

    Buffer *body = Buffer::New((char *) dataOut, bytesOut);
    result->Set(SYM_BODY, body->handle_);

    Local<Object> dataOffsets = Object::New();
    dataOffsets->Set(SYM_LEFT, Integer::New(HEADER_SIZE));
    dataOffsets->Set(SYM_RIGHT, Integer::New(HEADER_SIZE + dataLength));
    dataOffsets->Set(SYM_LAST, Integer::New(HEADER_SIZE + dataLength));

    Buffer *crc = Buffer::New((char *) dataOut + (bytesOut - FOOTER_SIZE), 4);

    Local<Object> meta = Object::New();
    meta->Set(SYM_TYPE, Integer::New(dataType));
    meta->Set(SYM_OFFSETS, dataOffsets);
    meta->Set(SYM_LENGTH, Integer::New(bytesIn));
    meta->Set(SYM_RAW_LENGTH, Integer::New(bytesOut - HEADER_SIZE - FOOTER_SIZE));
    meta->Set(SYM_CRC, crc->handle_);

    result->Set(SYM_META, meta);

    free(dataOut);

	return scope.Close(result);
}

static Handle<Value> compress (const Arguments& args) {
	HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

	if (args.Length() < 1) {
		return Undefined();
	}

	if (!Buffer::HasInstance(args[0])) {
		ThrowNodeError("First argument must be a Buffer");
		return Undefined();
	}

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        ThrowNodeError("Unable to compress");
        return Undefined();
    }

    Buffer *buff = Buffer::New(dataOut, bytesOut);

    return scope.Close(buff->handle_);
}

static Handle<Value> estimate (const Arguments &args) {
    HandleScope scope;

    Local<Array> arr = Local<Array>::Cast(args[0]);
    int i = 0;
    int l = arr->Length();
    int sum = HEADER_SIZE + FOOTER_SIZE + ((l - 1) * SPACER_SIZE);

    for(; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        sum += meta->Get(SYM_RAW_LENGTH)->Uint32Value();
    }

    return scope.Close(Integer::New(sum));
}

static unsigned long reverseBytes (unsigned char *buf) {
    unsigned long v;

    v = *buf;
    v += (unsigned long) *(buf + 1) << 8;
    v += (unsigned long) *(buf + 2) << 16;
    v += (unsigned long) *(buf + 3) << 24;

    return v;
}

static Handle<Value> getCrc (const Arguments &args) {
    HandleScope scope;

    unsigned long crc = crc32(0L, Z_NULL, 0);
    unsigned long tot = 0;

    Local<Array> arr = Local<Array>::Cast(args[0]);

    int l = arr->Length();
    int i = 0;

    for (; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        Local<Object> bufCrc = meta->Get(SYM_CRC)->ToObject();

        unsigned long tmpCrc = reverseBytes((unsigned char *) Buffer::Data(bufCrc));
        unsigned long tmpLen = meta->Get(SYM_LENGTH)->Uint32Value();

        crc = crc32_combine(crc, tmpCrc, tmpLen);
        tot += tmpLen;
    }

    Local<Object> data = Object::New();
    data->Set(SYM_CRC, Buffer::New((char *) &crc, 4)->handle_);
    data->Set(SYM_LENGTH, Buffer::New((char *) &tot, 4)->handle_);

    return scope.Close(data);
}

static Handle<Value> uncompress (const Arguments &args) {
    HandleScope scope;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    z_stream strmUncompress;

    strmUncompress.zalloc=Z_NULL;
    strmUncompress.zfree=Z_NULL;
    strmUncompress.opaque=Z_NULL;
    strmUncompress.avail_in = 0;
    strmUncompress.next_in = Z_NULL;

    int rci = inflateInit2(&strmUncompress, WBITS);

    if (rci != Z_OK) {
        ThrowNodeError("zlib initialization error.");
        return Undefined();
    }

    Local<Object> bufferIn=args[0]->ToObject();

    strmUncompress.next_in = (Bytef*) Buffer::Data(bufferIn);
    strmUncompress.avail_in = Buffer::Length(bufferIn);

    Bytef  *bufferOut = NULL;
    uint32_t malloc_size=0;
    uint32_t currentPosition=0;

    int ret;

    do {
        Bytef *tmp = (Bytef*)malloc(CHUNK);
        strmUncompress.avail_out = CHUNK;
        strmUncompress.next_out = tmp;

        ret = inflate(&strmUncompress, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);
        switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strmUncompress);
                if (bufferOut!=NULL) {
                    free(bufferOut);
                }
                if (tmp!=NULL) {
                    free(tmp);
                }
                return Undefined();
        }

        uint32_t have = CHUNK - strmUncompress.avail_out;
        if (have>0) {
            bufferOut = (Bytef *) realloc(bufferOut, malloc_size+have);
            malloc_size=malloc_size+have;
        }

        memcpy(bufferOut+currentPosition, tmp, have);
        currentPosition+=have;
        free(tmp);
    } while (strmUncompress.avail_out == 0 && ret != Z_STREAM_END);

    inflateEnd(&strmUncompress);

    if (ret != Z_STREAM_END) {
        if (bufferOut!=NULL) {
            free(bufferOut);
        }
        return Undefined();
    }

    Buffer *BufferOut=Buffer::New((char *)bufferOut, malloc_size);
    free(bufferOut);

    return scope.Close(BufferOut->handle_);
}

extern "C" void init (Handle<Object> target) {
    SYM_BODY = NODE_PSYMBOL("body");
    SYM_LEFT = NODE_PSYMBOL("left");
    SYM_RIGHT = NODE_PSYMBOL("right");
    SYM_LAST = NODE_PSYMBOL("last");
    SYM_TYPE = NODE_PSYMBOL("type");
    SYM_OFFSETS = NODE_PSYMBOL("offsets");
    SYM_LENGTH = NODE_PSYMBOL("length");
    SYM_RAW_LENGTH = NODE_PSYMBOL("rawLength");
    SYM_CRC = NODE_PSYMBOL("crc");
    SYM_META = NODE_PSYMBOL("meta");
    SYM_BUFFERS = NODE_PSYMBOL("buffers");
    SYM_HEADER = NODE_PSYMBOL("header");
    SYM_ODD = NODE_PSYMBOL("odd");

    char header[] = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
    Buffer *headerBuffer = Buffer::New(header, 10);

    char odd[] = {0x00, 0x00, 0xff, 0xff};
    Buffer *oddBuffer = Buffer::New(odd, 4);

    Handle<Object> buffers = Object::New();
    buffers->Set(SYM_HEADER, headerBuffer->handle_);
    buffers->Set(SYM_ODD, oddBuffer->handle_);

    target->Set(SYM_BUFFERS, buffers);

	NODE_SET_METHOD(target, "compress", compress);
	NODE_SET_METHOD(target, "uncompress", uncompress);
    NODE_SET_METHOD(target, "metaCompress", onet_compress);
	NODE_SET_METHOD(target, "getCrc", getCrc);
	NODE_SET_METHOD(target, "estimate", estimate);

}

NODE_MODULE(compress_buffer_bindings, init);

<commit_msg>retab<commit_after>#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <v8.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <malloc/malloc.h>
#endif
#include <zlib.h>

// zlib magic something
#define WBITS 16+MAX_WBITS
#define WBITS_RAW -15

#define CHUNK 1024*100
#define HEADER_SIZE 10
#define FOOTER_SIZE 8
#define SPACER_SIZE 6

using namespace v8;
using namespace node;

static Persistent<String> SYM_BODY;
static Persistent<String> SYM_LEFT;
static Persistent<String> SYM_RIGHT;
static Persistent<String> SYM_LAST;
static Persistent<String> SYM_TYPE;
static Persistent<String> SYM_OFFSETS;
static Persistent<String> SYM_LENGTH;
static Persistent<String> SYM_RAW_LENGTH;
static Persistent<String> SYM_CRC;
static Persistent<String> SYM_META;
static Persistent<String> SYM_BUFFERS;
static Persistent<String> SYM_HEADER;
static Persistent<String> SYM_ODD;

static Handle<Value> ThrowNodeError (const char* what = NULL) {
    return ThrowException(Exception::Error(String::New(what)));
}

static int meta_uncompress (char *dataIn, size_t bytesIn, int *dataType) {
    z_stream strmUncompress;

    strmUncompress.zalloc = Z_NULL;
    strmUncompress.zfree = Z_NULL;
    strmUncompress.opaque = Z_NULL;
    strmUncompress.avail_in = 0;
    strmUncompress.next_in = Z_NULL;

    //this can be further improved!
    //we should only do inflate if the the stream is compressed
    //and header skip should be done earlier
    if (inflateInit2(&strmUncompress, WBITS_RAW) != Z_OK) {
        return -1;
    }

    unsigned char *tmp = (unsigned char *) malloc(CHUNK);

    //skipping header
    strmUncompress.next_in = ((unsigned char *) dataIn) + HEADER_SIZE;
    strmUncompress.avail_in = bytesIn - HEADER_SIZE;

    //checking if stream is compressed, first byte - binary:
    //xxxxx001 - stream is NOT compressed
    //xxxxx011 - stream is compressed (using fixed huffman codes)
    //xxxxx111 - stream is compressed (using dynamic huffman codes)
    if ((*strmUncompress.next_in & 3) == 3 || (*strmUncompress.next_in & 5) == 5) {
        for (;;) {
            strmUncompress.avail_out = CHUNK;
            strmUncompress.next_out = tmp;

            int ret = inflate(&strmUncompress, Z_BLOCK);

            assert(ret != Z_STREAM_ERROR);

            switch (ret) {
                case Z_NEED_DICT:
                    ret = Z_DATA_ERROR;     /* and fall through */
                case Z_DATA_ERROR:
                case Z_MEM_ERROR:
                    inflateEnd(&strmUncompress);
                    if (tmp != NULL) {
                        free(tmp);
                    }

                    return -2;
            }

            if (strmUncompress.data_type & 128) {
                break;
            }
        }
        *dataType = strmUncompress.data_type;
    } else {
        *dataType = 128;
    }

    inflateEnd(&strmUncompress);

    return 0;

}

static int compress (char *dataIn, size_t bytesIn, int compressionLevel, char **dataOut, size_t *bytesOut) {
    size_t bytesDeflated = 0;

    if (compressionLevel < 0 || compressionLevel > 9) {
        compressionLevel = Z_DEFAULT_COMPRESSION;
    }

    z_stream strmCompress;
    strmCompress.zalloc = Z_NULL;
    strmCompress.zfree = Z_NULL;
    strmCompress.opaque = Z_NULL;

    if (deflateInit2(&strmCompress, compressionLevel, Z_DEFLATED, WBITS, 8L, Z_DEFAULT_STRATEGY) != Z_OK) {
        return -1;
    }

    bytesDeflated = deflateBound(&strmCompress, bytesIn);

    if (bytesDeflated < 1024) {
        bytesDeflated = 1024;
    }

    *dataOut = (char *) malloc(bytesDeflated);

    strmCompress.next_in = (Bytef *) dataIn;
    strmCompress.avail_in = bytesIn;
    strmCompress.next_out = (Bytef *) *dataOut;
    strmCompress.avail_out = bytesDeflated;

    if (deflate(&strmCompress, Z_NO_FLUSH) < Z_OK) {
        deflateReset(&strmCompress);
        return -2;
    }

    deflate(&strmCompress, Z_FINISH);

    *bytesOut = strmCompress.total_out;

    deflateReset(&strmCompress);

    return 0;
}

static Handle<Value> onet_compress (const Arguments &args) {
    HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int dataType = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        char msg[30];
        sprintf(msg, "Unable to compress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    status = meta_uncompress(dataOut, bytesOut, &dataType);

    if (status != 0) {
        char msg[30];
        sprintf(msg, "Unable to uncompress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    unsigned int dataLength = bytesOut - HEADER_SIZE - FOOTER_SIZE - 1;

    Local<Object> result = Object::New();

    Buffer *body = Buffer::New((char *) dataOut, bytesOut);
    result->Set(SYM_BODY, body->handle_);

    Local<Object> dataOffsets = Object::New();
    dataOffsets->Set(SYM_LEFT, Integer::New(HEADER_SIZE));
    dataOffsets->Set(SYM_RIGHT, Integer::New(HEADER_SIZE + dataLength));
    dataOffsets->Set(SYM_LAST, Integer::New(HEADER_SIZE + dataLength));

    Buffer *crc = Buffer::New((char *) dataOut + (bytesOut - FOOTER_SIZE), 4);

    Local<Object> meta = Object::New();
    meta->Set(SYM_TYPE, Integer::New(dataType));
    meta->Set(SYM_OFFSETS, dataOffsets);
    meta->Set(SYM_LENGTH, Integer::New(bytesIn));
    meta->Set(SYM_RAW_LENGTH, Integer::New(bytesOut - HEADER_SIZE - FOOTER_SIZE));
    meta->Set(SYM_CRC, crc->handle_);

    result->Set(SYM_META, meta);

    free(dataOut);

    return scope.Close(result);
}

static Handle<Value> compress (const Arguments& args) {
    HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        ThrowNodeError("Unable to compress");
        return Undefined();
    }

    Buffer *buff = Buffer::New(dataOut, bytesOut);

    return scope.Close(buff->handle_);
}

static Handle<Value> estimate (const Arguments &args) {
    HandleScope scope;

    Local<Array> arr = Local<Array>::Cast(args[0]);
    int i = 0;
    int l = arr->Length();
    int sum = HEADER_SIZE + FOOTER_SIZE + ((l - 1) * SPACER_SIZE);

    for(; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        sum += meta->Get(SYM_RAW_LENGTH)->Uint32Value();
    }

    return scope.Close(Integer::New(sum));
}

static unsigned long reverseBytes (unsigned char *buf) {
    unsigned long v;

    v = *buf;
    v += (unsigned long) *(buf + 1) << 8;
    v += (unsigned long) *(buf + 2) << 16;
    v += (unsigned long) *(buf + 3) << 24;

    return v;
}

static Handle<Value> getCrc (const Arguments &args) {
    HandleScope scope;

    unsigned long crc = crc32(0L, Z_NULL, 0);
    unsigned long tot = 0;

    Local<Array> arr = Local<Array>::Cast(args[0]);

    int l = arr->Length();
    int i = 0;

    for (; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        Local<Object> bufCrc = meta->Get(SYM_CRC)->ToObject();

        unsigned long tmpCrc = reverseBytes((unsigned char *) Buffer::Data(bufCrc));
        unsigned long tmpLen = meta->Get(SYM_LENGTH)->Uint32Value();

        crc = crc32_combine(crc, tmpCrc, tmpLen);
        tot += tmpLen;
    }

    Local<Object> data = Object::New();
    data->Set(SYM_CRC, Buffer::New((char *) &crc, 4)->handle_);
    data->Set(SYM_LENGTH, Buffer::New((char *) &tot, 4)->handle_);

    return scope.Close(data);
}

static Handle<Value> uncompress (const Arguments &args) {
    HandleScope scope;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    z_stream strmUncompress;

    strmUncompress.zalloc=Z_NULL;
    strmUncompress.zfree=Z_NULL;
    strmUncompress.opaque=Z_NULL;
    strmUncompress.avail_in = 0;
    strmUncompress.next_in = Z_NULL;

    int rci = inflateInit2(&strmUncompress, WBITS);

    if (rci != Z_OK) {
        ThrowNodeError("zlib initialization error.");
        return Undefined();
    }

    Local<Object> bufferIn=args[0]->ToObject();

    strmUncompress.next_in = (Bytef*) Buffer::Data(bufferIn);
    strmUncompress.avail_in = Buffer::Length(bufferIn);

    Bytef  *bufferOut = NULL;
    uint32_t malloc_size=0;
    uint32_t currentPosition=0;

    int ret;

    do {
        Bytef *tmp = (Bytef*)malloc(CHUNK);
        strmUncompress.avail_out = CHUNK;
        strmUncompress.next_out = tmp;

        ret = inflate(&strmUncompress, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);
        switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strmUncompress);
                if (bufferOut!=NULL) {
                    free(bufferOut);
                }
                if (tmp!=NULL) {
                    free(tmp);
                }
                return Undefined();
        }

        uint32_t have = CHUNK - strmUncompress.avail_out;
        if (have>0) {
            bufferOut = (Bytef *) realloc(bufferOut, malloc_size+have);
            malloc_size=malloc_size+have;
        }

        memcpy(bufferOut+currentPosition, tmp, have);
        currentPosition+=have;
        free(tmp);
    } while (strmUncompress.avail_out == 0 && ret != Z_STREAM_END);

    inflateEnd(&strmUncompress);

    if (ret != Z_STREAM_END) {
        if (bufferOut!=NULL) {
            free(bufferOut);
        }
        return Undefined();
    }

    Buffer *BufferOut=Buffer::New((char *)bufferOut, malloc_size);
    free(bufferOut);

    return scope.Close(BufferOut->handle_);
}

extern "C" void init (Handle<Object> target) {
    SYM_BODY = NODE_PSYMBOL("body");
    SYM_LEFT = NODE_PSYMBOL("left");
    SYM_RIGHT = NODE_PSYMBOL("right");
    SYM_LAST = NODE_PSYMBOL("last");
    SYM_TYPE = NODE_PSYMBOL("type");
    SYM_OFFSETS = NODE_PSYMBOL("offsets");
    SYM_LENGTH = NODE_PSYMBOL("length");
    SYM_RAW_LENGTH = NODE_PSYMBOL("rawLength");
    SYM_CRC = NODE_PSYMBOL("crc");
    SYM_META = NODE_PSYMBOL("meta");
    SYM_BUFFERS = NODE_PSYMBOL("buffers");
    SYM_HEADER = NODE_PSYMBOL("header");
    SYM_ODD = NODE_PSYMBOL("odd");

    char header[] = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
    Buffer *headerBuffer = Buffer::New(header, 10);

    char odd[] = {0x00, 0x00, 0xff, 0xff};
    Buffer *oddBuffer = Buffer::New(odd, 4);

    Handle<Object> buffers = Object::New();
    buffers->Set(SYM_HEADER, headerBuffer->handle_);
    buffers->Set(SYM_ODD, oddBuffer->handle_);

    target->Set(SYM_BUFFERS, buffers);

    NODE_SET_METHOD(target, "compress", compress);
    NODE_SET_METHOD(target, "uncompress", uncompress);
    NODE_SET_METHOD(target, "metaCompress", onet_compress);
    NODE_SET_METHOD(target, "getCrc", getCrc);
    NODE_SET_METHOD(target, "estimate", estimate);

}

NODE_MODULE(compress_buffer_bindings, init);

<|endoftext|>


<commit_before>#pragma once

#include <iostream>

#define PI 3.1415926535897932
#define TWOPI 2.0*PI
#define HPI 0.5*PI
#define RPI 1.0/PI
#define RTWOPI 1.0/TWOPI
#define FPI 4.0*PI
#define RFPI 1.0/(FPI)

namespace mocc {
    // Surface and direction indexing
    enum Surface {
        EAST  = 0,
        NORTH = 1,
        WEST  = 2,
        SOUTH = 3,
        TOP = 4,
        BOTTOM = 5,
        INVALID = 6,
    };

    enum class Direction {
        EAST  = 0,
        NORTH = 1,
        WEST  = 2,
        SOUTH = 3,
        TOP = 4,
        BOTTOM = 5,
        NE,
        NW,
        SW,
        SE,
        INVALID
    };

    extern const Surface AllSurfaces[6];

    enum class Normal {
        X_NORM = 0,
        Y_NORM,
        Z_NORM
    };

    extern const Normal AllNormals[3];

    // Boundary condition enumeration
    enum class Boundary {
        /**
         * Zero incoming flux
         */
        VACUUM,
        /**
         * Reflected incoming flux
         */
        REFLECT,
        /**
         * Incoming flux communicated between domain nodes
         */
        PARALLEL,
        /**
         * Self-explanatory
         */
        PERIODIC,
        INVALID
    };

    enum class TraceDir {
        FW,
        BW
    };

    std::ostream& operator<<(std::ostream& os, const Surface s );

    std::ostream& operator<<(std::ostream& os, const Boundary b );

    std::ostream& operator<<(std::ostream& os, const Normal n );

    Normal surface_to_normal( Surface s );

}
<commit_msg>Better comments<commit_after>#pragma once

#include <iostream>

#define PI 3.1415926535897932
#define TWOPI 2.0*PI
#define HPI 0.5*PI
#define RPI 1.0/PI
#define RTWOPI 1.0/TWOPI
#define FPI 4.0*PI
#define RFPI 1.0/(FPI)

namespace mocc {
    // Surface and direction indexing
    enum Surface {
        EAST  = 0,
        NORTH = 1,
        WEST  = 2,
        SOUTH = 3,
        TOP = 4,
        BOTTOM = 5,
        INVALID = 6,
    };

    enum class Direction {
        EAST  = 0,
        NORTH = 1,
        WEST  = 2,
        SOUTH = 3,
        TOP = 4,
        BOTTOM = 5,
        NE,
        NW,
        SW,
        SE,
        INVALID
    };

    extern const Surface AllSurfaces[6];

    enum class Normal {
        X_NORM = 0,
        Y_NORM,
        Z_NORM
    };

    extern const Normal AllNormals[3];

    // Boundary condition enumeration
    enum class Boundary {
        /**
         * Zero incoming flux
         */
        VACUUM,
        /**
         * Reflected incoming flux
         */
        REFLECT,
        /**
         * Incoming flux communicated between domain nodes
         */
        PARALLEL,
        /**
         * Flux exiting one face enters the opposite face, same angle
         */
        PERIODIC,
        INVALID
    };

    enum class TraceDir {
        FW,
        BW
    };

    std::ostream& operator<<(std::ostream& os, const Surface s );

    std::ostream& operator<<(std::ostream& os, const Boundary b );

    std::ostream& operator<<(std::ostream& os, const Normal n );

    Normal surface_to_normal( Surface s );

}
<|endoftext|>


<commit_before>/*
 * Convert GError to a HTTP response.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "request.hxx"
#include "bp_instance.hxx"
#include "http_client.hxx"
#include "nfs/Quark.hxx"
#include "ajp/ajp_client.hxx"
#include "memcached/memcached_client.hxx"
#include "cgi/cgi_quark.h"
#include "fcgi/Quark.hxx"
#include "was/was_quark.h"
#include "widget/Error.hxx"
#include "http_response.hxx"
#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_quark.h"
#include "http/MessageHttpResponse.hxx"
#include "HttpMessageResponse.hxx"
#include "gerrno.h"
#include "pool.hxx"
#include "util/Exception.hxx"

#include <daemon/log.h>

#include <nfsc/libnfs-raw-nfs.h>

static MessageHttpResponse
Dup(struct pool &pool, http_status_t status, const char *msg)
{
    return {status, p_strdup(&pool, msg)};
}

gcc_pure
static MessageHttpResponse
ToResponse(struct pool &pool, GError &error)
{
    if (error.domain == http_response_quark())
        return Dup(pool, http_status_t(error.code), error.message);

    if (error.domain == widget_quark()) {
        switch (WidgetErrorCode(error.code)) {
        case WidgetErrorCode::UNSPECIFIED:
            break;

        case WidgetErrorCode::WRONG_TYPE:
        case WidgetErrorCode::UNSUPPORTED_ENCODING:
            return {HTTP_STATUS_BAD_GATEWAY, "Malformed widget response"};

        case WidgetErrorCode::NO_SUCH_VIEW:
            return {HTTP_STATUS_NOT_FOUND, "No such view"};

        case WidgetErrorCode::NOT_A_CONTAINER:
            return Dup(pool, HTTP_STATUS_NOT_FOUND, error.message);

        case WidgetErrorCode::FORBIDDEN:
            return {HTTP_STATUS_FORBIDDEN, "Forbidden"};
        }
    }

    if (error.domain == nfs_client_quark()) {
        switch (error.code) {
        case NFS3ERR_NOENT:
        case NFS3ERR_NOTDIR:
            return {HTTP_STATUS_NOT_FOUND,
                    "The requested file does not exist."};
        }
    }

    if (error.domain == http_client_quark() ||
             error.domain == ajp_client_quark())
        return {HTTP_STATUS_BAD_GATEWAY, "Upstream server failed"};
    else if (error.domain == cgi_quark() ||
             error.domain == fcgi_quark() ||
             error.domain == was_quark())
        return {HTTP_STATUS_BAD_GATEWAY, "Script failed"};
    else if (error.domain == errno_quark()) {
        switch (error.code) {
        case ENOENT:
        case ENOTDIR:
            return {HTTP_STATUS_NOT_FOUND,
                    "The requested file does not exist."};
            break;

        default:
            return {HTTP_STATUS_INTERNAL_SERVER_ERROR,
                    "Internal server error"};
        }
    } else if (error.domain == memcached_client_quark())
        return {HTTP_STATUS_BAD_GATEWAY, "Cache server failed"};
    else
        return {HTTP_STATUS_INTERNAL_SERVER_ERROR, "Internal server error"};
}

gcc_pure
static MessageHttpResponse
ToResponse(struct pool &pool, std::exception_ptr ep)
{
    try {
        FindRetrowNested<HttpMessageResponse>(ep);
    } catch (const HttpMessageResponse &e) {
        return Dup(pool, e.GetStatus(), e.what());
    }

    try {
        FindRetrowNested<WidgetError>(ep);
    } catch (const WidgetError &e) {
        switch (e.GetCode()) {
        case WidgetErrorCode::UNSPECIFIED:
            break;

        case WidgetErrorCode::WRONG_TYPE:
        case WidgetErrorCode::UNSUPPORTED_ENCODING:
            return {HTTP_STATUS_BAD_GATEWAY, "Malformed widget response"};

        case WidgetErrorCode::NO_SUCH_VIEW:
            return {HTTP_STATUS_NOT_FOUND, "No such view"};

        case WidgetErrorCode::NOT_A_CONTAINER:
            return Dup(pool, HTTP_STATUS_NOT_FOUND, e.what());

        case WidgetErrorCode::FORBIDDEN:
            return {HTTP_STATUS_FORBIDDEN, "Forbidden"};
        }
    }

    return {HTTP_STATUS_INTERNAL_SERVER_ERROR, "Internal server error"};
}

void
response_dispatch_error(Request &request, GError *error)
{
    auto response = ToResponse(request.pool, *error);
    if (request.instance.config.verbose_response)
        response.message = p_strdup(&request.pool, error->message);

    response_dispatch_message(request, response.status, response.message);
}

void
response_dispatch_log(Request &request, http_status_t status,
                      const char *msg, const char *log_msg)
{
    daemon_log(2, "error on '%s': %s\n", request.request.uri, log_msg);

    if (request.instance.config.verbose_response)
        msg = p_strdup(&request.pool, log_msg);

    response_dispatch_message(request, status, msg);
}

void
response_dispatch_log(Request &request, http_status_t status,
                      const char *log_msg)
{
    response_dispatch_log(request, status,
                          http_status_to_string(status), log_msg);
}

void
response_dispatch_log(Request &request, std::exception_ptr ep)
{
    auto log_msg = GetFullMessage(ep);
    daemon_log(2, "error on '%s': %s\n", request.request.uri, log_msg.c_str());

    auto response = ToResponse(request.pool, ep);
    if (request.instance.config.verbose_response)
        response.message = p_strdup(&request.pool, log_msg.c_str());

    response_dispatch_message(request, response.status, response.message);
}
<commit_msg>rerror: translate NfsClientError<commit_after>/*
 * Convert GError to a HTTP response.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "request.hxx"
#include "bp_instance.hxx"
#include "http_client.hxx"
#include "nfs/Quark.hxx"
#include "nfs/Error.hxx"
#include "ajp/ajp_client.hxx"
#include "memcached/memcached_client.hxx"
#include "cgi/cgi_quark.h"
#include "fcgi/Quark.hxx"
#include "was/was_quark.h"
#include "widget/Error.hxx"
#include "http_response.hxx"
#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_quark.h"
#include "http/MessageHttpResponse.hxx"
#include "HttpMessageResponse.hxx"
#include "gerrno.h"
#include "pool.hxx"
#include "util/Exception.hxx"

#include <daemon/log.h>

#include <nfsc/libnfs-raw-nfs.h>

static MessageHttpResponse
Dup(struct pool &pool, http_status_t status, const char *msg)
{
    return {status, p_strdup(&pool, msg)};
}

gcc_pure
static MessageHttpResponse
ToResponse(struct pool &pool, GError &error)
{
    if (error.domain == http_response_quark())
        return Dup(pool, http_status_t(error.code), error.message);

    if (error.domain == widget_quark()) {
        switch (WidgetErrorCode(error.code)) {
        case WidgetErrorCode::UNSPECIFIED:
            break;

        case WidgetErrorCode::WRONG_TYPE:
        case WidgetErrorCode::UNSUPPORTED_ENCODING:
            return {HTTP_STATUS_BAD_GATEWAY, "Malformed widget response"};

        case WidgetErrorCode::NO_SUCH_VIEW:
            return {HTTP_STATUS_NOT_FOUND, "No such view"};

        case WidgetErrorCode::NOT_A_CONTAINER:
            return Dup(pool, HTTP_STATUS_NOT_FOUND, error.message);

        case WidgetErrorCode::FORBIDDEN:
            return {HTTP_STATUS_FORBIDDEN, "Forbidden"};
        }
    }

    if (error.domain == nfs_client_quark()) {
        switch (error.code) {
        case NFS3ERR_NOENT:
        case NFS3ERR_NOTDIR:
            return {HTTP_STATUS_NOT_FOUND,
                    "The requested file does not exist."};
        }
    }

    if (error.domain == http_client_quark() ||
             error.domain == ajp_client_quark())
        return {HTTP_STATUS_BAD_GATEWAY, "Upstream server failed"};
    else if (error.domain == cgi_quark() ||
             error.domain == fcgi_quark() ||
             error.domain == was_quark())
        return {HTTP_STATUS_BAD_GATEWAY, "Script failed"};
    else if (error.domain == errno_quark()) {
        switch (error.code) {
        case ENOENT:
        case ENOTDIR:
            return {HTTP_STATUS_NOT_FOUND,
                    "The requested file does not exist."};
            break;

        default:
            return {HTTP_STATUS_INTERNAL_SERVER_ERROR,
                    "Internal server error"};
        }
    } else if (error.domain == memcached_client_quark())
        return {HTTP_STATUS_BAD_GATEWAY, "Cache server failed"};
    else
        return {HTTP_STATUS_INTERNAL_SERVER_ERROR, "Internal server error"};
}

gcc_pure
static MessageHttpResponse
ToResponse(struct pool &pool, std::exception_ptr ep)
{
    try {
        FindRetrowNested<HttpMessageResponse>(ep);
    } catch (const HttpMessageResponse &e) {
        return Dup(pool, e.GetStatus(), e.what());
    }

    try {
        FindRetrowNested<WidgetError>(ep);
    } catch (const WidgetError &e) {
        switch (e.GetCode()) {
        case WidgetErrorCode::UNSPECIFIED:
            break;

        case WidgetErrorCode::WRONG_TYPE:
        case WidgetErrorCode::UNSUPPORTED_ENCODING:
            return {HTTP_STATUS_BAD_GATEWAY, "Malformed widget response"};

        case WidgetErrorCode::NO_SUCH_VIEW:
            return {HTTP_STATUS_NOT_FOUND, "No such view"};

        case WidgetErrorCode::NOT_A_CONTAINER:
            return Dup(pool, HTTP_STATUS_NOT_FOUND, e.what());

        case WidgetErrorCode::FORBIDDEN:
            return {HTTP_STATUS_FORBIDDEN, "Forbidden"};
        }
    }

    try {
        FindRetrowNested<NfsClientError>(ep);
    } catch (const NfsClientError &e) {
        switch (e.GetCode()) {
        case NFS3ERR_NOENT:
        case NFS3ERR_NOTDIR:
            return {HTTP_STATUS_NOT_FOUND,
                    "The requested file does not exist."};
        }
    }

    return {HTTP_STATUS_INTERNAL_SERVER_ERROR, "Internal server error"};
}

void
response_dispatch_error(Request &request, GError *error)
{
    auto response = ToResponse(request.pool, *error);
    if (request.instance.config.verbose_response)
        response.message = p_strdup(&request.pool, error->message);

    response_dispatch_message(request, response.status, response.message);
}

void
response_dispatch_log(Request &request, http_status_t status,
                      const char *msg, const char *log_msg)
{
    daemon_log(2, "error on '%s': %s\n", request.request.uri, log_msg);

    if (request.instance.config.verbose_response)
        msg = p_strdup(&request.pool, log_msg);

    response_dispatch_message(request, status, msg);
}

void
response_dispatch_log(Request &request, http_status_t status,
                      const char *log_msg)
{
    response_dispatch_log(request, status,
                          http_status_to_string(status), log_msg);
}

void
response_dispatch_log(Request &request, std::exception_ptr ep)
{
    auto log_msg = GetFullMessage(ep);
    daemon_log(2, "error on '%s': %s\n", request.request.uri, log_msg.c_str());

    auto response = ToResponse(request.pool, ep);
    if (request.instance.config.verbose_response)
        response.message = p_strdup(&request.pool, log_msg.c_str());

    response_dispatch_message(request, response.status, response.message);
}
<|endoftext|>


<commit_before>// RSHELL.CPP
// Main source code for rshell

#include "unistd.h"
#include "sys/wait.h"
#include "stdio.h"
#include "errno.h"

#include <iostream>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/regex.hpp>

#include "rshell.h"

#define RSHELL_DEBUG

const char* CONN_AMP = "&&";
const char* CONN_PIPE = "||";
const char* CONN_SEMIC = ";";

/* Initialize environment */
void init() {}

/* Main loop - controls command line, parsing, and execution logic */
int run() {

    std::vector<std::string> tokens_conn;
    std::vector<std::string> tokens_word;
    std::string usr_input;

    while(true) {

        usr_input = prompt();

        tokens_conn = tokenize(usr_input, "(\\|\\||\\&\\&|;)");
        for(unsigned int i = 0; i < tokens_conn.size(); i++) {

#ifdef RSHELL_DEBUG
            std::cout << "<" << tokens_conn.at(i) << ">" << std::endl;
#endif

            tokens_word = toksplit(tokens_conn.at(i), " ");
            for(unsigned int j = 0; j < tokens_word.size(); j++) {

                std::string word = tokens_word.at(j);
                // kill empty words
                if(word == "") tokens_word.erase(tokens_word.begin() + j);

                // using boost for convenience - this can be implemented manually
                boost::trim_if(word, boost::is_any_of(" \t"));
            }

            std::vector<char*> cmd_argv(tokens_word.size() + 1);
            for(unsigned int k = 0; k < tokens_word.size(); k++) {
               cmd_argv[k] = &tokens_word[k][0];
#ifdef RSHELL_DEBUG
               std::cout << "\t" << "<" << tokens_word.at(k) << ">" << std::endl;
#endif
            }

            // exit only if first word is "exit", after formatting
            if(tokens_word.at(0) == "exit") return 0;

            execute(cmd_argv[0], cmd_argv.data());
        }
    }

    return 0;
}

/* Prints the prompt symbol and takes in raw command line input */
std::string prompt() {

    std::cout << "$ " << std::flush;

    std::string input_raw;
    std::getline(std::cin, input_raw);

    return input_raw;
}

/* Basically a wrapper for execvp, has error checking */
int execute(const char* path, char* const argv[]) {

#ifdef RSHELL_DEBUG
    std::cout << "executing " << path << std::endl;
#endif
    int pid = fork();
    if(pid == -1) {
        perror(NULL);
        return -1;
    } else if(pid == 0) {
        execvp(path, argv);
        perror(path);
        return 1;
    } else {
        if(waitpid(pid, NULL, 0) == -1)
            perror(NULL);
    }

    return 0;
}

/* Overload to tokenize by whitespace */
std::vector<std::string> tokenize(std::string s) {
    return tokenize(s, "\\s");
}

/* Tokenize a string using boost regex */
std::vector<std::string> tokenize(std::string s, std::string r) {

    std::vector<std::string> token_vec;

    boost::algorithm::split_regex(token_vec, s, boost::regex(r));
    return token_vec;
}

/* Tokenize a string using boost split */
std::vector<std::string> toksplit(std::string s, std::string toks) {

    std::vector<std::string> token_vec;
    boost::split(token_vec, s, boost::is_any_of(toks), boost::token_compress_on);
    return token_vec;
}
<commit_msg>fixed exit bug<commit_after>// RSHELL.CPP
// Main source code for rshell

#define RSHELL_DEBUG

#include "unistd.h"
#include "sys/wait.h"
#include "stdio.h"
#include "errno.h"

#include <iostream>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/regex.hpp>

#include "rshell.h"

const char* CONN_AMP = "&&";
const char* CONN_PIPE = "||";
const char* CONN_SEMIC = ";";

/* Initialize environment */
void init() {}

/* Main loop - controls command line, parsing, and execution logic */
int run() {

    std::vector<std::string> tokens_conn;
    std::vector<std::string> tokens_word;
    std::string usr_input;

    while(true) {

        usr_input = prompt();

        tokens_conn = tokenize(usr_input, "(\\|\\||\\&\\&|;)");
        for(unsigned int i = 0; i < tokens_conn.size(); i++) {

#ifdef RSHELL_DEBUG
            std::cout << "<" << tokens_conn.at(i) << ">" << std::endl;
#endif

            tokens_word = toksplit(tokens_conn.at(i), " ");
            for(unsigned int j = 0; j < tokens_word.size(); j++) {

                std::string word = tokens_word.at(j);
                // kill empty words
                if(word == "") tokens_word.erase(tokens_word.begin() + j);

                // using boost for convenience - this can be implemented manually
                boost::trim_if(word, boost::is_any_of(" \t"));
            }

            std::vector<char*> cmd_argv(tokens_word.size() + 1);
            for(unsigned int k = 0; k < tokens_word.size(); k++) {
               cmd_argv[k] = &tokens_word[k][0];
#ifdef RSHELL_DEBUG
               std::cout << "\t" << "<" << tokens_word.at(k) << ">" << std::endl;
#endif
            }

            // exit only if first word is "exit", after formatting
            if(tokens_word.at(0) == "exit") return 0;

            int err_num = execute(cmd_argv[0], cmd_argv.data());

            // if execvp returned and had error, stop the process
            if(err_num == 1) return 1;
        }
    }

    return 0;
}

/* Prints prompt text and takes in raw command line input */
std::string prompt() {

    char hostname[HOST_NAME_MAX];
    if(gethostname(hostname, HOST_NAME_MAX) == -1)
        perror("gethostname");

    std::cout << getlogin() << "@" << hostname;
    std::cout << "$ " << std::flush;

    std::string input_raw;
    std::getline(std::cin, input_raw);

    return input_raw;
}

/* fork and exec a program, complete error checking */
int execute(const char* path, char* const argv[]) {

#ifdef RSHELL_DEBUG
    std::cout << "executing " << path << std::endl;
#endif

    int pid = fork();

#ifdef RSHELL_DEBUG
    std::cout << "created process with id " << pid << std::endl;
#endif

    if(pid == -1) {
        perror("fork");
        return -1;
    } else if(pid == 0) {
        execvp(path, argv);
        perror(path);
        return 1;
    } else {
        if(waitpid(pid, NULL, 0) == -1)
            perror("waitpid");
    }

    return 0;
}

/* Overload to tokenize by whitespace */
std::vector<std::string> tokenize(std::string s) {
    return tokenize(s, "\\s");
}

/* Tokenize a string using boost regex */
std::vector<std::string> tokenize(std::string s, std::string r) {

    std::vector<std::string> token_vec;

    boost::algorithm::split_regex(token_vec, s, boost::regex(r));
    return token_vec;
}

/* Tokenize a string using boost split */
std::vector<std::string> toksplit(std::string s, std::string toks) {

    std::vector<std::string> token_vec;
    boost::split(token_vec, s, boost::is_any_of(toks), boost::token_compress_on);
    return token_vec;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string.h>
#include <boost/tokenizer.hpp>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <algorithm>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>

using namespace std;
using namespace boost;

class Connector
{
    public:
        Connector();
        ~Connector();
        bool run;
        int type;
        bool runNext();
        bool precedence;

};

Connector::Connector()
{
    // the semicolon connector allows the next command to be execute always
    run = true;
    type = 0; // semicolon connector set to 0
    precedence = false;
}

Connector::~Connector()
{
}
bool Connector::runNext()
{
    if (type == 1) // && connector
    {
        if (!run) // if the first command doesn't succeed  it wont run the next command
        {
            return false;
        }
    }
    else if (type == 2) // || connector
    {
        if (run) // if the first command succeed it wont run the next command
        {
            return false;
        }
    }
    return true;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag);
void commandifier(string command, string argument, Connector& connect, string flag);
void test_function(string command, string & flag, string argument, Connector& connect);
int main()
{
    string flag;
    string str;
    string command;
    string argument;
    Connector connect;
    char hostname[100];
    int position = 0;
    while (true)
    {
        printf("%s",getlogin()); // returns string containing name of user logged in
        gethostname(hostname, sizeof hostname); // returns the standard host name for the current machine
        cout << "@" << hostname << "$ ";
        getline(cin, str);
        if (str == "exit") // special command of exit
        {
            break;
        }
        vector<string> instruction; // vector of strings
        typedef tokenizer<boost::char_separator<char> > Tok;
        char_separator<char> sep; // default constructed
        Tok tok(str, sep);;
        for (Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) // parses the input into a command and argument
        {
	    instruction.push_back(*tok_iter);

	}
	if (instruction[0] != "#") // checks for user input except for comments (#)
        {
            parseinator(instruction, command, argument, position, connect, flag); // parses the input into a command and argument
            commandifier(command, argument, connect, flag); // runs a command with a given argument
            command = "";
            argument = "";
            int vector_size = instruction.size();
            for (; position < vector_size;) // run until the end of the instruction
            {
                parseinator(instruction, command, argument, position, connect, flag);
                if (connect.runNext() && command != "") // checks connector to see if the next command should be ran
	        {
                    commandifier(command, argument, connect, flag);
                }
	        else
	        {
	            while(connect.precedence && position < vector_size)
		        {
		            if(instruction[position] == ")")
		            {
		                connect.precedence = false;
		            }
		            position++;
		        }
	            connect.run = true;
	            command = "";
	        }
	        command = "";
                argument = "";
            }
            position = 0;
        }
    }
    return 0;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag)
{
    if (input[position] == "&") // check if string is equal to & connector
    {
        connect.type = 1; // set & connector to 1
        position += 2; // +=2 in order to take && connect
    }
    if (input[position] == "|")
    {
        connect.type = 2; // set | connector to 2
        position += 2; // +=2 in order to take || connector
    }
    if (input[position] == ";")
    {
        connect.type = 0; // set ; connector to 0
        position ++;
    }
    if (input[position] == "(")
    {
        connect.precedence = true;
        position++;
    }
    if (input[position] != "#")
    {
        command = input[position];
        position++;
    }
    if (command == "test")
    {
        if(input[position] == "-")
        {
            position++;
	    if (input[position] == "f")
            {
		flag = "-f";
		position++;
	    }
	    else if (input[position] == "d")
	    {
		flag = "-d";
		position++;
	    }
	    else // DEFAULT E
	    {
		flag = "-e";
		position++;
            }
        }
    }

    int input_size = input.size();
    for (; position < input_size; position++)
    {
        if (input[position] == ")")
        {
            connect.precedence = false;
            position++;
            break;
        }
        if(command == "echo" && input[position] == "\"")
        {
            position++;
            while(input[position] != "\"" && position <= input_size)
            {

                argument += input[position];
                if(!isalnum(input[position].at(0)) && !isalnum(input[position+1].at(0)))
                {

                }
                else
		{
                    argument += " ";
                }
		position++;
            }
            position++;
            break;
        }
        if (input[position] == "#")
        {
            position = input.size();
            break;
        }
        if (input[position] == "&" || input[position] == "|" || input[position] == ";")
	    {
            break;
    	}

        argument += input[position];
        int input_size1 = input.size();
        if (position+1 != input_size1 && command == "echo")
	{
	    //adds spaces when echoing
            argument += " ";
	}
    }
}
void commandifier(string command, string argument, Connector& connect, string flag)
{
    const char * const_command = command.c_str();
    char * char_command = new char[command.size()];
    const char * const_argument = argument.c_str();
    char * char_argument = new char[argument.size()];
    strcpy (char_command, const_command);
    strcpy (char_argument, const_argument);
    char * args[2]; // char pointer array that holds command, and NULL
    char * args1[3]; // char pointer array that holds command, argument, and NULL
    bool no_arg = true;
    bool failed = false;

    if(command == "test" || command == "[")
    {
	test_function(command,flag,argument,connect);
	return;
    }
    // exit command
    if(command == "exit" || argument == "exit")
    {
	exit(1);
    }

    if (argument.size() == 0) // no arguments
    {
        args[0] = char_command; // args will contain the command
        args[1] = NULL;
    }
    else
    {
	no_arg = false; // sets bool no_arg to false
	args1[0] = char_command; // args1 contains command and argument
        args1[1] = char_argument;
        args1[2] = NULL;
    }
    pid_t c_pid, pid; // data type to reporesent process ID's
    int status;
    c_pid = fork(); // create our fork

    if (c_pid < 0) // indicates the fork has fail if its less than 0
    {
        perror("fork failed");
        exit(1);
    }
    else if (c_pid == 0) // in child process
    {
 	if (no_arg) // no argument
	{
        	execvp( args[0], args); // execvp the char pointer array that holds the command only
        	if (execvp(args[0], args) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
	else // with command and argument
	{
		execvp(args1[0], args1); // execvp the char pointer array that holds the command, and argument
		if (execvp(args1[0], args1) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
    }
    else if (c_pid > 0) // parent process
    {
        if((pid = wait(&status)) < 0 )
        {
            perror("wait");
	    exit(3);
        }
        if (WIFEXITED(status))  //Evaluates to a non-zero value if status was returned for a child process that terminated normally.

        {
            if (WEXITSTATUS(status) != 0)
            {
                connect.run = false;
            }
	    else
	    {
		connect.run = true;
            }
        }
       else
        {
            connect.run = true;
        }
     }
}
void test_function(string command, string & flag, string argument, Connector& connect)
{
   const char * arg = argument.c_str();
   struct stat sb; // struct for the stat function
   cout<<flag<<endl;
   if(flag == "-f")
   {
        if(stat(arg,&sb) == 0)
        {
            connect.run = true;
	    if(S_ISREG(sb.st_mode))
	    {
 		connect.run = true;
	    }
	    else
	    {
		connect.run = false;
	    }
        }
        else
        {
            connect.run = false;
        }
   }
   else if(flag == "-d")
   {
        if(stat(arg,&sb) == 0)
        {
            connect.run = true;
            if(S_ISDIR(sb.st_mode))
            {
            	connect.run = true;
            }
            else
       	    {
             	connect.run = false;
            }
        }
        else
        {
            connect.run = false;
        }

   }
   else
   {
	if(stat(arg,&sb) == 0)
	{
	    connect.run = true;
 	}
	else
	{
	    connect.run = false;
	}
   }
}
<commit_msg>Update rshell.cpp<commit_after>#include <iostream>
#include <string.h>
#include <boost/tokenizer.hpp>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <algorithm>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>

using namespace std;
using namespace boost;

class Connector
{
    public:
        Connector();
        ~Connector();
        bool run;
        int type;
        bool runNext();
        bool precedence;

};

Connector::Connector()
{
    // the semicolon connector allows the next command to be execute always
    run = true;
    type = 0; // semicolon connector set to 0
    precedence = false;
}

Connector::~Connector()
{
}
bool Connector::runNext()
{
    if (type == 1) // && connector
    {
        if (!run) // if the first command doesn't succeed  it wont run the next command
        {
            return false;
        }
    }
    else if (type == 2) // || connector
    {
        if (run) // if the first command succeed it wont run the next command
        {
            return false;
        }
    }
    return true;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag);
void commandifier(string command, string argument, Connector& connect, string flag);
void test_function(string command, string & flag, string argument, Connector& connect);
int main()
{
    string flag;
    string str;
    string command;
    string argument;
    Connector connect;
    char hostname[100];
    int position = 0;
    while (true)
    {
        printf("%s",getlogin()); // returns string containing name of user logged in
        gethostname(hostname, sizeof hostname); // returns the standard host name for the current machine
        cout << "@" << hostname << "$ ";
        getline(cin, str);
        if (str == "exit") // special command of exit
        {
            break;
        }
        vector<string> instruction; // vector of strings
        typedef tokenizer<boost::char_separator<char> > Tok;
        char_separator<char> sep; // default constructed
        Tok tok(str, sep);;
        for (Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) // parses the input into a command and argument
        {
	    instruction.push_back(*tok_iter);

	}
	if (instruction[0] != "#") // checks for user input except for comments (#)
        {
            parseinator(instruction, command, argument, position, connect, flag); // parses the input into a command and argument
            commandifier(command, argument, connect, flag); // runs a command with a given argument
            command = "";
            argument = "";
            int vector_size = instruction.size();
            for (; position < vector_size;) // run until the end of the instruction
            {
                parseinator(instruction, command, argument, position, connect, flag);
                if (connect.runNext() && command != "") // checks connector to see if the next command should be ran
	        {
                    commandifier(command, argument, connect, flag);
                }
	        else
	        {
	            while(connect.precedence && position < vector_size)
		        {
		            if(instruction[position] == ")")
		            {
		                connect.precedence = false;
		            }
		            position++;
		        }
	            connect.run = true;
	            command = "";
	        }
	        command = "";
                argument = "";
            }
            position = 0;
        }
    }
    return 0;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag)
{
    if (input[position] == "&") // check if string is equal to & connector
    {
        connect.type = 1; // set & connector to 1
        position += 2; // +=2 in order to take && connect
    }
    if (input[position] == "|")
    {
        connect.type = 2; // set | connector to 2
        position += 2; // +=2 in order to take || connector
    }
    if (input[position] == ";")
    {
        connect.type = 0; // set ; connector to 0
        position ++;
    }
    if (input[position] == "(")
    {
        connect.precedence = true;
        position++;
    }
    if (input[position] != "#")
    {
        command = input[position];
        position++;
    }
    if (command == "test")
    {
        if(input[position] == "-")
        {
            position++;
	    if (input[position] == "f")
            {
		flag = "-f";
		position++;
	    }
	    else if (input[position] == "d")
	    {
		flag = "-d";
		position++;
	    }
	    else // DEFAULT E
	    {
		flag = "-e";
		position++;
            }
        }
    }

    int input_size = input.size();
    for (; position < input_size; position++)
    {
        if (input[position] == ")")
        {
            connect.precedence = false;
            position++;
            break;
        }
        if(command == "echo" && input[position] == "\"")
        {
            position++;
            while(input[position] != "\"" && position <= input_size)
            {

                argument += input[position];
                if(!isalnum(input[position].at(0)) && !isalnum(input[position+1].at(0)))
                {

                }
                else
		{
                    argument += " ";
                }
		position++;
            }
            position++;
            break;
        }
        if (input[position] == "#")
        {
            position = input.size();
            break;
        }
        if (input[position] == "&" || input[position] == "|" || input[position] == ";")
	    {
            break;
    	}

        argument += input[position];
        int input_size1 = input.size();
        if (position+1 != input_size1 && command == "echo")
	{
	    //adds spaces when echoing
            argument += " ";
	}
    }
}
void commandifier(string command, string argument, Connector& connect, string flag)
{
    const char * const_command = command.c_str();
    char * char_command = new char[command.size()];
    const char * const_argument = argument.c_str();
    char * char_argument = new char[argument.size()];
    strcpy (char_command, const_command);
    strcpy (char_argument, const_argument);
    char * args[2]; // char pointer array that holds command, and NULL
    char * args1[3]; // char pointer array that holds command, argument, and NULL
    bool no_arg = true;
    bool failed = false;

    if(command == "test" || command == "[")
    {
	test_function(command,flag,argument,connect);
	return;
    }
    // exit command
    if(command == "exit" || argument == "exit")
    {
	exit(1);
    }

    if (argument.size() == 0) // no arguments
    {
        args[0] = char_command; // args will contain the command
        args[1] = NULL;
    }
    else
    {
	no_arg = false; // sets bool no_arg to false
	args1[0] = char_command; // args1 contains command and argument
        args1[1] = char_argument;
        args1[2] = NULL;
    }
    pid_t c_pid, pid; // data type to reporesent process ID's
    int status;
    c_pid = fork(); // create our fork

    if (c_pid < 0) // indicates the fork has fail if its less than 0
    {
        perror("fork failed");
        exit(1);
    }
    else if (c_pid == 0) // in child process
    {
 	if (no_arg) // no argument
	{
        	execvp( args[0], args); // execvp the char pointer array that holds the command only
        	if (execvp(args[0], args) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
	else // with command and argument
	{
		execvp(args1[0], args1); // execvp the char pointer array that holds the command, and argument
		if (execvp(args1[0], args1) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
    }
    else if (c_pid > 0) // parent process
    {
        if((pid = wait(&status)) < 0 )
        {
            perror("wait");
	    exit(3);
        }
        if (WIFEXITED(status))  //Evaluates to a non-zero value if status was returned for a child process that terminated normally.

        {
            if (WEXITSTATUS(status) != 0)
            {
                connect.run = false;
            }
	    else
	    {
		connect.run = true;
            }
        }
       else
        {
            connect.run = true;
        }
     }
}
void test_function(string command, string & flag, string argument, Connector& connect)
{
   const char * arg = argument.c_str();
   struct stat sb; // struct for the stat function
   if(flag == "-f")
   {
        if(stat(arg,&sb) == 0)
        {
            connect.run = true;
	    if(S_ISREG(sb.st_mode))
	    {
 		connect.run = true;
	    }
	    else
	    {
		connect.run = false;
	    }
        }
        else
        {
            connect.run = false;
        }
   }
   else if(flag == "-d")
   {
        if(stat(arg,&sb) == 0)
        {
            connect.run = true;
            if(S_ISDIR(sb.st_mode))
            {
            	connect.run = true;
            }
            else
       	    {
             	connect.run = false;
            }
        }
        else
        {
            connect.run = false;
        }

   }
   else
   {
	if(stat(arg,&sb) == 0)
	{
	    connect.run = true;
 	}
	else
	{
	    connect.run = false;
	}
   }
}
<|endoftext|>