text:
/**
 * Copyright (C) 2016 MongoDB Inc.
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * As a special exception, the copyright holders give permission to link the
 * code of portions of this program with the OpenSSL library under certain
 * conditions as described in each individual source file and distribute
 * linked combinations including the program with the OpenSSL library. You
 * must comply with the GNU Affero General Public License in all respects
 * for all of the code used other than as permitted herein. If you modify
 * file(s) with this exception, you may extend this exception to your
 * version of the file(s), but you are not obligated to do so. If you do not
 * wish to do so, delete this exception statement from your version. If you
 * delete this exception statement from all source files in the program,
 * then also delete it in the license file.
 */

#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kFTDC

#include "mongo/platform/basic.h"

#include "mongo/util/procparser.h"

#include <algorithm>
#include <array>
#include <boost/algorithm/string/finder.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem.hpp>
#include <fcntl.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <type_traits>
#include <unistd.h>

#include "mongo/base/parse_number.h"
#include "mongo/base/status.h"
#include "mongo/base/status_with.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/scopeguard.h"
#include "mongo/util/text.h"
namespace mongo {

namespace {

/**
 * Get USER_HZ for the machine. See time(7) for an explanation.
 */
int64_t getTicksPerSecond() {
    int64_t ret = sysconf(_SC_CLK_TCK);
    return ret;
}

/**
 * Convert USER_HZ to milliseconds.
 */
double convertTicksToMilliSeconds(const int64_t ticks, const int64_t ticksPerSecond) {
    return static_cast<double>(ticks) / (static_cast<double>(ticksPerSecond) / 1000.0);
}

const size_t kFileBufferSize = 16384;
const size_t kFileReadRetryCount = 5;

constexpr auto kSysBlockDeviceDirectoryName = "device";

/**
 * Read a file from disk as a string with a null-terminating byte using the POSIX file api.
 *
 * This function is designed to get all the data it needs from small /proc files in a single read.
 * The /proc/stat and /proc/diskstats files can vary in size, but 16kb will cover most cases.
 *
 * Finally, we return errors instead of throwing to ensure that FTDC can return partial information
 * on failure instead of no information. Some container filesystems may overlay /proc so we may not
 * be reading directly from the kernel.
 */
StatusWith<std::string> readFileAsString(StringData filename) {
    int fd = open(filename.toString().c_str(), 0);
    if (fd == -1) {
        int err = errno;
        return Status(ErrorCodes::FileOpenFailed,
                      str::stream() << "Failed to open file " << filename
                                    << " with error: " << errnoWithDescription(err));
    }
    auto scopedGuard = MakeGuard([fd] { close(fd); });

    BufBuilder builder(kFileBufferSize);
    std::array<char, kFileBufferSize> buf;

    ssize_t size_read = 0;

    // Read until the end as needed
    do {
        // Retry if interrupted
        size_t retry = 0;

        do {
            size_read = read(fd, buf.data(), kFileBufferSize);

            if (size_read == -1) {
                int err = errno;

                // Retry if we hit EGAIN or EINTR a few times before giving up
                if (retry < kFileReadRetryCount && (err == EAGAIN || err == EINTR)) {
                    ++retry;
                    continue;
                }

                return Status(ErrorCodes::FileStreamFailed,
                              str::stream() << "Failed to read file " << filename
                                            << " with error: " << errnoWithDescription(err));
            }

            break;
        } while (true);

        if (size_read != 0) {
            builder.appendBuf(buf.data(), size_read);
        }
    } while (size_read != 0);

    // Null terminate the buffer since we are about to convert it to a string
    builder.appendChar(0);

    return std::string(builder.buf(), builder.len());
}

const char* const kAdditionCpuFields[] = {"user_ms",
                                          "nice_ms",
                                          "system_ms",
                                          "idle_ms",
                                          "iowait_ms",
                                          "irq_ms",
                                          "softirq_ms",
                                          "steal_ms",
                                          "guest_ms",
                                          "guest_nice_ms"};
const size_t kAdditionCpuFieldCount = std::extent<decltype(kAdditionCpuFields)>::value;

const char* const kDiskFields[] = {
    "reads",
    "reads_merged",
    "read_sectors",
    "read_time_ms",
    "writes",
    "writes_merged",
    "write_sectors",
    "write_time_ms",
    "io_in_progress",
    "io_time_ms",
    "io_queued_ms",
};

const size_t kDiskFieldCount = std::extent<decltype(kDiskFields)>::value;

}  // namespace

namespace procparser {
// Here is an example of the type of string it supports.
// Note: intr output has been trimmed
//
// The cpu field maps up to 10 individual fields depending on the kernel version. For other views,
// this code assumes there is only a single value.
//
// For more information, see:
// Documentation/filesystems/proc.txt in the Linux kernel
// proc(5) man page
//
// > cat /proc/stat
// cpu  41801 9179 32206 831134223 34279 0 947 0 0 0
// cpu0 2977 450 2475 69253074 1959 0 116 0 0 0
// cpu1 6213 4261 9400 69177349 845 0 539 0 0 0
// cpu2 1949 831 3699 69261035 645 0 0 0 0 0
// cpu3 2222 644 3283 69264801 783 0 0 0 0 0
// cpu4 16576 607 4757 69232589 8195 0 291 0 0 0
// cpu5 3742 391 4571 69257332 2322 0 0 0 0 0
// cpu6 2173 376 743 69284308 400 0 0 0 0 0
// cpu7 1232 375 704 69285753 218 0 0 0 0 0
// cpu8 960 127 576 69262851 18107 0 0 0 0 0
// cpu9 1755 227 744 69283938 362 0 0 0 0 0
// cpu10 1380 641 678 69285193 219 0 0 0 0 0
// cpu11 618 244 572 69285995 218 0 0 0 0 0
// intr 54084718 135 2 ....
// ctxt 190305514
// btime 1463584038
// processes 47438
// procs_running 1
// procs_blocked 0
// softirq 102690251 8 26697410 115481 23345078 816026 0 2296 26068778 0 25645174
//
Status parseProcStat(const std::vector<StringData>& keys,
                     StringData data,
                     int64_t ticksPerSecond,
                     BSONObjBuilder* builder) {
    bool foundKeys = false;

    using string_split_iterator = boost::split_iterator<StringData::const_iterator>;

    // Split the file by lines.
    // token_compress_on means the iterator skips over consecutive '\n'. This should not be a
    // problem in normal /proc/stat output.
    for (string_split_iterator lineIt = string_split_iterator(
             data.begin(),
             data.end(),
             boost::token_finder([](char c) { return c == '\n'; }, boost::token_compress_on));
         lineIt != string_split_iterator();
         ++lineIt) {
        StringData line((*lineIt).begin(), (*lineIt).end());

        // Split the line by spaces since that is the only delimiter for stat files.
        // token_compress_on means the iterator skips over consecutive ' '. This is needed for the
        // first line which is "cpu  <number>".
        string_split_iterator partIt = string_split_iterator(
            line.begin(),
            line.end(),
            boost::token_finder([](char c) { return c == ' '; }, boost::token_compress_on));

        // Skip processing this line if we do not have a key.
        if (partIt == string_split_iterator()) {
            continue;
        }

        StringData key((*partIt).begin(), (*partIt).end());

        ++partIt;

        // Skip processing this line if we only have a key, and no number.
        if (partIt == string_split_iterator()) {
            continue;
        }

        // Check if the key is in the list. /proc/stat will have extra keys, and
        // may not have the keys we want.
        if (keys.empty() || std::find(keys.begin(), keys.end(), key) != keys.end()) {
            foundKeys = true;

            if (key == "cpu") {
                // Cpu is 10 fields, we need to chew through all of them.
                // Some kernels we support lack the last field or two: guest and/or guest_nice.
                for (size_t index = 0;
                     partIt != string_split_iterator() && index < kAdditionCpuFieldCount;
                     ++partIt, ++index) {
                    StringData stringValue((*partIt).begin(), (*partIt).end() - (*partIt).begin());

                    uint64_t value;

                    if (!parseNumberFromString(stringValue, &value).isOK()) {
                        value = 0;
                    }

                    builder->appendNumber(kAdditionCpuFields[index],
                                          convertTicksToMilliSeconds(value, ticksPerSecond));
                }
            } else {
                StringData stringValue((*partIt).begin(), (*partIt).end() - (*partIt).begin());

                uint64_t value;

                if (!parseNumberFromString(stringValue, &value).isOK()) {
                    value = 0;
                }

                builder->appendNumber(key, static_cast<long long>(value));
            }
        }
    }

    return foundKeys ? Status::OK()
                     : Status(ErrorCodes::NoSuchKey, "Failed to find any keys in stat string");
}

Status parseProcStatFile(StringData filename,
                         const std::vector<StringData>& keys,
                         BSONObjBuilder* builder) {
    auto swString = readFileAsString(filename);
    if (!swString.isOK()) {
        return swString.getStatus();
    }

    return parseProcStat(keys, swString.getValue(), getTicksPerSecond(), builder);
}

// Here is an example of the type of string it supports:
// Note: output has been trimmed
//
// For more information, see:
// Documentation/filesystems/proc.txt in the Linux kernel
// proc(5) man page
//
// > cat /proc/meminfo
// MemTotal:       12294392 kB
// MemFree:         3652612 kB
// MemAvailable:   11831704 kB
// Buffers:          568536 kB
// Cached:          6421520 kB
// SwapCached:            0 kB
// HugePages_Total:       0
//
// Note: HugePages_* do not end in kB, it is not a typo
//
Status parseProcMemInfo(const std::vector<StringData>& keys,
                        StringData data,
                        BSONObjBuilder* builder) {
    bool foundKeys = false;

    using string_split_iterator = boost::split_iterator<StringData::const_iterator>;

    // Split the file by lines.
    // token_compress_on means the iterator skips over consecutive '\n'. This should not be a
    // problem in normal /proc/memInfo output.
    for (string_split_iterator lineIt = string_split_iterator(
             data.begin(),
             data.end(),
             boost::token_finder([](char c) { return c == '\n'; }, boost::token_compress_on));
         lineIt != string_split_iterator();
         ++lineIt) {
        StringData line((*lineIt).begin(), (*lineIt).end());

        // Split the line by spaces and colons since these are the delimiters for meminfo files.
        // token_compress_on means the iterator skips over consecutive ' '. This is needed for
        // every line.
        string_split_iterator partIt = string_split_iterator(line.begin(),
                                                             line.end(),
                                                             boost::token_finder([](char c) {
                                                                 return c == ' ' || c == ':';
                                                             }, boost::token_compress_on));

        // Skip processing this line if we do not have a key.
        if (partIt == string_split_iterator()) {
            continue;
        }

        StringData key((*partIt).begin(), (*partIt).end());

        ++partIt;

        // Skip processing this line if we only have a key, and no number.
        if (partIt == string_split_iterator()) {
            continue;
        }

        // Check if the key is in the list. /proc/meminfo will have extra keys, and may not have the
        // keys we want.
        if (keys.empty() || std::find(keys.begin(), keys.end(), key) != keys.end()) {
            foundKeys = true;

            StringData stringValue((*partIt).begin(), (*partIt).end());

            uint64_t value;

            if (!parseNumberFromString(stringValue, &value).isOK()) {
                value = 0;
            }

            // Check if the line ends in "kB"
            ++partIt;

            // If there is one last token, check if it is actually "kB"
            if (partIt != string_split_iterator()) {
                StringData kb_token((*partIt).begin(), (*partIt).end());
                auto keyWithSuffix = key.toString();

                if (kb_token == "kB") {
                    keyWithSuffix.append("_kb");
                }

                builder->appendNumber(keyWithSuffix, static_cast<long long>(value));
            } else {
                builder->appendNumber(key, static_cast<long long>(value));
            }
        }
    }

    return foundKeys ? Status::OK()
                     : Status(ErrorCodes::NoSuchKey, "Failed to find any keys in meminfo string");
}

Status parseProcMemInfoFile(StringData filename,
                            const std::vector<StringData>& keys,
                            BSONObjBuilder* builder) {
    auto swString = readFileAsString(filename);
    if (!swString.isOK()) {
        return swString.getStatus();
    }

    return parseProcMemInfo(keys, swString.getValue(), builder);
}

// Here is an example of the type of string it supports:
//
// For more information, see:
// Documentation/iostats.txt in the Linux kernel
// proc(5) man page
//
// > cat /proc/diskstats
//   8       0 sda 120611 33630 6297628 96550 349797 167398 11311562 2453603 0 117514 2554160
//   8       1 sda1 138 37 8642 315 3 0 18 14 0 292 329
//   8       2 sda2 120409 33593 6285754 96158 329029 167398 11311544 2450573 0 115611 2550739
//   8      16 sdb 12707 3876 1525418 57507 997 3561 297576 97976 0 37870 155619
//   8      17 sdb1 12601 3876 1521090 57424 992 3561 297576 97912 0 37738 155468
//  11       0 sr0 0 0 0 0 0 0 0 0 0 0 0
// 253       0 dm-0 154910 0 6279522 177681 506513 0 11311544 5674418 0 117752 5852275
// 253       1 dm-1 109 0 4584 226 0 0 0 0 0 172 226
//
Status parseProcDiskStats(const std::vector<StringData>& disks,
                          StringData data,
                          BSONObjBuilder* builder) {
    bool foundKeys = false;
    std::vector<uint64_t> stats;
    stats.reserve(kDiskFieldCount);

    using string_split_iterator = boost::split_iterator<StringData::const_iterator>;

    // Split the file by lines.
    // token_compress_on means the iterator skips over consecutive '\n'. This should not be a
    // problem in normal /proc/diskstats output.
    for (string_split_iterator lineIt = string_split_iterator(
             data.begin(),
             data.end(),
             boost::token_finder([](char c) { return c == '\n'; }, boost::token_compress_on));
         lineIt != string_split_iterator();
         ++lineIt) {
        StringData line((*lineIt).begin(), (*lineIt).end());

        // Skip leading whitespace so that the split_iterator starts on non-whitespace otherwise we
        // get an empty first token. Device major numbers (the first number on each line) are right
        // aligned to 4 spaces and start from
        // single digits.
        auto beginNonWhitespace =
            std::find_if_not(line.begin(), line.end(), [](char c) { return c == ' '; });

        // Split the line by spaces since that is the only delimiter for diskstats files.
        // token_compress_on means the iterator skips over consecutive ' '.
        string_split_iterator partIt = string_split_iterator(
            beginNonWhitespace,
            line.end(),
            boost::token_finder([](char c) { return c == ' '; }, boost::token_compress_on));

        // Skip processing this line if the line is blank
        if (partIt == string_split_iterator()) {
            continue;
        }

        ++partIt;

        // Skip processing this line if we only have a device major number.
        if (partIt == string_split_iterator()) {
            continue;
        }

        ++partIt;

        // Skip processing this line if we only have a device major minor.
        if (partIt == string_split_iterator()) {
            continue;
        }

        StringData disk((*partIt).begin(), (*partIt).end());

        // Skip processing this line if we only have a block device name.
        if (partIt == string_split_iterator()) {
            continue;
        }

        ++partIt;

        // Check if the disk is in the list. /proc/diskstats will have extra disks, and may not have
        // the disk we want.
        if (disks.empty() || std::find(disks.begin(), disks.end(), disk) != disks.end()) {
            foundKeys = true;

            stats.clear();

            // Only generate a disk document if the disk has some activity. For instance, there
            // could be a CD-ROM drive that is not used.
            bool hasSomeNonZeroStats = false;

            for (size_t index = 0; partIt != string_split_iterator() && index < kDiskFieldCount;
                 ++partIt, ++index) {
                StringData stringValue((*partIt).begin(), (*partIt).end());

                uint64_t value;

                if (!parseNumberFromString(stringValue, &value).isOK()) {
                    value = 0;
                }

                if (value != 0) {
                    hasSomeNonZeroStats = true;
                }

                stats.push_back(value);
            }

            if (hasSomeNonZeroStats) {
                // Start a new document with disk as the name.
                BSONObjBuilder sub(builder->subobjStart(disk));

                for (size_t index = 0; index < stats.size() && index < kDiskFieldCount; ++index) {
                    sub.appendNumber(kDiskFields[index], static_cast<long long>(stats[index]));
                }

                sub.doneFast();
            }
        }
    }

    return foundKeys ? Status::OK()
                     : Status(ErrorCodes::NoSuchKey, "Failed to find any keys in diskstats string");
}

Status parseProcDiskStatsFile(StringData filename,
                              const std::vector<StringData>& disks,
                              BSONObjBuilder* builder) {
    auto swString = readFileAsString(filename);
    if (!swString.isOK()) {
        return swString.getStatus();
    }

    return parseProcDiskStats(disks, swString.getValue(), builder);
}

namespace {

/**
 * Is this a disk that is interesting to us? We only want physical disks, not multiple disk devices,
 * LVM2 devices, partitions, or RAM disks.
 *
 * A physical disk has a symlink to a directory at /sys/block/<device name>/device.
 *
 * Note: returns false upon any errors such as access denied.
 */
bool isInterestingDisk(const boost::filesystem::path& path) {
    boost::filesystem::path blockDevicePath(path);
    blockDevicePath /= kSysBlockDeviceDirectoryName;

    boost::system::error_code ec;
    auto statusSysBlock = boost::filesystem::status(blockDevicePath, ec);
    if (!boost::filesystem::exists(statusSysBlock)) {
        return false;
    }

    if (ec) {
        warning() << "Error checking directory '" << blockDevicePath.generic_string()
                  << "': " << ec.message();
        return false;
    }

    if (!boost::filesystem::is_directory(statusSysBlock)) {
        return false;
    }

    return true;
}

}  // namespace

std::vector<std::string> findPhysicalDisks(StringData sysBlockPath) {
    boost::system::error_code ec;
    auto sysBlockPathStr = sysBlockPath.toString();

    auto statusSysBlock = boost::filesystem::status(sysBlockPathStr, ec);
    if (ec) {
        warning() << "Error checking directory '" << sysBlockPathStr << "': " << ec.message();
        return {};
    }

    if (!(boost::filesystem::exists(statusSysBlock) &&
          boost::filesystem::is_directory(statusSysBlock))) {
        warning() << "Could not find directory '" << sysBlockPathStr << "': " << ec.message();
        return {};
    }

    std::vector<std::string> files;

    // Iterate through directories in /sys/block. The directories in this directory can be physical
    // block devices (like SSD or HDD) or virtual devices like the LVM2 device mapper or a multiple
    // disk device. It does not contain disk partitions.
    boost::filesystem::directory_iterator di(sysBlockPathStr, ec);
    if (ec) {
        warning() << "Error getting directory iterator '" << sysBlockPathStr
                  << "': " << ec.message();
        return {};
    }

    for (; di != boost::filesystem::directory_iterator(); di++) {
        auto path = (*di).path();

        if (isInterestingDisk(path)) {
            files.push_back(path.filename().generic_string());
        }
    }

    return files;
}

}  // namespace procparser
}  // namespace mongo

max_stars_repo_name: bmhoang/mongodb

max_issues_repo_name: bmhoang/mongodb

max_forks_repo_name: bmhoang/mongodb


text:
/*
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you under the Apache License, Version 2.0 (the
 *    "License"); you may not use this file except in compliance
 *    with the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing,
 *    software distributed under the License is distributed on an
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *    KIND, either express or implied.  See the License for the
 *    specific language governing permissions and limitations
 *    under the License.
 * ====================================================================
 */

#include <boost/test/unit_test.hpp>

#include <codecvt>
#include <cstdint>
#include <locale>
#include <random>
#include <stdexcept>
#include <string>
#include <vector>

#include "private/svn_utf_private.h"
#include "../src/aprwrap.hpp"

namespace {
std::string to_utf8(const std::u32string& str)
{
  static const int32_t endiancheck = 0xa5cbbc5a;
  static const bool arch_big_endian =
    (reinterpret_cast<const char*>(&endiancheck)[sizeof(endiancheck) - 1] == '\x5a');

  apr::pool scratch_pool;
  const svn_string_t* utf8_string;

  auto err = svn_utf__utf32_to_utf8(
      &utf8_string,
      reinterpret_cast<const apr_int32_t*>(str.c_str()),
      str.size(), arch_big_endian, scratch_pool.get(), scratch_pool.get());
  if (err)
    {
      svn_error_clear(err);
      throw std::range_error("bad unicode code point");
    }
  return std::string(utf8_string->data, utf8_string->len);
}

template<typename C> struct codepoint;
template<> struct codepoint<void>
{
  using src_type = char32_t;
  static constexpr std::uint_least32_t min = 0;
  static constexpr std::uint_least32_t max = 0x10ffff;
  static constexpr std::uint_least32_t surrogate_min = 0xd800;
  static constexpr std::uint_least32_t surrogate_max = 0xdfff;
};

template<> struct codepoint<char32_t> : public codepoint<void>
{
  using dst_type = char32_t;
  static std::u32string convert(const std::u32string& str)
    {
      return str;
    };
};

template<> struct codepoint<char16_t> : public codepoint<void>
{
  using dst_type = char16_t;
  static std::u16string convert(const std::u32string& str)
    {
      std::wstring_convert<std::codecvt_utf8_utf16<dst_type>, dst_type> u;
      return u.from_bytes(to_utf8(str));
    }
};

template<> struct codepoint<wchar_t> : public codepoint<void>
{
  using dst_type = wchar_t;

#ifdef WIN32
  // Be conservative, use UCS-2 for wchar_t on Windows
  static_assert(sizeof(wchar_t) == sizeof(char16_t),
                "I thought we had 2-byte wide chars on Windows");
  static constexpr std::uint_least32_t max = 0xffff;
#endif

  static std::wstring convert(const std::u32string& str)
    {
#ifdef WIN32
      const auto from_utf8 =
        [](const std::string& sstr)
          {
            apr::pool scratch_pool;
            const wchar_t* result;
            auto err = svn_utf__win32_utf8_to_utf16(
                &result, sstr.c_str(), nullptr, scratch_pool.get());
            if (err)
              {
                svn_error_clear(err);
                throw std::range_error("bad conversion to utf16");
              }
            return std::wstring(result);
          }
#else
      std::wstring_convert<std::codecvt_utf8<dst_type>, dst_type> u;
      const auto from_utf8 = [&u](const std::string& sstr)
                               {
                                 return u.from_bytes(sstr);
                               };
#endif
      return from_utf8(to_utf8(str));
    }
};

// Generate random strings.
template<typename C>
inline std::vector<std::basic_string<C>> generate_string_data(int count)
{
  using cp = codepoint<C>;
  std::mt19937 mt{std::random_device()()};
  std::uniform_int_distribution<> cgen{typename cp::src_type(cp::min),
                                       typename cp::src_type(cp::max)};
  std::uniform_int_distribution<> lgen{7U, 31U};

  std::vector<std::basic_string<C>> result;
  result.reserve(count);

  for (int i = 0; i < count; ++i)
    {
      const unsigned len = lgen(mt);

      std::u32string val;
      val.reserve(len);

      for (unsigned j = 0; j < len; ++j)
        {
        repeat:
          auto c = cgen(mt);
          if (uint_least32_t(c) >= cp::surrogate_min
              && uint_least32_t(c) <= cp::surrogate_max)
            goto repeat;
          val.push_back(c);
        }
      result.emplace_back(cp::convert(val));
    }
  return result;
}
} // anonymous namespace

#include "../src/private/strings_private.hpp"

#include "fixture_init.hpp"

namespace svn = ::apache::subversion::svnxx;
namespace impl = ::apache::subversion::svnxx::impl;

BOOST_AUTO_TEST_SUITE(strings,
                      * boost::unit_test::fixture<init>());

BOOST_AUTO_TEST_CASE(wstring_conversion_roundtrip)
{
  for (const auto& sample : generate_string_data<wchar_t>(100))
    BOOST_TEST((sample == impl::convert<wchar_t>(impl::convert(sample))));
}

BOOST_AUTO_TEST_CASE(u16string_conversion_roundtrip)
{
  for (const auto& sample : generate_string_data<char16_t>(100))
    BOOST_TEST((sample == impl::convert<char16_t>(impl::convert(sample))));
}

BOOST_AUTO_TEST_CASE(u32string_conversion_roundtrip)
{
  for (const auto& sample : generate_string_data<char32_t>(100))
    BOOST_TEST((sample == impl::convert<char32_t>(impl::convert(sample))));
}

BOOST_AUTO_TEST_CASE(nulchar)
{
  const std::string nulstr("\0", 1);
  const std::wstring wnulstr(L"\0", 1);
  const std::u16string u16nulstr(u"\0", 1);
  const std::u32string u32nulstr(U"\0", 1);

  BOOST_TEST(nulstr.size() == 1);
  BOOST_TEST(wnulstr.size() == 1);
  BOOST_TEST(u16nulstr.size() == 1);
  BOOST_TEST(u32nulstr.size() == 1);

  BOOST_TEST(impl::convert<wchar_t>(nulstr).size() == 1);
  BOOST_TEST(impl::convert<char16_t>(nulstr).size() == 1);
  BOOST_TEST(impl::convert<char32_t>(nulstr).size() == 1);

  BOOST_TEST((impl::convert<wchar_t>(nulstr) == wnulstr));
  BOOST_TEST((impl::convert<char16_t>(nulstr) == u16nulstr));
  BOOST_TEST((impl::convert<char32_t>(nulstr) == u32nulstr));

  BOOST_TEST(impl::convert(wnulstr).size() == 1);
  BOOST_TEST(impl::convert(u16nulstr).size() == 1);
  BOOST_TEST(impl::convert(u32nulstr).size() == 1);

  BOOST_TEST((impl::convert(wnulstr) == nulstr));
  BOOST_TEST((impl::convert(u16nulstr) == nulstr));
  BOOST_TEST((impl::convert(u32nulstr) == nulstr));
}

BOOST_AUTO_TEST_SUITE_END();

ext: cpp


text:
#pragma once

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <chrono>

class Barrier
{
public:
	Barrier(size_t number);

	void wait();
    bool timedWait(std::chrono::microseconds timeout);
	void reset();

private:
	bool step();

	boost::interprocess::interprocess_condition condition;
	boost::interprocess::interprocess_mutex     mutex;
	size_t number;
	size_t counter;
};

ext: hpp

max_stars_repo_name: AlloSphere-Research-Group/AlloStreamer

max_issues_repo_name: AlloSphere-Research-Group/AlloStreamer

max_forks_repo_name: AlloSphere-Research-Group/AlloStreamer


text:
// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache 2.0 license.
// Please see LICENSE file in the project root for terms.
#ifndef CAFFE_DISTRI_SOCKET_HPP_
#define CAFFE_DISTRI_SOCKET_HPP_

#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include "threadpool.hpp"
#include "caffe/caffe.hpp"
#include "caffe/common.hpp"
#include "caffe/util/blocking_queue.hpp"

using std::vector;
using std::map;
using std::string;

namespace caffe {
class SocketChannel;
class SocketAdapter {
 public:
  volatile int port;
  explicit SocketAdapter(vector<shared_ptr<SocketChannel> > * channels);
  vector<shared_ptr<SocketChannel> > *channels;
  void start_sockt_srvr();
  string address(){
    char self_name[256];
    char port_buf[256];
    gethostname(self_name, 256);
    snprintf(port_buf, sizeof(port_buf), "%d", port);
    string address = self_name;
    address +=":";
    address += port_buf;
    return address;
  }
};

enum message_type {DIFF, DATA};
class QueuedMessage {
 public:
  int rank;
  int iter_count_;
  message_type type;
  int size;
  uint8_t* buffer;
  QueuedMessage(int _rank, int iter_count, message_type type, int size, uint8_t* buffer);
};

class SocketBuffer {
 public:
  SocketBuffer(int rank, int iterCount, message_type mt, SocketChannel* channel,
               uint8_t* buffer, size_t size, uint8_t* addr);
  uint8_t* addr() const {
    return addr_;
  }
  uint8_t* buffer() const {
    return buffer_;
  }
  const size_t size() const {
    return size_;
  }
  // Synchronously writes content to remote peer
  void Write();
  SocketBuffer* Read();
 //protected:
  SocketChannel* channel_;
  uint8_t* addr_;
  uint8_t* buffer_;
  /*const*/ size_t size_;
  int rank;
  message_type mt_;
  int iterCount_;
  string info() {
      std::stringstream sstm;
      sstm << "Iteration: " << iterCount_;
      return sstm.str();
  }
};

class SocketChannel {
 private:
  int connect_to_peer(string to_peer, string to_port);
 public:
  SocketChannel();
  ~SocketChannel();
  void Connect(string peer);
  int client_fd;
  caffe::BlockingQueue<QueuedMessage*> receive_queue;
  int serving_fd;
  int port_no;
  string peer_name;
  size_t size;
  mutable boost::mutex write_mutex_;
  string peer_info() {
      std::stringstream sstm;
      sstm << "peer_name: " << peer_name << " port_no: " << port_no
           << " client_fd: " << client_fd << " serving_fd: " << serving_fd;
      return sstm.str();
  }

  static boost::threadpool::pool tp;

  static caffe::BlockingQueue<QueuedMessage*> global_diff_receive_queue;

  static caffe::BlockingQueue<QueuedMessage*> global_data_receive_queue;

  static shared_ptr<SocketBuffer> read_next(const vector<shared_ptr<SocketBuffer> > &buffers, const message_type &mt) {
  	// Pop the message from local queue
  	QueuedMessage* qm =
  			reinterpret_cast<QueuedMessage*>(
  					(mt == DIFF ? global_diff_receive_queue : global_data_receive_queue)
  					.pop(string("trying to get message from queue")));
    LOG(INFO) << "Iteration: " << qm->iter_count_ <<  " got a message from: " << " , " << buffers[qm->rank]->channel_->peer_info();
  	shared_ptr<SocketBuffer> sb_sptr = buffers[qm->rank];
  	memcpy(sb_sptr->addr_, qm->buffer, qm->size);
  	// Free up the buffer and the wrapper object
  	delete qm->buffer;
  	delete qm;
  	return sb_sptr;
  }
};

class Socket {
 public:
    explicit Socket(const string &host, int port, bool listen);
    ~Socket();
    int descriptor() { return fd_; }

    shared_ptr<Socket> accept();
    size_t read(void *buff, size_t size);
    size_t write(void *buff, size_t size);

    uint64_t readInt() {
        // TODO loop for partial reads or writes
        uint64_t value;
        CHECK_EQ(read(&value, sizeof(uint64_t)), sizeof(uint64_t));
        return value;
    }
    void writeInt(uint64_t value) {
        CHECK_EQ(write(&value, sizeof(uint64_t)), sizeof(uint64_t));
    }
    string readStr() {
        size_t size = readInt();
        string str(size, ' ');
        CHECK_EQ(read(&str[0], size), size);
        return str;
    }
    void writeStr(const string &str) {
        writeInt(str.size());
        CHECK_EQ(write(const_cast<void*>(reinterpret_cast<const void *>
                      (str.c_str())), str.size()), str.size());
    }

 protected:
    explicit Socket(int fd) : fd_(fd) { }
    int fd_;

    DISABLE_COPY_AND_ASSIGN(Socket);
};
}  // namespace caffe

#endif


text:
#ifndef META_PROCESS_H
#define META_PROCESS_H

#include <boost/process.hpp>

namespace bp = boost::process;

namespace meta_classes {
class MetaProcess {
  bp::child process;

 public:
  bp::opstream output;
  bp::ipstream input;

  MetaProcess() = default;

  MetaProcess(std::string_view process_name) {
    if (!process_name.empty()) {
      this->process = bp::child(process_name.data(), bp::std_out > input,
                                bp::std_in < output);
    }
  }

  // NOTE: something is wrong with the defaut move of basic_opstream so we move
  // the pipe
  MetaProcess(MetaProcess&& p)
      : process{std::move(p.process)},
        output{std::move(p.output.pipe())},
        input{std::move(p.input.pipe())} {}

  MetaProcess& operator=(MetaProcess&& p) {
    process = std::move(p.process);
    output = std::move(p.output.pipe());
    input = std::move(p.input.pipe());

    return *this;
  }

  bool ok() { return process.running(); }

  void wait() noexcept {
    std::error_code e;
    process.wait(e);
  }
};
}  // namespace meta_classes

#endif  //! META_PROCESS_H

max_stars_repo_name: OBorce/zero-preprocessor

max_issues_repo_name: OBorce/zero-preprocessor

max_forks_repo_name: OBorce/zero-preprocessor


text:
/*
Copyright (c) Members of the EGEE Collaboration. 2004.
See http://www.eu-egee.org/partners/ for details on the copyright
holders.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

//
// File: operations.cpp
// Author: Giuseppe Avellino <egee@datamat.it>
//

#include <fstream>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <set>

// Boost
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include "boost/filesystem/path.hpp"

#include "common.h"
#include "operations.h"
#include "configuration.h"
#include "structconverter.h"

#include "common/src/utilities/manipulation.h"

// Utilities
#include "utilities/utils.h"

// Eventlogger
#include "eventlogger/expdagad.h"
#include "eventlogger/eventlogger.h"

#include "security/vomsauthn.h"
#include "security/authorizer.h"
#include "security/gaclmanager.h"
#include "security/delegation.h"

//Logger
#include "utilities/logging.h"
#include "glite/wms/common/logger/edglog.h"
#include "glite/wms/common/logger/logger_utils.h"

#include "commands/listfiles.h"

// WMP Exceptions
#include "utilities/wmpexceptions.h"
#include "utilities/wmpexception_codes.h"

// RequestAd
#include "glite/jobid/JobId.h"
#include "glite/jdl/PrivateAttributes.h"
#include "glite/jdl/JDLAttributes.h"
#include "glite/jdl/jdl_attributes.h"
#include "glite/jdl/DAGAdManipulation.h"
#include "glite/jdl/RequestAdExceptions.h"

// Logging and Bookkeeping
#include "glite/lb/JobStatus.h"

// Configuration
#include "glite/wms/common/configuration/Configuration.h"
#include "common/src/configuration/NSConfiguration.h"

using namespace std;
using namespace glite::lb; // JobStatus
using namespace glite::jdl; // DagAd, AdConverter
using namespace glite::jobid; //JobId

using namespace glite::wms::wmproxy::server;
using namespace glite::wms::wmproxy::utilities; //Exception
using namespace glite::wms::wmproxy::eventlogger;
using namespace glite::wms::common::configuration; // Configuration

namespace utils      = glite::wmsutils::classads;
namespace logger         = glite::wms::common::logger;
namespace configuration  = glite::wms::common::configuration;
namespace wmputilities   = glite::wms::wmproxy::utilities;
namespace eventlogger    = glite::wms::wmproxy::eventlogger;
namespace security     = glite::wms::wmproxy::security;

// Global variables for configuration
extern WMProxyConfiguration conf;

// WMProxy software version
const std::string WMP_VERSION = WMP_SOFTWARE_VERSION;

// DONE job output file
const std::string MARADONA_FILE = "Maradona.output";

// Perusal functionality
const std::string PERUSAL_FILE_2_PEEK_NAME = "files2peek";
const std::string TEMP_PERUSAL_FILE_NAME = "tempperusalfile";
const std::string PERUSAL_DATE_INFO_SEPARATOR = "-";

// File size limit of globus URL copy
const long FILE_TRANSFER_SIZE_LIMIT = 2147000000;
// 2 Giga = 2 * 1.073.741.824 = 2.147.483.648

// Defining File Separator
#ifdef WIN
// Windows File Separator
const std::string FILE_SEPARATOR = "\\";
#else
// Linux File Separator
const std::string FILE_SEPARATOR = "/";
#endif

const std::string ALL_PROTOCOLS = "all";
const std::string DEFAULT_PROTOCOL = "default";

namespace {

// a valid delegated credential is not needed for some operations
// (retrieve the output and job information in general) but we need to make
// sure that such information, i.e. the output file list, is returned
// only for jobs belonging to same DN/FQAN (in principle the file transfer
// would be denied, in the end, but we don't want people to see each
// other's file names or job related information either)
void check_ownership(std::string const& jid) {
   std::string reg_jdl(
      wmputilities::readTextFile(wmputilities::getJobJDLExistingStartPath(jid))
   );
   boost::scoped_ptr<classad::ClassAd> ad(utils::parse_classad(reg_jdl));
   // get DN and FQAN from the attributes of the stored JDL
   std::string voms_fqan;
   ad->EvaluateAttrString(JDLPrivate::VOMS_FQAN, voms_fqan);
   std::string dn;
   ad->EvaluateAttrString(JDL::CERT_SUBJ, dn);
   // and compare them with DN and FQAN returned by mod_gridsite (retrieved from the submitter)
   std::vector<std::string> fqans_v(wmputilities::getGridsiteFQANs());
   bool matched_fqan(std::find(fqans_v.begin(), fqans_v.end(), voms_fqan) != fqans_v.end());
  if (dn != wmputilities::getDN_SSL() || !matched_fqan) {
      string msg("getOutputFileList operation not allowed for presented DN/FQANs");
      edglog(error) << msg << ": " << jid << endl;
      throw JobOperationException(__FILE__, __LINE__, "getOutputFileList()",
                                  wmputilities::WMS_OPERATION_NOT_ALLOWED, msg);
   }
}

}

//
// WM Web Service available operations
//

// To get more information see WMProxy service wsdl file
void
getVersion(getVersionResponse& getVersion_response)
{
   GLITE_STACK_TRY("getVersion()");
   edglog_fn("wmpoperations::getVersion");

   initWMProxyOperation("getVersion");
   getVersion_response.version = WMP_VERSION;
   edglog(info) << "Version retrieved: "<< getVersion_response.version << endl;
   GLITE_STACK_CATCH();
}

void
getJDL(const std::string& job_id, JdlType jdltype, getJDLResponse& getJDL_response)
{
   GLITE_STACK_TRY("getJDL()");
   edglog_fn("wmpoperations::getJDL");
   edglog(debug) << "getJDL requested for job: " << job_id <<endl;

   initWMProxyOperation("getJDL");
   check_ownership(job_id);

   getJDL_response.jdl = "";
   JobId jid(job_id);
   switch (jdltype) {
   case WMS_JDL_ORIGINAL:
      getJDL_response.jdl = wmputilities::readTextFile(
                               wmputilities::getJobJDLOriginalPath(jid));
      break;
   case WMS_JDL_REGISTERED:
      getJDL_response.jdl = wmputilities::readTextFile(
                               wmputilities::getJobJDLExistingStartPath(jid));
      break;
   default:
      break;
   }
   edglog(debug) << "retrieved JDL: " << getJDL_response.jdl << endl;
   GLITE_STACK_CATCH();
}

void
getMaxInputSandboxSize(getMaxInputSandboxSizeResponse
                       &getMaxInputSandboxSize_response)
{
   GLITE_STACK_TRY("getMaxInputSandboxSize()");
   edglog_fn("wmpoperations::getMaxInputSandboxSize");

   initWMProxyOperation("getMaxInputSandboxSize");
   security::do_authZ("getMaxInputSandboxSize");
   try {
      getMaxInputSandboxSize_response.size =
         // WARNING: Temporal cast TBD
         // WARNING: double temporarely casted into long (soon long will be returned directly
         // currently parameter is a double - casting needed
         (long)conf.wmp_config->max_input_sandbox_size();
   } catch (exception& ex) {
      edglog(severe)<<"Unable to get max input sandbox size: "
                    <<ex.what()<<endl;
      throw JobOperationException(__FILE__, __LINE__,
                                  "getMaxInputSandboxSize()", wmputilities::WMS_CONFIGURATION_ERROR,
                                  "Unable to get max input sandbox size");
   }

   GLITE_STACK_CATCH();
}

void
getSandboxDestURI(getSandboxDestURIResponse& getSandboxDestURI_response,
                  const string& jid, const string& protocol)
{
   GLITE_STACK_TRY("getSandboxDestURI()");
   edglog_fn("wmpoperations::getSandboxDestURI");

   edglog(debug) << "getSandboxDestURI requested for job: " << jid << endl;
   initWMProxyOperation("getSandboxDestURI");
   security::do_authZ_jobid("getSandboxDestURI", jid);
   getSandboxDestURI_response.path = new StringList;
   getSandboxDestURI_response.path->Item = new vector<string>(0);
   JobId jobid(jid);
   vector<string> *jobdiruris = getJobDirectoryURIsVector(conf.getProtocols(),
                                conf.getDefaultProtocol(), conf.getDefaultPort(), conf.getHTTPSPort(),
                                jid, protocol, "input");

   getSandboxDestURI_response.path->Item = jobdiruris;

   GLITE_STACK_CATCH();
}

void
getSandboxBulkDestURI(getSandboxBulkDestURIResponse& getSandboxBulkDestURI_response,
                      const string& jid, const string& protocol)
{
   GLITE_STACK_TRY("getSandboxBulkDestURI()");
   edglog_fn("wmpoperations::getSandboxBulkDestURI");

   edglog(debug) << "getSandboxBulkDestURI requested for job: " << jid << endl;
   initWMProxyOperation("getSandboxBulkDestURI");
   security::do_authZ_jobid("getSandboxBulkDestURI", jid);
   // Initializing logger
   WMPEventLogger wmplogger(wmputilities::getEndpoint());
   wmplogger.setLBProxy(conf.isLBProxyAvailable(), wmputilities::getDN_SSL());
   JobId jobid(jid);
   wmplogger.setUserProxy(wmputilities::getJobDelegatedProxyPath(jobid));
   wmplogger.init_and_set_logging_job("", 0, &jobid);

   DestURIsStructType *destURIsStruct = new DestURIsStructType();
   destURIsStruct->Item = new vector<DestURIStructType*>(0);

   // Getting job status to get children number
   JobStatus status = wmplogger.getStatus(true);
   vector<string> jids = status.getValStringList(JobStatus::CHILDREN);
   edglog(debug)<<"Children count: "<<status.getValInt(JobStatus::CHILDREN_NUM)<<endl;
   vector<string>::iterator jidsiterator = jids.begin();
   jids.insert(jidsiterator, 1, jid);

   vector<string>::iterator iter = jids.begin();
   vector<string>::iterator const end = jids.end();
   for (; iter != end; ++iter) {
      vector<string> *uris = getJobDirectoryURIsVector(conf.getProtocols(),
                             conf.getDefaultProtocol(), conf.getDefaultPort(), conf.getHTTPSPort(),
                             *iter, protocol, "input");

      DestURIStructType *destURIStruct = new DestURIStructType();
      destURIStruct->id = *iter;
      destURIStruct->destURIs = uris;
      destURIsStruct->Item->push_back(destURIStruct);
   }
   getSandboxBulkDestURI_response.destURIsStruct = destURIsStruct;

   GLITE_STACK_CATCH();
}

void
getQuota(getQuotaResponse& getQuota_response)
{
   GLITE_STACK_TRY("getQuota()");
   edglog_fn("wmpoperations::getQuota");

   initWMProxyOperation("getQuota");
   std::string user_name = security::do_authZ("getQuota"); // throws
   pair<long, long> quotas;
   if (!wmputilities::getUserQuota(quotas, user_name)) {
      edglog(severe)<<"Unable to get total quota"<<endl;
      throw FileSystemException(__FILE__, __LINE__,
                                "getQuota()", wmputilities::WMS_IS_FAILURE,
                                "Unable to get total quota");
   }
   getQuota_response.softLimit = quotas.first;
   getQuota_response.hardLimit = quotas.second;

   GLITE_STACK_CATCH();
}

void
getFreeQuota(getFreeQuotaResponse& getFreeQuota_response)
{
   GLITE_STACK_TRY("getFreeQuota()");
   edglog_fn("wmpoperations::getFreeQuota");

   initWMProxyOperation("getFreeQuota");
   std::string user_name = security::do_authZ("getFreeQuota"); //throws
   pair<long, long> quotas;
   if (!wmputilities::getUserFreeQuota(quotas, user_name)) {
      edglog(severe)<<"Unable to get free quota"<<endl;
      throw FileSystemException(__FILE__, __LINE__, "getFreeQuota()",
                                wmputilities::WMS_IS_FAILURE, "Unable to get free quota");
   }
   getFreeQuota_response.softLimit = quotas.first;
   getFreeQuota_response.hardLimit = quotas.second;

   GLITE_STACK_CATCH();
}

void
getOutputFileList(getOutputFileListResponse& getOutputFileList_response,
                  const string& jid, const string& protocol)
{
   int fd = -1;
   try {
      edglog_fn("wmpoperations::getOutputFileList");
      edglog(debug) << "getOutputFileList requested for job: " << jid << endl;
      initWMProxyOperation("getOutputFileList");

      check_ownership(jid);

      // File descriptor for operation lock system:
      // During jobPurge operation, a check to getOutputFileList lock file is done
      // If a getOutputFileList is requested, jobPurge operation is aborted
      JobId jobid(jid);
      fd = wmputilities::operationLock(
              wmputilities::getGetOutputFileListLockFilePath(jobid),
              "getOutputFileList");

      string jobdirectory = wmputilities::getJobDirectoryPath(jobid);

      // Checking for maradona file, created if and only if the job is in DONE state
      // isn't the check on the status already done in the client?
      edglog(info)<<"Searching for MARADONA file: "<<jobdirectory + FILE_SEPARATOR
                   + MARADONA_FILE<<endl;
      if (!wmputilities::fileExists(jobdirectory + FILE_SEPARATOR + MARADONA_FILE)) {
         // MARADONA file NOT found
         // Initializing logger
         WMPEventLogger wmplogger(wmputilities::getEndpoint());
         wmplogger.setLBProxy(conf.isLBProxyAvailable(), wmputilities::getDN_SSL());
         wmplogger.init_and_set_logging_job("", 0, &jobid);

         string userProxyJob =  wmputilities::getJobDelegatedProxyPath(jobid);

         long timeleft = 0;
         try {
           security::getProxyTimeLeft(userProxyJob);
         } catch (glite::wmsutils::exception::Exception& ex) {
         }

         // Setting user proxy, checks whether the user proxy is still valid,
         // switching to the host proxy if the user proxy expired
         if ( timeleft <= 1) {
            string hostProxy = configuration::Configuration::instance()->common()->host_proxy_file();
            try {
               wmplogger.setUserProxy(hostProxy); // throws
            } catch (glite::wmsutils::exception::Exception& ex) {
               throw JobOperationException(__FILE__, __LINE__, "getOutputFileList()",
                  wmputilities::WMS_OPERATION_NOT_ALLOWED,
                  "neither user nor service certificates are valid, cannot log CLEAR event, halting");
            }
         } else {
            wmplogger.setUserProxy(userProxyJob); // throws
         }

         // Getting job status to check if is a job and its status
         JobStatus status = wmplogger.getStatus(false);
         if (status.getValInt(JobStatus::CHILDREN_NUM) != 0) {
            string msg = "getOutputFileList operation not allowed for dag or collection type";
            edglog(error)<<msg<<": "<<jobid.toString()<<endl;
            throw JobOperationException(__FILE__, __LINE__, "getOutputFileList()",
                  wmputilities::WMS_OPERATION_NOT_ALLOWED, msg);
         }
         // getOutputFileList allowed when:
         // STATUS is eithr Done (yet done_code!= FAILED) or Aborted
         if (((status.status == JobStatus::DONE)
               &&(status.getValInt(JobStatus::DONE_CODE) == JobStatus::DONE_CODE_FAILED))
               || ((status.status != JobStatus::DONE) && (status.status != JobStatus::ABORTED))) {
            edglog(error)<<
                  "Job current status doesn't allow getOutputFileList operation"<<endl;
            throw JobOperationException(__FILE__, __LINE__,
                  "getOutputFileList()", wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                        "Job current status doesn't allow getOutputFileList operation");
         }
      }  // else ...... If MARADONA file is found, output files are definitely present on WMS
      string outputpath = wmputilities::getOutputSBDirectoryPath(jid);
      vector<string> *jobdiruris = getJobDirectoryURIsVector(conf.getProtocols(),
                                   conf.getDefaultProtocol(), conf.getDefaultPort(), conf.getHTTPSPort(),
                                   jid, protocol, "output");
      unsigned int jobdirsize = jobdiruris->size();

      // Searching files inside directory
      const boost::filesystem::path p(outputpath, boost::filesystem::native);
      std::vector<std::string> found;
      glite::wms::wmproxy::commands::list_files(p, found);
      edglog(debug)<<"List size is (hidden files included): "
                   <<found.size()<<endl;

      // Creating the list
      StringAndLongList *list = new StringAndLongList();
      vector<StringAndLongType*> *file = new vector<StringAndLongType*>;
      StringAndLongType *item = NULL;
      string filename;
      long filesize;

      vector<string>::iterator iter = found.begin();
      vector<string>::iterator const end = found.end();
      for (; iter != end; ++iter) {
         // Checking for hidden files
         filename = wmputilities::getFileName(string(*iter));
         if ((filename != MARADONA_FILE) && (filename
                                             != security::GaclManager::WMPGACL_DEFAULT_FILE)) {
            filesize = wmputilities::computeFileSize(*iter);
            edglog(debug)<<"Inserting file name: " <<filename<<endl;
            edglog(debug)<<"Inserting file size: " <<filesize<<endl;
            for (unsigned int i = 0; i < jobdirsize; i++) {
               item = new StringAndLongType();
               item->name = (*jobdiruris)[i] + FILE_SEPARATOR + filename;
               item->size = filesize;
               file->push_back(item);
            }
         }
      }
      list->file = file;
      getOutputFileList_response.OutputFileAndSizeList = list;
      edglog(debug)<<"Successfully retrieved files: "<<found.size()<<endl;
      edglog(debug)<<"Removing lock..."<<std::endl;
      wmputilities::operationUnlock(fd);
   } catch (glite::wmsutils::exception::Exception const& e) {
      edglog(debug)<<"Removing lock..."<<std::endl;
      wmputilities::operationUnlock(fd);
      edglog(debug) << "wmsutils::Exception: " << e.what() << std::endl;
      throw e;
   } catch (exception& ex) {
      edglog(debug)<<"Removing lock..."<<std::endl;
      wmputilities::operationUnlock(fd);
      edglog(debug)<<"std::exception: "<<ex.what()<<std::endl;
      throw ex;
   }
}

void
getJobTemplate(getJobTemplateResponse& getJobTemplate_response,
               JobTypeList jobType, const string& executable,
               const string& arguments, const string& requirements, const string& rank)
{
   GLITE_STACK_TRY("getJobTemplate()");
   edglog_fn("wmpoperations::getJobTemplate");

   initWMProxyOperation("getJobTemplate");
   security::do_authZ("getJobTemplate");

   getJobTemplate_response.jdl =
      (AdConverter::createJobTemplate(convertJobTypeListToInt(jobType),
                                      executable, arguments, requirements, rank))->toString();

   edglog(debug)<<"Job Template successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getDAGTemplate(getDAGTemplateResponse& getDAGTemplate_response,
               GraphStructType dependencies, const string& requirements,
               const string& rank)
{
   GLITE_STACK_TRY("getDAGTemplate()");
   edglog_fn("wmpoperations::getDAGTemplate");

   initWMProxyOperation("getDAGTemplate");
   security::do_authZ("getDAGTemplate");

   getDAGTemplate_response.jdl = AdConverter::createDAGTemplate(
                                    convertGraphStructTypeToNodeStruct(dependencies),
                                    requirements, rank)->toString();

   edglog(debug)<<"DAG Template successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getCollectionTemplate(getCollectionTemplateResponse
                      &getCollectionTemplate_response, int jobNumber,
                      const string& requirements, const string& rank)
{
   GLITE_STACK_TRY("getCollectionTemplate()");
   edglog_fn("wmpoperations::getCollectionTemplate");

   initWMProxyOperation("getCollectionTemplate");
   security::do_authZ("getCollectionTemplate");
   getCollectionTemplate_response.jdl =
      AdConverter::createCollectionTemplate(jobNumber, requirements,
            rank)->toString();

   edglog(debug)<<"Collection Template successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getIntParametricJobTemplate(getIntParametricJobTemplateResponse
                            &getIntParametricJobTemplate_response, StringList *attributes, int param,
                            int parameterStart, int parameterStep, const string& requirements,
                            const string& rank)
{
   GLITE_STACK_TRY("getIntParametricJobTemplate()");
   edglog_fn("wmpoperations::getIntParametricJobTemplate");

   initWMProxyOperation("getIntParametricJobTemplate");
   security::do_authZ("getIntParametricJobTemplate");

   getIntParametricJobTemplate_response.jdl =
      AdConverter::createIntParametricTemplate(*(attributes->Item), param,
            parameterStart, parameterStep, requirements, rank)->toString();

   edglog(debug)<<"Int Parametric Job Template successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getStringParametricJobTemplate(getStringParametricJobTemplateResponse
                               &getStringParametricJobTemplate_response, StringList *attributes,
                               StringList *param, const string& requirements, const string& rank)
{
   GLITE_STACK_TRY("getStringParametricJobTemplate()");
   edglog_fn("wmpoperations::getStringParametricJobTemplate");

   initWMProxyOperation("getStringParametricJobTemplate");
   security::do_authZ("getStringParametricJobTemplate");
   getStringParametricJobTemplate_response.jdl =
      AdConverter::createStringParametricTemplate(*(attributes->Item),
            *(param->Item), requirements, rank)->toString();

   edglog(debug)<<"String Parametric Job Template successful"<<endl;

   GLITE_STACK_CATCH();
}

// DELEGATION OPERATION DESCRIPTION

void
getDelegationVersion(getVersionResponse& getVersion_response)
{
   GLITE_STACK_TRY("getDelegationVersion()");
   edglog_fn("wmpoperations::getDelegationVersion");

   initWMProxyOperation("getDelegationVersion");
   security::do_authZ("getDelegationVersion");
   getVersion_response.version = security::getDelegationVersion();
   edglog(info)<<"Version retrieved: "<<getVersion_response.version<<endl;

   GLITE_STACK_CATCH();
}

void
getDelegationIntefaceVersion(getVersionResponse& getVersion_response)
{
   GLITE_STACK_TRY("getDelegationInterfaceVersion()");
   edglog_fn("wmpoperations::getDelegationInterfaceVersion");

   initWMProxyOperation("getDelegationInterfaceVersion");
   security::do_authZ("getDelegationVersion");
   getVersion_response.version = security::getDelegationInterfaceVersion();
   edglog(info)<<"Version retrieved: "<<getVersion_response.version<<endl;

   GLITE_STACK_CATCH();
}

void
getProxyReq(getProxyReqResponse& getProxyReq_response,
            const string& delegation_id)
{
   GLITE_STACK_TRY("getProxyReq()");
   edglog_fn("wmpoperations::getProxyReq");

   initWMProxyOperation("getProxyReq");
   security::do_authZ("getProxyReq"); // the delegated proxy is not there

#ifndef GRST_VERSION
   if (delegation_id == "") {
      edglog(error)<<"Empty delegation id not allowed with delegation 1"<<endl;
      throw ProxyOperationException(__FILE__, __LINE__,
                                    "getProxyReq()", wmputilities::WMS_INVALID_ARGUMENT,
                                    "Provided delegation id not valid");
   }
#endif

   getProxyReq_response.request =
      security::getProxyRequest(delegation_id);
   edglog(debug)<<"Proxy request successful"<<endl;

   GLITE_STACK_CATCH();
}

void
putProxy(putProxyResponse& putProxyReq_response, const string& delegation_id,
         const string& proxy)
{
   GLITE_STACK_TRY("putProxy()");
   edglog_fn("wmpoperations::putProxy");

   initWMProxyOperation("putProxy");
   security::do_authZ("putProxy"); // the delegated proxy is not there

   security::putProxy(delegation_id, proxy);
   edglog(debug)<<"Proxy put successful"<<endl;

   GLITE_STACK_CATCH();
}

void
renewProxyReq(string& renewProxyReq_response,
              const string& delegation_id)
{
   GLITE_STACK_TRY("renewProxyReq()");
   edglog_fn("wmpoperations::renewProxyReq");

   initWMProxyOperation("renewProxyReq");
   security::do_authZ("renewProxyReq", delegation_id);

   renewProxyReq_response = security::renewProxyRequest(delegation_id);
   edglog(debug)<<"Proxy renewed successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getNewProxyReq(pair<string, string> &retpair)
{
   GLITE_STACK_TRY("getNewProxyReq()");
   edglog_fn("wmpoperations::getNewProxyReq");

   initWMProxyOperation("getNewProxyReq");
   security::do_authZ("getNewProxyReq");

   edglog(debug)<<"found delegationID: "<<retpair.first<<endl;
   edglog(debug)<<"found proxyRequest "<<retpair.second<<endl;
   edglog(debug)<<"Proxy requested successful"<<endl;

   GLITE_STACK_CATCH();
}

void
destroyProxy(const string& delegation_id)
{
   GLITE_STACK_TRY("destroyProxy()");
   edglog_fn("wmpoperations::destroyProxy");
   initWMProxyOperation("destroyProxy");

   security::do_authZ("destroyProxy", delegation_id);

   edglog(debug)<<"destroyProxy successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getProxyTerminationTime(time_t
                        &getProxyTerminationTime_response, const string& delegation_id)
{
   GLITE_STACK_TRY("getProxyTerminationTime()");
   edglog_fn("wmpoperations::getProxyTerminationTime");

   initWMProxyOperation("getProxyTerminationTime");
   security::do_authZ("getProxyTerminationTime", delegation_id);
   getProxyTerminationTime_response = security::getTerminationTime(delegation_id);
   edglog(debug)<<"getProxyTerminationTime successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getACLItems(getACLItemsResponse& getACLItems_response, const string& job_id)
{
   GLITE_STACK_TRY("getACLItems()");
   edglog_fn("wmpoperations::getACLItems");

   edglog(debug)<<"Operation requested for job: "<<job_id<<endl;
   initWMProxyOperation("getACLItems");
   security::do_authZ_jobid("getACLItems", job_id);
   JobId jid(job_id);
   string jobpath = wmputilities::getJobDirectoryPath(jid);
   edglog(debug)<<"GACL File: "<<jobpath + FILE_SEPARATOR
                + security::GaclManager::WMPGACL_DEFAULT_FILE<<endl;
   security::GaclManager gaclmanager(jobpath + FILE_SEPARATOR
                                     + security::GaclManager::WMPGACL_DEFAULT_FILE);
   getACLItems_response =
      gaclmanager.getItems(security::GaclManager::WMPGACL_PERSON_TYPE);
   edglog(debug) << "getACLItems successful" << endl;

   GLITE_STACK_CATCH();
}

void
addACLItems(addACLItemsResponse& addACLItems_response, const string& job_id,
            StringList * dnlist)
{
   GLITE_STACK_TRY("addACLItems()");
   edglog_fn("wmpoperations::addACLItems");

   edglog(debug)<<"Operation requested for job: "<<job_id<<endl;
   initWMProxyOperation("addACLItems");
   security::do_authZ_jobid("addACLItems", job_id);

   JobId jid(job_id);
   string jobpath = wmputilities::getJobDirectoryPath(jid);

   edglog(debug)<<"GACL File: "<<jobpath + FILE_SEPARATOR
                + security::GaclManager::WMPGACL_DEFAULT_FILE<<endl;
   security::GaclManager gaclmanager(jobpath + FILE_SEPARATOR
                                     + security::GaclManager::WMPGACL_DEFAULT_FILE);

   vector<pair<security::GaclManager::WMPgaclCredType, string> > gaclvect;
   pair<security::GaclManager::WMPgaclCredType, string> gaclpair;
   for (unsigned int i = 0; i < dnlist->Item->size(); i++) {
      gaclpair.first = security::GaclManager::WMPGACL_PERSON_TYPE;
      edglog(debug)<<"Item to add: "<<(*(dnlist->Item))[i]<<endl;
      gaclpair.second = (*(dnlist->Item))[i];
      gaclvect.push_back(gaclpair);
   }
   gaclmanager.addEntries(gaclvect);
   gaclmanager.saveGacl();

   edglog(debug)<<"addACLItems successful"<<endl;

   GLITE_STACK_CATCH();
}

void
removeACLItem(removeACLItemResponse& removeACLItem_response,
              const string& job_id, const string& item)
{
   GLITE_STACK_TRY("removeACLItem()");
   edglog_fn("wmpoperations::removeACLItem");

   edglog(debug)<<"Operation requested for job: "<<job_id<<endl;
   initWMProxyOperation("removeACLItem");
   security::do_authZ_jobid("removeACLItem", job_id);

   string errors = "";
   JobId jid (job_id);
   // TBD change test in: item == owner
   if (item == wmputilities::getDN_SSL()) {
      edglog(error)<<"Removal of the item representing user that has "
                   "registered the job is not allowed"<<endl;
      throw JobOperationException(__FILE__, __LINE__,
                                  "removeACLItem()", wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                  "Removal of the item representing user that has registered the "
                                  "job is not allowed");
   }
   string jobpath = wmputilities::getJobDirectoryPath(jid);

   edglog(debug)<<"GACL File: "<<jobpath + FILE_SEPARATOR
                + security::GaclManager::WMPGACL_DEFAULT_FILE<<endl;
   security::GaclManager gaclmanager(jobpath + FILE_SEPARATOR
                                     + security::GaclManager::WMPGACL_DEFAULT_FILE);
   gaclmanager.removeEntry(security::GaclManager::WMPGACL_PERSON_TYPE,
                           item, errors);

   if (errors.size() > 0) {
      edglog(error)<<"Removal of the gacl item failed: " << errors << "\n";
      throw AuthorizationException(__FILE__, __LINE__,
                                   "removeACLItem()", wmputilities::WMS_AUTHORIZATION_ERROR,
                                   "Removal of the gacl item failed:\n" + errors);
   }
   gaclmanager.saveGacl();

   edglog(debug)<<"removeACLItem successful"<<endl;

   GLITE_STACK_CATCH();
}

// getDelegatedProxyInfo and getJobProxyInfo
void
getProxyInfo(getProxyInfoResponse& getProxyInfo_response, const string& id,
             bool isjobid)
{
   GLITE_STACK_TRY("getProxyInfo()");
   edglog_fn("wmpoperations::getProxyInfo");

   initWMProxyOperation("getProxyInfo");
   if (isjobid) {
      security::do_authZ_jobid("getProxyInfo", id);
   } else {
      security::do_authZ("getProxyInfo", id);
   }

   string proxy;
   if (isjobid) {
      edglog(info)<<"Job Id: "<<id<<endl;
      // Checking delegation id
      if (id == "") {
         edglog(error)<<"Provided Job Id not valid"<<endl;
         throw JobOperationException(__FILE__, __LINE__,
                                     "getProxyInfo()", wmputilities::WMS_INVALID_ARGUMENT,
                                     "Provided Job Id not valid");
      }
      proxy = wmputilities::getJobDelegatedProxyPath(id);
      security::checkProxyExistence(proxy, id);
      edglog(debug)<<"Job proxy: "<<proxy<<endl;
   } else {
      edglog(info)<<"Delegation Id: "<<id<<endl;
      // Checking delegation id
      if (id == "") {
         edglog(error)<<"Provided Delegation Id not valid"<<endl;
         throw JobOperationException(__FILE__, __LINE__,
                                     "getProxyInfo()", wmputilities::WMS_INVALID_ARGUMENT,
                                     "Provided Delegation Id not valid");
      }
      proxy = security::getDelegatedProxyPath(id, wmputilities::getDN_SSL());
      edglog(debug)<<"Delegated Proxy: "<<proxy<<endl;
   }
   security::VOMSAuthN vomsproxy = security::VOMSAuthN(proxy);
   getProxyInfo_response.items = vomsproxy.getProxyInfo();

   edglog(debug)<<"getProxyInfo successful"<<endl;

   GLITE_STACK_CATCH();
}

void
checkPerusalFlag(JobId *jid, string& delegatedproxy, bool checkremotepeek)
{
   GLITE_STACK_TRY("checkPerusalFlag()");
   edglog_fn("wmpoperations::checkPerusalFlag");

   // not exposed: no security checks

   WMPEventLogger wmplogger(wmputilities::getEndpoint());
   wmplogger.setLBProxy(conf.isLBProxyAvailable(), wmputilities::getDN_SSL());
   wmplogger.setUserProxy(delegatedproxy);
   wmplogger.init_and_set_logging_job("", 0, jid);

   string jdlpath;
   jdlpath = wmputilities::getJobJDLExistingStartPath(*jid);

   edglog(debug)<<"jdlpath: "<<jdlpath<<endl;
   string type;
   boost::shared_ptr<JobAd> jad;
   string parent = wmplogger.retrieveRegJobEvent(jid->toString()).parent;
   if (!wmputilities::fileExists(jdlpath)) {
      // Checking if the job is a sub-node
      if (parent.empty()) {
         // JDL to start should be present, something went wrong
         throw JobOperationException(__FILE__, __LINE__,
                                     "checkPerusalFlag()", wmputilities::WMS_IS_FAILURE,
                                     "couldn't retrieve parent jobid for " + jid->toString());
      }

      // Job is a sub-node, getting JDL from parent JDL
      JobId parentjid(parent);
      jdlpath = wmputilities::getJobJDLExistingStartPath(parentjid);
      boost::shared_ptr<WMPExpDagAd> dag(new WMPExpDagAd(wmputilities::readTextFile(jdlpath)));
      boost::shared_ptr<NodeAd> jad(new NodeAd(dag->getNode(*jid)));

      // Supported sub-nodes are standard job, setting type = job
      type = JDL_TYPE_JOB;

   } else {
      // Job is standard job or a compound job parent
      if (!parent.empty()) {
         JobId parentjid(parent);
         jdlpath = wmputilities::getJobJDLExistingStartPath(parentjid);
      }
      boost::shared_ptr<Ad> ad(new Ad(wmputilities::readTextFile(jdlpath)));
      if (ad->hasAttribute(JDL::TYPE)) {
         type = glite_wms_jdl_toLower(ad->getString(JDL::TYPE));
      } else {
         type = JDL_TYPE_JOB;
      }
      if (type == JDL_TYPE_JOB) {
         jad.reset(new JobAd(*(ad->ad())));
      }
   }
   edglog(debug) <<"Type: "<<type<<endl;
   if (type == JDL_TYPE_JOB) {
      jad->setLocalAccess(false);

      if (jad->hasAttribute(JDL::PU_FILE_ENABLE)) {
         if (!jad->getBool(JDL::PU_FILE_ENABLE)) {
            edglog(debug)<<"Perusal not enabled for this job"<<endl;
            throw JobOperationException(__FILE__, __LINE__,
                                        "checkPerusalFlag()",
                                        wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                        "Perusal not enabled for this job");
         }
      } else {
         edglog(debug)<<"Perusal not enabled for this job"<<endl;
         throw JobOperationException(__FILE__, __LINE__,
                                     "checkPerusalFlag()",
                                     wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                     "Perusal not enabled for this job");
      }

      // Checking for attribute JDL::PU_FILES_DEST_URI value
      if (checkremotepeek) {
         if (jad->hasAttribute(JDL::PU_FILES_DEST_URI)) {
            string protocol = conf.getDefaultProtocol();
            string port = (conf.getDefaultPort() != 0)
                          ? (":" + boost::lexical_cast<std::string>(
                                conf.getDefaultPort()))
                          : "";
            string serverhost = getServerHost();
            string uri = jad->getString(JDL::PU_FILES_DEST_URI);

            string tofind = "://" + serverhost;
            std::string::size_type pos = uri.find(tofind);
            if (pos == string::npos) {
               edglog(debug)<<"Remote perusal peek URI set:\n"
                            <<uri<<endl;
               throw JobOperationException(__FILE__, __LINE__,
                                           "checkPerusalFlag()",
                                           wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                           "Remote perusal peek URI set:\n" + uri);
            }
            string uriprotocol = uri.substr(0, pos);
            edglog(debug)<<"URI protocol: "<<uriprotocol<<endl;
            string uripath = uri.substr(pos + tofind.length(),
                                        uri.length() - 1);
            edglog(debug)<<"URI path: "<<uripath<<endl;
            pos = uripath.find("/");
            // Looking for port
            if (pos == string::npos) {
               edglog(debug)<<"Remote perusal peek URI set:\n"
                            <<uri<<endl;
               throw JobOperationException(__FILE__, __LINE__,
                                           "checkPerusalFlag()",
                                           wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                           "Remote perusal peek URI set:\n" + uri);
            }
            uripath = uripath.substr(pos, uripath.length() - 1);
            edglog(debug)<<"URI path: "<<uripath<<endl;

            string serverpath;
            if ((uriprotocol == "https") || (uriprotocol == "http")) {
               // No document root added
               serverpath = wmputilities::getPeekDirectoryPath(*jid, false);
            } else {
               serverpath = wmputilities::getPeekDirectoryPath(*jid);
            }
            edglog(debug)<<"Server path: "<<serverpath<<endl;
            if (uripath != serverpath) {
               edglog(debug)<<"Remote perusal peek URI set:\n"
                            <<uri<<endl;
               throw JobOperationException(__FILE__, __LINE__,
                                           "checkPerusalFlag()",
                                           wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                           "Remote perusal peek URI refers to server host, but "
                                           "the path is not manged by WMProxy:\n" + uri);
            }
         }
      }
   } else {
      edglog(debug)<<"Perusal service not available for dag or collection "
                   "type"<<endl;
      throw JobOperationException(__FILE__, __LINE__,
                                  "checkPerusalFlag()", wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                  "Perusal service not available for dag or collection type");
   }

   GLITE_STACK_CATCH();
}

void
enableFilePerusal(enableFilePerusalResponse& enableFilePerusal_response,
                  const string& job_id, StringList * fileList)
{
   GLITE_STACK_TRY("enableFilePerusal()");
   edglog_fn("wmpoperations::enableFilePerusal");

   edglog(debug)<<"Operation requested for job: "<<job_id<<endl;
   initWMProxyOperation("enableFilePerusal");
   security::do_authZ_jobid("enableFilePerusal", job_id);

   JobId jid (job_id);
   // TODO delegation Id may be returned somehow when checking security...
   string delegatedproxy = wmputilities::getJobDelegatedProxyPath(jid);
   checkPerusalFlag(&jid, delegatedproxy, false);

   string filename = wmputilities::getPeekDirectoryPath(jid) + FILE_SEPARATOR
                     + PERUSAL_FILE_2_PEEK_NAME;

   // getting maxPerusalFiles attribute from configuration file
   unsigned int maxPerusalFiles = conf.getMaxPerusalFiles();
   unsigned int size = fileList->Item->size();

   if ( size <= maxPerusalFiles ) {
      if (size != 0) {
         fstream file2peek(filename.c_str(), ios::out);
         for (unsigned int i = 0; i < size; i++) {
            file2peek << (*(fileList->Item))[i]+"\n";
         }
         file2peek.close();
      } else {
         // Removing file2peek file if needed
         if (wmputilities::fileExists(filename)) {
            remove(filename.c_str());
         }
      }
      edglog(debug)<<"enableFilePerusal successful"<<endl;
   } else {
      throw JobOperationException(__FILE__, __LINE__, "wmpoperations::enableFilePerusal()",
                                  wmputilities::WMS_OPERATION_NOT_ALLOWED, "The maximum number of perusal files is reached");

   }

   GLITE_STACK_CATCH();
}

void
getPerusalFiles(getPerusalFilesResponse& getPerusalFiles_response,
                const string& job_id, const string& fileName, bool allChunks,
                const string& protocol)
{
   GLITE_STACK_TRY("getPerusalFiles()");
   edglog_fn("wmpoperations::getPerusalFiles");

   edglog(debug)<<"Operation requested for job: "<<job_id<<endl;
   initWMProxyOperation("getPerusalFiles");
   security::do_authZ_jobid("getPerusalFiles", job_id);

   JobId jid(job_id);

   if (fileName == "") {
      throw JobOperationException(__FILE__, __LINE__,
                                  "wmpoperations::getPerusalFiles()", wmputilities::WMS_INVALID_ARGUMENT,
                                  "Provided file name not valid");
   }

   if (!wmputilities::fileExists(wmputilities::getJobJDLStartedPath(jid))) {
      edglog(error)<<"The job is not started"<<endl;
      throw JobOperationException(__FILE__, __LINE__,
                                  "getPerusalFiles()", wmputilities::WMS_OPERATION_NOT_ALLOWED,
                                  "the job is not started");
   }
   // TODO delegation Id may be returned somehow when checking security...
   string delegatedproxy= wmputilities::getJobDelegatedProxyPath(jid);
   checkPerusalFlag(&jid, delegatedproxy, true);

   string peekdir = wmputilities::getPeekDirectoryPath(jid) + FILE_SEPARATOR;
   const boost::filesystem::path p(peekdir, boost::filesystem::native);
   vector<string> found;
   glite::wms::wmproxy::commands::list_files(p, found);

   vector<string> *jobdiruris = getJobDirectoryURIsVector(conf.getProtocols(),
                                conf.getDefaultProtocol(), conf.getDefaultPort(), conf.getHTTPSPort(),
                                job_id, protocol, "peek/");

   unsigned int jobdirsize = jobdiruris->size();

   vector<string> good;
   vector<string> returnvector;
   string currentfilename;

   vector<string>::iterator iter = found.begin();
   vector<string>::iterator const end = found.end();
   for (; iter != end; ++iter) {
      currentfilename = wmputilities::getFileName(*iter);
      if (currentfilename.find(fileName + ".") == 0) {
         edglog(debug)<<"Good perusal file: "<<*iter<<endl;
         good.push_back(*iter);
      }
      if (allChunks) {
         if (currentfilename.find(fileName + PERUSAL_DATE_INFO_SEPARATOR)
               == 0) {
            edglog(debug)<<"Good old global perusal file: "<<*iter<<endl;
            for (unsigned int i = 0; i < jobdirsize; i++) {
               returnvector.push_back((*jobdiruris)[i] + currentfilename);
            }
         }
      }
   }

   //unsigned int size = good.size();
   if (good.size()) {
      // Sorting vector
      sort(good.begin(), good.end());

      string tempfile = peekdir + TEMP_PERUSAL_FILE_NAME;

      long filesize = 0;
      long totalfilesize = 0;

      string startdate = good[0].substr(good[0].rfind(".") + 1,
                                        good[0].length() - 1);
      string enddate = startdate;

      fstream outfile(tempfile.c_str(), ios::out);
      if (!outfile.good()) {
         edglog(severe)<<tempfile<<": !outfile.good()"<<endl;
         throw FileSystemException(__FILE__, __LINE__,
                                   "getPerusalFiles()", WMS_FILE_SYSTEM_ERROR, "Unable to open "
                                   "perusal temporary file\n(please contact server administrator)");
      }

      string filetoreturn;
      vector<string>::iterator iter = good.begin();
      vector<string>::iterator const end = good.end();
      for (; iter != end; ++iter) {
         filesize = wmputilities::computeFileSize(*iter);
         filetoreturn = fileName
                        + PERUSAL_DATE_INFO_SEPARATOR + startdate
                        + PERUSAL_DATE_INFO_SEPARATOR + enddate;
         if ((totalfilesize + filesize) > FILE_TRANSFER_SIZE_LIMIT) {
            outfile.close();
            rename(tempfile.c_str(), (peekdir + filetoreturn).c_str());

            for (unsigned int i = 0; i < jobdirsize; i++) {
               returnvector.push_back((*jobdiruris)[i] + filetoreturn);
            }

            outfile.open(tempfile.c_str(), ios::out);
            if (!outfile.good()) {
               edglog(severe)<<tempfile<<": !outfile.good()"<<endl;
               throw FileSystemException(__FILE__, __LINE__,
                                         "getPerusalFiles()", WMS_FILE_SYSTEM_ERROR, "Unable to "
                                         "open perusal temporary file\n(please contact server "
                                         "administrator)");
            }
            totalfilesize = 0;
            enddate = (*iter).substr((*iter).rfind(".") + 1,
                                     (*iter).length() - 1);
            startdate = enddate;
         } else {
            enddate = (*iter).substr((*iter).rfind(".") + 1,
                                     (*iter).length() - 1);
         }
         ifstream infile((*iter).c_str());
         if (!infile.good()) {
            edglog(severe)<<*iter<<": !infile.good()"<<endl;
            throw FileSystemException(__FILE__, __LINE__,
                                      "getPerusalFiles()", WMS_FILE_SYSTEM_ERROR, "Unable to open "
                                      "perusal input file\n(please contact server administrator)");
         }
         outfile << infile.rdbuf();
         infile.close();
         remove((*iter).c_str());
         totalfilesize += filesize;
      }
      outfile.close();
      filetoreturn = fileName
                     + PERUSAL_DATE_INFO_SEPARATOR + startdate
                     + PERUSAL_DATE_INFO_SEPARATOR + enddate;
      rename(tempfile.c_str(), (peekdir + filetoreturn).c_str());

      for (unsigned int i = 0; i < jobdirsize; i++) {
         returnvector.push_back((*jobdiruris)[i] + filetoreturn);
      }
   }

   getPerusalFiles_response = returnvector;

   edglog(debug)<<"getPerusalFiles successful"<<endl;

   GLITE_STACK_CATCH();
}

void
getTransferProtocols(getTransferProtocolsResponse& getTransferProtocols_response)
{
   GLITE_STACK_TRY("getTransferProtocols()");
   edglog_fn("wmpoperations::getTransferProtocols");
   initWMProxyOperation("getTransferProtocols");
   security::do_authZ("getTransferProtocols");

   getTransferProtocols_response.protocols = new StringList;
   vector<string> *protocols = new vector<string>();

   vector<pair<string, int> > serverprotocols = conf.getProtocols();
   unsigned int size = serverprotocols.size();
   for (unsigned int i = 0; i < size; i++) {
      protocols->push_back(serverprotocols[i].first);
   }
   protocols->push_back("https");
   getTransferProtocols_response.protocols->Item = protocols;

   edglog(debug)<<"Transfer protocols retrieved successful"<<endl;
   GLITE_STACK_CATCH();
}

void
getJobStatusOp(getJobStatusResponse& getJobStatus_response, const string& job_id)
{
   GLITE_STACK_TRY("getJobStatus()");
   edglog_fn("wmpoperations::getJobStatus");

   initWMProxyOperation("getJobStatus");
   security::do_authZ("getJobStatusOp");

   // TODO status flag could be parametrized
   bool status_flag=true;
   // PERFORM Job actual Status request
   WMPEventLogger wmplogger(wmputilities::getEndpoint());
   JobStatus status = wmplogger.getStatus(status_flag);
   // fill in job Status structure:

   getJobStatus_response.jobStatus = new JobStatusStructType;
   getJobStatus_response.jobStatus->status = status.name();
   getJobStatus_response.jobStatus->jobid  = job_id;
   // TODO children?

   edglog(debug)<<"JobStatus retrieved successful"<<endl;
   GLITE_STACK_CATCH();
}

max_stars_repo_name: italiangrid/wms

max_issues_repo_name: italiangrid/wms

max_forks_repo_name: italiangrid/wms