<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#if TENSORFLOW_USE_SYCL

#define EIGEN_USE_SYCL

#include "tensorflow/core/common_runtime/sycl/sycl_device_context.h"
#include "tensorflow/core/common_runtime/dma_helper.h"

#define EIGEN_USE_SYCL
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"

namespace tensorflow {

void SYCLDeviceContext::CopyCPUTensorToDevice(const Tensor *cpu_tensor,
                                              Device *device,
                                              Tensor *device_tensor,
                                              StatusCallback done) const {
  const int64 total_bytes = cpu_tensor->TotalBytes();
  if (total_bytes > 0) {
    const void *src_ptr = DMAHelper::base(cpu_tensor);
    void *dst_ptr = DMAHelper::base(device_tensor);
    switch (cpu_tensor->dtype()) {
    case DT_FLOAT:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<float *>(dst_ptr), static_cast<const float *>(src_ptr),
          total_bytes);
      break;
    case DT_DOUBLE:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<double *>(dst_ptr), static_cast<const double *>(src_ptr),
          total_bytes);
      break;
    case DT_INT32:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int32 *>(dst_ptr), static_cast<const int32 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT64:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int64 *>(dst_ptr), static_cast<const int64 *>(src_ptr),
          total_bytes);
      break;
    case DT_HALF:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<Eigen::half *>(dst_ptr),
          static_cast<const Eigen::half *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX64:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<std::complex<float> *>(dst_ptr),
          static_cast<const std::complex<float> *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX128:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<std::complex<double> *>(dst_ptr),
          static_cast<const std::complex<double> *>(src_ptr), total_bytes);
      break;
    case DT_INT8:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int8 *>(dst_ptr), static_cast<const int8 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT16:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int16 *>(dst_ptr), static_cast<const int16 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT8:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<uint8 *>(dst_ptr), static_cast<const uint8 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT16:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<uint16 *>(dst_ptr), static_cast<const uint16 *>(src_ptr),
          total_bytes);
      break;
    default:
      assert(false && "unsupported type");
    }
  }
  done(Status::OK());
}

void SYCLDeviceContext::CopyDeviceTensorToCPU(const Tensor *device_tensor,
                                              StringPiece edge_name,
                                              Device *device,
                                              Tensor *cpu_tensor,
                                              StatusCallback done) {
  const int64 total_bytes = device_tensor->TotalBytes();
  if (total_bytes > 0) {
    device->eigen_sycl_device()->deallocate_all();
    const void* src_ptr = DMAHelper::base(device_tensor);
    void* dst_ptr = DMAHelper::base(cpu_tensor);
    switch (device_tensor->dtype()) {
    case DT_FLOAT:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<float *>(dst_ptr), static_cast<const float *>(src_ptr),
          total_bytes);
      break;
    case DT_DOUBLE:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<double *>(dst_ptr), static_cast<const double *>(src_ptr),
          total_bytes);
      break;
    case DT_INT32:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int32 *>(dst_ptr), static_cast<const int32 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT64:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int64 *>(dst_ptr), static_cast<const int64 *>(src_ptr),
          total_bytes);
      break;
    case DT_HALF:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<Eigen::half *>(dst_ptr),
          static_cast<const Eigen::half *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX64:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<std::complex<float> *>(dst_ptr),
          static_cast<const std::complex<float> *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX128:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<std::complex<double> *>(dst_ptr),
          static_cast<const std::complex<double> *>(src_ptr), total_bytes);
      break;
    case DT_INT8:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int8 *>(dst_ptr), static_cast<const int8 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT16:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int16 *>(dst_ptr), static_cast<const int16 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT8:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<uint8 *>(dst_ptr), static_cast<const uint8 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT16:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<uint16 *>(dst_ptr), static_cast<const uint16 *>(src_ptr),
          total_bytes);
      break;

    default:
      assert(false && "unsupported type");
    }
  }
  done(Status::OK());
}

}  // namespace tensorflow
#endif // TENSORFLOW_USE_SYCL
<commit_msg>Added support for boolean values on OpenCL devices<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#if TENSORFLOW_USE_SYCL

#define EIGEN_USE_SYCL

#include "tensorflow/core/common_runtime/sycl/sycl_device_context.h"
#include "tensorflow/core/common_runtime/dma_helper.h"

#define EIGEN_USE_SYCL
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"

namespace tensorflow {

void SYCLDeviceContext::CopyCPUTensorToDevice(const Tensor *cpu_tensor,
                                              Device *device,
                                              Tensor *device_tensor,
                                              StatusCallback done) const {
  const int64 total_bytes = cpu_tensor->TotalBytes();
  if (total_bytes > 0) {
    const void *src_ptr = DMAHelper::base(cpu_tensor);
    void *dst_ptr = DMAHelper::base(device_tensor);
    switch (cpu_tensor->dtype()) {
    case DT_FLOAT:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<float *>(dst_ptr), static_cast<const float *>(src_ptr),
          total_bytes);
      break;
    case DT_DOUBLE:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<double *>(dst_ptr), static_cast<const double *>(src_ptr),
          total_bytes);
      break;
    case DT_INT32:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int32 *>(dst_ptr), static_cast<const int32 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT64:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int64 *>(dst_ptr), static_cast<const int64 *>(src_ptr),
          total_bytes);
      break;
    case DT_HALF:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<Eigen::half *>(dst_ptr),
          static_cast<const Eigen::half *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX64:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<std::complex<float> *>(dst_ptr),
          static_cast<const std::complex<float> *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX128:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<std::complex<double> *>(dst_ptr),
          static_cast<const std::complex<double> *>(src_ptr), total_bytes);
      break;
    case DT_INT8:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int8 *>(dst_ptr), static_cast<const int8 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT16:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<int16 *>(dst_ptr), static_cast<const int16 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT8:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<uint8 *>(dst_ptr), static_cast<const uint8 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT16:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<uint16 *>(dst_ptr), static_cast<const uint16 *>(src_ptr),
          total_bytes);
      break;
    case DT_BOOL:
      device->eigen_sycl_device()->memcpyHostToDevice(
          static_cast<bool *>(dst_ptr), static_cast<const bool *>(src_ptr),
          total_bytes);
      break;
    default:
      assert(false && "unsupported type");
    }
  }
  done(Status::OK());
}

void SYCLDeviceContext::CopyDeviceTensorToCPU(const Tensor *device_tensor,
                                              StringPiece edge_name,
                                              Device *device,
                                              Tensor *cpu_tensor,
                                              StatusCallback done) {
  const int64 total_bytes = device_tensor->TotalBytes();
  if (total_bytes > 0) {
    device->eigen_sycl_device()->deallocate_all();
    const void* src_ptr = DMAHelper::base(device_tensor);
    void* dst_ptr = DMAHelper::base(cpu_tensor);
    switch (device_tensor->dtype()) {
    case DT_FLOAT:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<float *>(dst_ptr), static_cast<const float *>(src_ptr),
          total_bytes);
      break;
    case DT_DOUBLE:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<double *>(dst_ptr), static_cast<const double *>(src_ptr),
          total_bytes);
      break;
    case DT_INT32:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int32 *>(dst_ptr), static_cast<const int32 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT64:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int64 *>(dst_ptr), static_cast<const int64 *>(src_ptr),
          total_bytes);
      break;
    case DT_HALF:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<Eigen::half *>(dst_ptr),
          static_cast<const Eigen::half *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX64:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<std::complex<float> *>(dst_ptr),
          static_cast<const std::complex<float> *>(src_ptr), total_bytes);
      break;
    case DT_COMPLEX128:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<std::complex<double> *>(dst_ptr),
          static_cast<const std::complex<double> *>(src_ptr), total_bytes);
      break;
    case DT_INT8:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int8 *>(dst_ptr), static_cast<const int8 *>(src_ptr),
          total_bytes);
      break;
    case DT_INT16:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<int16 *>(dst_ptr), static_cast<const int16 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT8:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<uint8 *>(dst_ptr), static_cast<const uint8 *>(src_ptr),
          total_bytes);
      break;
    case DT_UINT16:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<uint16 *>(dst_ptr), static_cast<const uint16 *>(src_ptr),
          total_bytes);
      break;
    case DT_BOOL:
      device->eigen_sycl_device()->memcpyDeviceToHost(
          static_cast<bool *>(dst_ptr), static_cast<const bool *>(src_ptr),
          total_bytes);
      break;
    default:
      assert(false && "unsupported type");
    }
  }
  done(Status::OK());
}

}  // namespace tensorflow
#endif // TENSORFLOW_USE_SYCL
<|endoftext|>


<commit_before>/**
 * @file    CSIEnder.hh
 * @author  Paul Tagliamonte <tag@pault.ag>
 * @license MIT
 * @created Tue Nov  8 14:20:09 UTC 2011
 */

#include <iostream>

#include "StateMachine.hh"
#include "CSIEnder.hh"
#include "CSIValue.hh"

void CSIEnder::feed( char c ) {

}

void CSIEnder::enter() {
	for (
		unsigned int i = 0;
		i < ansi_state_CSIValue_parsed_ints.size();
		++i
	) {
		std::cout << ansi_state_CSIValue_parsed_ints.at(i) << ", " << std::endl;
	}
}

void CSIEnder::exit() {

}

CSIEnder ansi_state_CSIEnder;
<commit_msg>implementing the ender a bit<commit_after>/**
 * @file    CSIEnder.hh
 * @author  Paul Tagliamonte <tag@pault.ag>
 * @license MIT
 * @created Tue Nov  8 14:20:09 UTC 2011
 */

#include <iostream>

#include "StateMachine.hh"
#include "Exception.hh"
#include "InvalidState.hh"
#include "CSIEnder.hh"
#include "CSIValue.hh"
#include "ANSIEntry.hh"

/* Some wikipedia background:
 * The final byte is technically any character in the range 64 to 126
 * (hex 0x40 to 0x7e, ASCII @ to ~), and may be modified extended with leading
 * intermediate bytes in the range 32 to 47 (hex 0x20 to 0x2f). */

void CSIEnder::feed( char c ) {
	/* XXX: Implement leading bytes correctly */
	if ( c >= 64 && c <= 126 ) {
		/* We've parsed well */
		ansi_next_state = &ansi_state_ANSIEntry;
	} else {
		ansi_next_state = &ansi_state_InvalidState;
		throw new InvalidSequence();
	}
}

void CSIEnder::enter() {}
void CSIEnder::exit()  {}

CSIEnder ansi_state_CSIEnder;
<|endoftext|>


<commit_before>#include "Channel.hpp"
#include "Message.hpp"
#include "Network.hpp"
#include "PawnDispatcher.hpp"
#include "Logger.hpp"
#include "Guild.hpp"
#include "utils.hpp"

#include "fmt/format.h"

#undef SendMessage // Windows at its finest

Channel::Channel(ChannelId_t pawn_id, json const &data, GuildId_t guild_id) :
	m_PawnId(pawn_id)
{
	std::underlying_type<Type>::type type;
	if (!utils::TryGetJsonValue(data, type, "type")
		|| !utils::TryGetJsonValue(data, m_Id, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"type\" and \"id\" in \"{}\"", data.dump());
		return;
	}

	m_Type = static_cast<Type>(type);

	if (m_Type != Type::DM && m_Type != Type::GROUP_DM)
	{
		if (guild_id != 0)
		{
			m_GuildId = guild_id;
		}
		else
		{
			std::string guild_id_str;
			if (utils::TryGetJsonValue(data, guild_id_str, "guild_id"))
			{
				Guild_t const &guild = GuildManager::Get()->FindGuildById(guild_id_str);
				m_GuildId = guild->GetPawnId();
				guild->AddChannel(pawn_id);
			}
			else
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"invalid JSON: expected \"guild_id\" in \"{}\"", data.dump());
			}
		}

		Snowflake_t parent_id_str;
		utils::TryGetJsonValue(data, m_Name, "name");
		utils::TryGetJsonValue(data, m_Topic, "topic");
		utils::TryGetJsonValue(data, m_Position, "position");
		utils::TryGetJsonValue(data, m_IsNsfw, "nsfw");
		utils::TryGetJsonValue(data, parent_id_str, "parent_id");

		Channel_t const &channel = ChannelManager::Get()->FindChannelById(parent_id_str);
		m_ParentId = channel ? channel->GetPawnId() : INVALID_CHANNEL_ID;
	}
}

void Channel::SendMessage(std::string &&msg, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "content", std::move(msg) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Http::ResponseCb_t response_cb;
	if (cb)
	{
		response_cb = [cb](Http::Response response)
		{
			Logger::Get()->Log(LogLevel::DEBUG,
				"channel message create response: status {}; body: {}; add: {}",
				response.status, response.body, response.additional_data);
			if (response.status / 100 == 2) // success
			{
				auto msg_json = json::parse(response.body);
				PawnDispatcher::Get()->Dispatch([cb, msg_json]() mutable
				{
					auto msg = MessageManager::Get()->Create(msg_json);
					if (msg != INVALID_MESSAGE_ID)
					{
						MessageManager::Get()->SetCreatedMessageId(msg);
						cb->Execute();
						MessageManager::Get()->SetCreatedMessageId(INVALID_MESSAGE_ID);

						MessageManager::Get()->Delete(msg);
					}
				});
			}
		};
	}

	Network::Get()->Http().Post(fmt::format("/channels/{:s}/messages", GetId()), json_str,
		std::move(response_cb));
}

void Channel::SetChannelName(std::string const &name)
{
	json data = {
		{ "name", name }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelTopic(std::string const &topic)
{
	json data = {
		{ "topic", topic }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelPosition(int const position)
{
	json data = {
		{ "position", position }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelNsfw(bool const is_nsfw)
{
	json data = {
		{ "nsfw", is_nsfw }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelParentCategory(Channel_t const &parent)
{
	if (parent->GetType() != Type::GUILD_CATEGORY)
		return;

	json data = {
		{ "parent_id", parent->GetId() }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::DeleteChannel()
{
	Network::Get()->Http().Delete(fmt::format("/channels/{:s}", GetId()));
}

void ChannelManager::Initialize()
{
	assert(m_Initialized != m_InitValue);

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_CREATE, [](json const &data)
	{
		PawnDispatcher::Get()->Dispatch([data]() mutable
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(data);
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			// forward DCC_OnChannelCreate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelCreate", channel_id);
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_UPDATE, [](json const &data)
	{
		ChannelManager::Get()->UpdateChannel(data);
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_DELETE, [](json const &data)
	{
		ChannelManager::Get()->DeleteChannel(data);
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::READY, [this](json const &data)
	{
		static const char *PRIVATE_CHANNEL_KEY = "private_channels";
		if (utils::IsValidJson(data, PRIVATE_CHANNEL_KEY, json::value_t::array))
		{
			for (auto const &c : data.at(PRIVATE_CHANNEL_KEY))
				AddChannel(c);
		}
		else
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"invalid JSON: expected \"{}\" in \"{}\"", PRIVATE_CHANNEL_KEY, data.dump());
		}
		m_Initialized++;
	});
}

bool ChannelManager::IsInitialized()
{
	return m_Initialized == m_InitValue;
}

bool ChannelManager::CreateGuildChannel(Guild_t const &guild,
	std::string const &name, Channel::Type type, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "name", name },
		{ "type", static_cast<int>(type) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
	{
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);
		return false;
	}

	Network::Get()->Http().Post(fmt::format("/guilds/{:s}/channels", guild->GetId()), json_str,
		[this, cb](Http::Response r)
	{
		Logger::Get()->Log(LogLevel::DEBUG,
			"channel create response: status {}; body: {}; add: {}",
			r.status, r.body, r.additional_data);
		if (r.status / 100 == 2) // success
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(json::parse(r.body));
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			if (cb)
			{
				PawnDispatcher::Get()->Dispatch([=]()
				{
					m_CreatedChannelId = channel_id;
					cb->Execute();
					m_CreatedChannelId = INVALID_CHANNEL_ID;
				});
			}
		}
	});

	return true;
}

ChannelId_t ChannelManager::AddChannel(json const &data, GuildId_t guild_id/* = 0*/)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return INVALID_CHANNEL_ID;
	}

	Channel_t const &channel = FindChannelById(sfid);
	if (channel)
		return channel->GetPawnId(); // channel already exists

	ChannelId_t id = 1;
	while (m_Channels.find(id) != m_Channels.end())
		++id;

	if (!m_Channels.emplace(id, Channel_t(new Channel(id, data, guild_id))).second)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"can't create channel: duplicate key '{}'", id);
		return INVALID_CHANNEL_ID;
	}

	Logger::Get()->Log(LogLevel::INFO, "successfully added channel with id '{}'", id);
	return id;
}

void ChannelManager::UpdateChannel(json const &data)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return;
	}

	std::string name, topic;
	int position;
	bool is_nsfw;
	bool
		update_name = utils::TryGetJsonValue(data, name, "name"),
		update_topic = utils::TryGetJsonValue(data, topic, "topic"),
		update_position = utils::TryGetJsonValue(data, position, "position"),
		update_nsfw = utils::TryGetJsonValue(data, is_nsfw, "nsfw");

	PawnDispatcher::Get()->Dispatch([=]()
	{
		Channel_t const &channel = FindChannelById(sfid);
		if (!channel)
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"can't update channel: channel id \"{}\" not cached", sfid);
			return;
		}

		if (update_name && !name.empty())
			channel->m_Name = name;
		if (update_topic && !topic.empty())
			channel->m_Topic = topic;
		if (update_position)
			channel->m_Position = position;
		if (update_nsfw)
			channel->m_IsNsfw = is_nsfw;

		// forward DCC_OnChannelUpdate(DCC_Channel:channel);
		pawn_cb::Error error;
		pawn_cb::Callback::CallFirst(error, "DCC_OnChannelUpdate", channel->GetPawnId());
	});
}

void ChannelManager::DeleteChannel(json const &data)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return;
	}

	PawnDispatcher::Get()->Dispatch([this, sfid]()
	{
		Channel_t const &channel = FindChannelById(sfid);
		if (!channel)
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"can't delete channel: channel id \"{}\" not cached", sfid);
			return;
		}

		// forward DCC_OnChannelDelete(DCC_Channel:channel);
		pawn_cb::Error error;
		pawn_cb::Callback::CallFirst(error, "DCC_OnChannelDelete", channel->GetPawnId());

		Guild_t const &guild = GuildManager::Get()->FindGuild(channel->GetGuildId());
		if (guild)
			guild->RemoveChannel(channel->GetPawnId());

		m_Channels.erase(channel->GetPawnId());
	});

}

Channel_t const &ChannelManager::FindChannel(ChannelId_t id)
{
	static Channel_t invalid_channel;
	auto it = m_Channels.find(id);
	if (it == m_Channels.end())
		return invalid_channel;
	return it->second;
}

Channel_t const &ChannelManager::FindChannelByName(std::string const &name)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetName().compare(name) == 0)
			return channel;
	}
	return invalid_channel;
}

Channel_t const &ChannelManager::FindChannelById(Snowflake_t const &sfid)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetId().compare(sfid) == 0)
			return channel;
	}
	return invalid_channel;
}
<commit_msg>Fix channel updating on null values, rewrite updating & CHANNEL_UPDATE<commit_after>#include "Channel.hpp"
#include "Message.hpp"
#include "Network.hpp"
#include "PawnDispatcher.hpp"
#include "Logger.hpp"
#include "Guild.hpp"
#include "utils.hpp"

#include "fmt/format.h"

#undef SendMessage // Windows at its finest

Channel::Channel(ChannelId_t pawn_id, json const &data, GuildId_t guild_id) :
	m_PawnId(pawn_id)
{
	std::underlying_type<Type>::type type;
	if (!utils::TryGetJsonValue(data, type, "type")
		|| !utils::TryGetJsonValue(data, m_Id, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"type\" and \"id\" in \"{}\"", data.dump());
		return;
	}

	m_Type = static_cast<Type>(type);
	if (m_Type < Type::DM)
	{
		if (guild_id != 0)
		{
			m_GuildId = guild_id;
		}
		else
		{
			std::string guild_id_str;
			if (utils::TryGetJsonValue(data, guild_id_str, "guild_id"))
			{
				Guild_t const &guild = GuildManager::Get()->FindGuildById(guild_id_str);
				m_GuildId = guild->GetPawnId();
				guild->AddChannel(pawn_id);
			}
			else
			{
				Logger::Get()->Log(LogLevel::ERROR,
					"invalid JSON: expected \"guild_id\" in \"{}\"", data.dump());
			}
		}
		Update(data);
	}
}

void Channel::Update(json const &data)
{
	std::string name, topic;
	int position;
	bool is_nsfw;
	Snowflake_t parent_id;
	bool
		update_name = utils::TryGetJsonValue(data, name, "name"),
		update_topic = utils::TryGetJsonValue(data, topic, "topic"),
		update_position = utils::TryGetJsonValue(data, position, "position"),
		update_nsfw = utils::TryGetJsonValue(data, is_nsfw, "nsfw"),
		update_parent_id = utils::TryGetJsonValue(data, parent_id, "parent_id");

	if (update_name)
		m_Name = name;
	if (update_topic)
		m_Topic = topic;
	if (update_position)
		m_Position = position;
	if (update_nsfw)
		m_IsNsfw = is_nsfw;
	if (update_parent_id)
	{
		Channel_t const &channel = ChannelManager::Get()->FindChannelById(parent_id);
		m_ParentId = channel ? channel->GetPawnId() : INVALID_CHANNEL_ID;
	}
}

void Channel::SendMessage(std::string &&msg, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "content", std::move(msg) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Http::ResponseCb_t response_cb;
	if (cb)
	{
		response_cb = [cb](Http::Response response)
		{
			Logger::Get()->Log(LogLevel::DEBUG,
				"channel message create response: status {}; body: {}; add: {}",
				response.status, response.body, response.additional_data);
			if (response.status / 100 == 2) // success
			{
				auto msg_json = json::parse(response.body);
				PawnDispatcher::Get()->Dispatch([cb, msg_json]() mutable
				{
					auto msg = MessageManager::Get()->Create(msg_json);
					if (msg != INVALID_MESSAGE_ID)
					{
						MessageManager::Get()->SetCreatedMessageId(msg);
						cb->Execute();
						MessageManager::Get()->SetCreatedMessageId(INVALID_MESSAGE_ID);

						MessageManager::Get()->Delete(msg);
					}
				});
			}
		};
	}

	Network::Get()->Http().Post(fmt::format("/channels/{:s}/messages", GetId()), json_str,
		std::move(response_cb));
}

void Channel::SetChannelName(std::string const &name)
{
	json data = {
		{ "name", name }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelTopic(std::string const &topic)
{
	json data = {
		{ "topic", topic }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelPosition(int const position)
{
	json data = {
		{ "position", position }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelNsfw(bool const is_nsfw)
{
	json data = {
		{ "nsfw", is_nsfw }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::SetChannelParentCategory(Channel_t const &parent)
{
	if (parent->GetType() != Type::GUILD_CATEGORY)
		return;

	json data = {
		{ "parent_id", parent->GetId() }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);

	Network::Get()->Http().Patch(fmt::format("/channels/{:s}", GetId()), json_str);
}

void Channel::DeleteChannel()
{
	Network::Get()->Http().Delete(fmt::format("/channels/{:s}", GetId()));
}

void ChannelManager::Initialize()
{
	assert(m_Initialized != m_InitValue);

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_CREATE, [](json const &data)
	{
		PawnDispatcher::Get()->Dispatch([data]() mutable
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(data);
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			// forward DCC_OnChannelCreate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelCreate", channel_id);
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_UPDATE, [](json const &data)
	{
		Snowflake_t sfid;
		if (!utils::TryGetJsonValue(data, sfid, "id"))
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"invalid JSON: expected \"id\" in \"{}\"", data.dump());
			return;
		}

		Channel_t const &channel = ChannelManager::Get()->FindChannelById(sfid);
		if (!channel)
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"can't update channel: channel id \"{}\" not cached", sfid);
			return;
		}

		channel->Update(data);

		ChannelId_t const &pawnId = channel->GetPawnId();
		PawnDispatcher::Get()->Dispatch([pawnId]() mutable
		{
			// forward DCC_OnChannelUpdate(DCC_Channel:channel);
			pawn_cb::Error error;
			pawn_cb::Callback::CallFirst(error, "DCC_OnChannelUpdate", pawnId);
		});
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::CHANNEL_DELETE, [](json const &data)
	{
		ChannelManager::Get()->DeleteChannel(data);
	});

	Network::Get()->WebSocket().RegisterEvent(WebSocket::Event::READY, [this](json const &data)
	{
		static const char *PRIVATE_CHANNEL_KEY = "private_channels";
		if (utils::IsValidJson(data, PRIVATE_CHANNEL_KEY, json::value_t::array))
		{
			for (auto const &c : data.at(PRIVATE_CHANNEL_KEY))
				AddChannel(c);
		}
		else
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"invalid JSON: expected \"{}\" in \"{}\"", PRIVATE_CHANNEL_KEY, data.dump());
		}
		m_Initialized++;
	});
}

bool ChannelManager::IsInitialized()
{
	return m_Initialized == m_InitValue;
}

bool ChannelManager::CreateGuildChannel(Guild_t const &guild,
	std::string const &name, Channel::Type type, pawn_cb::Callback_t &&cb)
{
	json data = {
		{ "name", name },
		{ "type", static_cast<int>(type) }
	};

	std::string json_str;
	if (!utils::TryDumpJson(data, json_str))
	{
		Logger::Get()->Log(LogLevel::ERROR, "can't serialize JSON: {}", json_str);
		return false;
	}

	Network::Get()->Http().Post(fmt::format("/guilds/{:s}/channels", guild->GetId()), json_str,
		[this, cb](Http::Response r)
	{
		Logger::Get()->Log(LogLevel::DEBUG,
			"channel create response: status {}; body: {}; add: {}",
			r.status, r.body, r.additional_data);
		if (r.status / 100 == 2) // success
		{
			auto const channel_id = ChannelManager::Get()->AddChannel(json::parse(r.body));
			if (channel_id == INVALID_CHANNEL_ID)
				return;

			if (cb)
			{
				PawnDispatcher::Get()->Dispatch([=]()
				{
					m_CreatedChannelId = channel_id;
					cb->Execute();
					m_CreatedChannelId = INVALID_CHANNEL_ID;
				});
			}
		}
	});

	return true;
}

ChannelId_t ChannelManager::AddChannel(json const &data, GuildId_t guild_id/* = 0*/)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return INVALID_CHANNEL_ID;
	}

	Channel_t const &channel = FindChannelById(sfid);
	if (channel)
		return channel->GetPawnId(); // channel already exists

	ChannelId_t id = 1;
	while (m_Channels.find(id) != m_Channels.end())
		++id;

	if (!m_Channels.emplace(id, Channel_t(new Channel(id, data, guild_id))).second)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"can't create channel: duplicate key '{}'", id);
		return INVALID_CHANNEL_ID;
	}

	Logger::Get()->Log(LogLevel::INFO, "successfully added channel with id '{}'", id);
	return id;
}

void ChannelManager::DeleteChannel(json const &data)
{
	Snowflake_t sfid;
	if (!utils::TryGetJsonValue(data, sfid, "id"))
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"invalid JSON: expected \"id\" in \"{}\"", data.dump());
		return;
	}

	PawnDispatcher::Get()->Dispatch([this, sfid]()
	{
		Channel_t const &channel = FindChannelById(sfid);
		if (!channel)
		{
			Logger::Get()->Log(LogLevel::ERROR,
				"can't delete channel: channel id \"{}\" not cached", sfid);
			return;
		}

		// forward DCC_OnChannelDelete(DCC_Channel:channel);
		pawn_cb::Error error;
		pawn_cb::Callback::CallFirst(error, "DCC_OnChannelDelete", channel->GetPawnId());

		Guild_t const &guild = GuildManager::Get()->FindGuild(channel->GetGuildId());
		if (guild)
			guild->RemoveChannel(channel->GetPawnId());

		m_Channels.erase(channel->GetPawnId());
	});

}

Channel_t const &ChannelManager::FindChannel(ChannelId_t id)
{
	static Channel_t invalid_channel;
	auto it = m_Channels.find(id);
	if (it == m_Channels.end())
		return invalid_channel;
	return it->second;
}

Channel_t const &ChannelManager::FindChannelByName(std::string const &name)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetName().compare(name) == 0)
			return channel;
	}
	return invalid_channel;
}

Channel_t const &ChannelManager::FindChannelById(Snowflake_t const &sfid)
{
	static Channel_t invalid_channel;
	for (auto const &c : m_Channels)
	{
		Channel_t const &channel = c.second;
		if (channel->GetId().compare(sfid) == 0)
			return channel;
	}
	return invalid_channel;
}
<|endoftext|>


<commit_before>
/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * ``The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is SimpleAmqpClient for RabbitMQ.
 *
 * The Initial Developer of the Original Code is Alan Antonuk.
 * Original code is Copyright (C) Alan Antonuk.
 *
 * All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU General Public License Version 2 or later (the "GPL"), in
 * which case the provisions of the GPL are applicable instead of those
 * above. If you wish to allow use of your version of this file only
 * under the terms of the GPL, and not to allow others to use your
 * version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the
 * notice and other provisions required by the GPL. If you do not
 * delete the provisions above, a recipient may use your version of
 * this file under the terms of any one of the MPL or the GPL.
 *
 * ***** END LICENSE BLOCK *****
 */

#include "SimpleAmqpClient/Channel.h"

#include "SimpleAmqpClient/Util.h"
#include "config.h"

#include <amqp_framing.h>

#include <stdexcept>

#include <boost/cstdint.hpp>
#include <boost/limits.hpp>

// This will get us the posix version of strerror_r() on linux
#define _XOPEN_SOURCE 600
#include <string.h>
#include <sys/types.h>
#include <errno.h>

#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif

#ifdef HAVE_WINSOCK2_H
# include <WinSock2.h>
#endif

#include <time.h>

// Win32 headers seem to define this annoyingly...
#ifdef max
# undef max
#endif

namespace AmqpClient {

const amqp_table_t Channel::EMPTY_TABLE = { 0, NULL };
const std::string Channel::EXCHANGE_TYPE_DIRECT("amq.direct");
const std::string Channel::EXCHANGE_TYPE_FANOUT("fanout");
const std::string Channel::EXCHANGE_TYPE_TOPIC("topic");

Channel::Channel(const std::string& host,
                 int port,
                 const std::string& username,
                 const std::string& password,
                 const std::string& vhost,
                 int frame_max) :
    m_channel(DEFAULT_CHANNEL)
{
    m_connection = amqp_new_connection();

    int sock = amqp_open_socket(host.c_str(), port);
    Util::CheckForError(sock, "Channel::Channel amqp_open_socket");

    amqp_set_sockfd(m_connection, sock);

    Util::CheckRpcReply(amqp_login(m_connection, vhost.c_str(), 2,
                                   frame_max, BROKER_HEARTBEAT, AMQP_SASL_METHOD_PLAIN,
                                   username.c_str(), password.c_str()), "Amqp Login");

    amqp_channel_open(m_connection, m_channel);
    Util::CheckLastRpcReply(m_connection, "Channel::Channel creating default channel");
}

Channel::~Channel()
{
    amqp_channel_close(m_connection, m_channel, AMQP_REPLY_SUCCESS);
    amqp_connection_close(m_connection, AMQP_REPLY_SUCCESS);
    amqp_destroy_connection(m_connection);
}

void Channel::DeclareExchange(const std::string& exchange_name,
                              const std::string& exchange_type,
                              bool passive,
                              bool durable,
                              bool auto_delete)
{
    amqp_exchange_declare(m_connection, m_channel,
                          amqp_cstring_bytes(exchange_name.c_str()),
                          amqp_cstring_bytes(exchange_type.c_str()),
                          passive,
                          durable,
                          EMPTY_TABLE);
	Util::CheckLastRpcReply(m_connection, "Declaring exchange");
}

void Channel::DeleteExchange(const std::string& exchange_name,
                             bool if_unused,
                             bool nowait)
{
	amqp_method_number_t replies[2] = { AMQP_EXCHANGE_DELETE_OK_METHOD, 0 };
	amqp_exchange_delete_t req;
	req.exchange = amqp_cstring_bytes(exchange_name.c_str());
	req.if_unused = if_unused;
	req.nowait = nowait;

	Util::CheckRpcReply(amqp_simple_rpc(m_connection, m_channel,
				AMQP_EXCHANGE_DELETE_METHOD,
				replies, &req), "Delete Exchange");
}

std::string Channel::DeclareQueue(const std::string& queue_name,
          		                  bool passive,
								  bool durable,
								  bool exclusive,
								  bool auto_delete)
{

    amqp_queue_declare_ok_t* queue_declare =
			amqp_queue_declare(m_connection, m_channel,
								amqp_cstring_bytes(queue_name.c_str()),
								passive,
								durable,
								exclusive,
								auto_delete,
								EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Declaring queue");

	return std::string((char*)queue_declare->queue.bytes,
			queue_declare->queue.len);
}

void Channel::DeleteQueue(const std::string& queue_name,
                          bool if_unused,
                          bool if_empty)
{
    amqp_queue_delete(m_connection, m_channel,
                      amqp_cstring_bytes(queue_name.c_str()),
                      if_unused,
                      if_empty);

	Util::CheckLastRpcReply(m_connection, "Deleting Queue");
}

void Channel::BindQueue(const std::string& queue_name,
                        const std::string& exchange_name,
                        const std::string& routing_key)
{
    amqp_queue_bind(m_connection, m_channel,
                    amqp_cstring_bytes(queue_name.c_str()),
                    amqp_cstring_bytes(exchange_name.c_str()),
                    amqp_cstring_bytes(routing_key.c_str()),
                    EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Binding queue");
}

void Channel::UnbindQueue(const std::string& queue_name,
                          const std::string& exchange_name,
                          const std::string& binding_key)
{
    amqp_queue_unbind(m_connection, m_channel,
                      amqp_cstring_bytes(queue_name.c_str()),
                      amqp_cstring_bytes(exchange_name.c_str()),
                      amqp_cstring_bytes(binding_key.c_str()),
                      EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Unbinding queue");
}

void Channel::BasicAck(const BasicMessage::ptr_t message)
{
	BasicAck(message->DeliveryTag());
}

void Channel::BasicAck(uint64_t delivery_tag)
{
	Util::CheckForError(amqp_basic_ack(m_connection, m_channel,
			delivery_tag,
			false), "Ack");

}
void Channel::BasicPublish(const std::string& exchange_name,
                           const std::string& routing_key,
                           const BasicMessage::ptr_t message,
                           bool mandatory,
                           bool immediate)
{
    amqp_basic_publish(m_connection, m_channel,
                       amqp_cstring_bytes(exchange_name.c_str()),
                       amqp_cstring_bytes(routing_key.c_str()),
                       mandatory,
                       immediate,
                       message->getAmqpProperties(),
                       message->getAmqpBody());

	Util::CheckLastRpcReply(m_connection, "Publishing to queue");
}

void Channel::BasicConsume(const std::string& queue,
						   const std::string& consumer_tag,
						   bool no_local,
						   bool no_ack,
						   bool exclusive)
{
	amqp_basic_consume(m_connection, m_channel,
			amqp_cstring_bytes(queue.c_str()),
			amqp_cstring_bytes(consumer_tag.c_str()),
			no_local,
			no_ack,
			exclusive,
      EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Basic Consume");
}

void Channel::BasicCancel(const std::string& consumer_tag)
{
	amqp_method_number_t replies[2] = { AMQP_BASIC_CANCEL_OK_METHOD, 0 };
	amqp_basic_cancel_t req;
	req.consumer_tag = amqp_cstring_bytes(consumer_tag.c_str());
	req.nowait = 0;

	Util::CheckRpcReply(amqp_simple_rpc(m_connection, m_channel,
				AMQP_BASIC_CANCEL_METHOD,
				replies, &req), "Basic Cancel");
}

BasicMessage::ptr_t Channel::BasicConsumeMessage()
{
	BasicMessage::ptr_t returnval;
	BasicConsumeMessage(returnval, 0);
	return returnval;
}

bool Channel::BasicConsumeMessage(BasicMessage::ptr_t& message, int timeout)
{

	int socketno = amqp_get_sockfd(m_connection);

	struct timeval tv_timeout;
	memset(&tv_timeout, 0, sizeof(tv_timeout));
	tv_timeout.tv_sec = timeout;

	struct timeval tv_zero;
	memset(&tv_zero, 0, sizeof(tv_zero));
	tv_zero.tv_sec = 0;

	while (true)
	{
		amqp_frame_t frame;
		amqp_maybe_release_buffers(m_connection);

		// Possibly set a timeout on receiving
		// We only do this on the first frame otherwise we'd confuse
		// This function if it immediately turns around and gets called again
		if (timeout > 0)
		{
			if (setsockopt(socketno, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_timeout, sizeof(tv_timeout)))
			{

				std::string error_string("Setting socket timeout failed (setsockopt) ");
#ifdef HAVE_STRERROR_S
        const int BUFFER_LENGTH = 256;
        char error_string_buffer[BUFFER_LENGTH] = {0};
        strerror_s(error_string_buffer, errno);
        error_string += error_string_buffer;
#elif defined(HAVE_STRERROR_R)
				const int BUFFER_LENGTH = 256;
				char error_string_buffer[BUFFER_LENGTH] = {0};
				strerror_r(errno, error_string_buffer, BUFFER_LENGTH);
        error_string += error_string_buffer;
#else
        error_string += strerror(errno);
#endif

				throw std::runtime_error(error_string.c_str());
			}
		}

		int ret = amqp_simple_wait_frame(m_connection, &frame);
		// Save errno as it might be overwritten by setsockopt
		int errno_save = errno;

		setsockopt(socketno, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_zero, sizeof(tv_zero));

		if (ret != 0)
		{
#ifdef HAVE_WINSOCK2_H
			int wsa_err = (-ret) & ~(1 << 29);
			if (wsa_err == WSAETIMEDOUT)
			{
				return false;
			}
#else // HAVE_WINSOCK2_H
			// Interrupted system call, just loop around and try it again
			if (errno_save == EINTR)
			{
				continue;
			}
			else if (errno_save == EAGAIN || errno_save == EWOULDBLOCK)
			{
				return false;
			}
#endif
		}

		Util::CheckForError(ret, "Consume Message: method frame");

		if (frame.frame_type != AMQP_FRAME_METHOD || frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD)
			continue;

		amqp_basic_deliver_t* deliver_method = reinterpret_cast<amqp_basic_deliver_t*>(frame.payload.method.decoded);

		// Wait for frame #2, the header frame which contains body size
		Util::CheckForError(amqp_simple_wait_frame(m_connection, &frame), "Consume Message: header frame");

		if (frame.frame_type != AMQP_FRAME_HEADER)
			throw std::runtime_error("Channel::BasicConsumeMessage: receieved unexpected frame type (was expected AMQP_FRAME_HEADER)");

		amqp_basic_properties_t* properties = reinterpret_cast<amqp_basic_properties_t*>(frame.payload.properties.decoded);

		size_t body_size = frame.payload.properties.body_size;
		size_t received_size = 0;
		amqp_bytes_t body = amqp_bytes_malloc(body_size);

		// frame #3 and up:
		while (received_size < body_size)
		{
			Util::CheckForError(amqp_simple_wait_frame(m_connection, &frame), "Consume Message: body frame");

			if (frame.frame_type != AMQP_FRAME_BODY)
				throw std::runtime_error("Channel::BasicConsumeMessge: received unexpected frame type (was expecting AMQP_FRAME_BODY)");

			void* body_ptr = reinterpret_cast<char*>(body.bytes) + received_size;
			memcpy(body_ptr, frame.payload.body_fragment.bytes, frame.payload.body_fragment.len);
			received_size += frame.payload.body_fragment.len;
		}

		message = BasicMessage::Create(body, properties, deliver_method->delivery_tag);
		return true;
	}
}

void Channel::ResetChannel()
{
  Util::CheckRpcReply(amqp_channel_close(m_connection, m_channel, AMQP_REPLY_SUCCESS), "ResetChannel: closing channel");
  m_channel = (m_channel + 1) % std::numeric_limits<uint16_t>::max();
  amqp_channel_open(m_connection, m_channel);
  Util::CheckLastRpcReply(m_connection, "ResetChannel: opening channel");
}

} // namespace AmqpClient
<commit_msg>Pass the correct arguments to setsockopt on Win32<commit_after>
/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * ``The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is SimpleAmqpClient for RabbitMQ.
 *
 * The Initial Developer of the Original Code is Alan Antonuk.
 * Original code is Copyright (C) Alan Antonuk.
 *
 * All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU General Public License Version 2 or later (the "GPL"), in
 * which case the provisions of the GPL are applicable instead of those
 * above. If you wish to allow use of your version of this file only
 * under the terms of the GPL, and not to allow others to use your
 * version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the
 * notice and other provisions required by the GPL. If you do not
 * delete the provisions above, a recipient may use your version of
 * this file under the terms of any one of the MPL or the GPL.
 *
 * ***** END LICENSE BLOCK *****
 */

#include "SimpleAmqpClient/Channel.h"

#include "SimpleAmqpClient/Util.h"
#include "config.h"

#include <amqp_framing.h>

#include <stdexcept>

#include <boost/cstdint.hpp>
#include <boost/limits.hpp>

// This will get us the posix version of strerror_r() on linux
#define _XOPEN_SOURCE 600
#include <string.h>
#include <sys/types.h>
#include <errno.h>

#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif

#ifdef HAVE_WINSOCK2_H
# include <WinSock2.h>
#endif

#include <time.h>

// Win32 headers seem to define this annoyingly...
#ifdef max
# undef max
#endif

namespace AmqpClient {

const amqp_table_t Channel::EMPTY_TABLE = { 0, NULL };
const std::string Channel::EXCHANGE_TYPE_DIRECT("amq.direct");
const std::string Channel::EXCHANGE_TYPE_FANOUT("fanout");
const std::string Channel::EXCHANGE_TYPE_TOPIC("topic");

Channel::Channel(const std::string& host,
                 int port,
                 const std::string& username,
                 const std::string& password,
                 const std::string& vhost,
                 int frame_max) :
    m_channel(DEFAULT_CHANNEL)
{
    m_connection = amqp_new_connection();

    int sock = amqp_open_socket(host.c_str(), port);
    Util::CheckForError(sock, "Channel::Channel amqp_open_socket");

    amqp_set_sockfd(m_connection, sock);

    Util::CheckRpcReply(amqp_login(m_connection, vhost.c_str(), 2,
                                   frame_max, BROKER_HEARTBEAT, AMQP_SASL_METHOD_PLAIN,
                                   username.c_str(), password.c_str()), "Amqp Login");

    amqp_channel_open(m_connection, m_channel);
    Util::CheckLastRpcReply(m_connection, "Channel::Channel creating default channel");
}

Channel::~Channel()
{
    amqp_channel_close(m_connection, m_channel, AMQP_REPLY_SUCCESS);
    amqp_connection_close(m_connection, AMQP_REPLY_SUCCESS);
    amqp_destroy_connection(m_connection);
}

void Channel::DeclareExchange(const std::string& exchange_name,
                              const std::string& exchange_type,
                              bool passive,
                              bool durable,
                              bool auto_delete)
{
    amqp_exchange_declare(m_connection, m_channel,
                          amqp_cstring_bytes(exchange_name.c_str()),
                          amqp_cstring_bytes(exchange_type.c_str()),
                          passive,
                          durable,
                          EMPTY_TABLE);
	Util::CheckLastRpcReply(m_connection, "Declaring exchange");
}

void Channel::DeleteExchange(const std::string& exchange_name,
                             bool if_unused,
                             bool nowait)
{
	amqp_method_number_t replies[2] = { AMQP_EXCHANGE_DELETE_OK_METHOD, 0 };
	amqp_exchange_delete_t req;
	req.exchange = amqp_cstring_bytes(exchange_name.c_str());
	req.if_unused = if_unused;
	req.nowait = nowait;

	Util::CheckRpcReply(amqp_simple_rpc(m_connection, m_channel,
				AMQP_EXCHANGE_DELETE_METHOD,
				replies, &req), "Delete Exchange");
}

std::string Channel::DeclareQueue(const std::string& queue_name,
          		                  bool passive,
								  bool durable,
								  bool exclusive,
								  bool auto_delete)
{

    amqp_queue_declare_ok_t* queue_declare =
			amqp_queue_declare(m_connection, m_channel,
								amqp_cstring_bytes(queue_name.c_str()),
								passive,
								durable,
								exclusive,
								auto_delete,
								EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Declaring queue");

	return std::string((char*)queue_declare->queue.bytes,
			queue_declare->queue.len);
}

void Channel::DeleteQueue(const std::string& queue_name,
                          bool if_unused,
                          bool if_empty)
{
    amqp_queue_delete(m_connection, m_channel,
                      amqp_cstring_bytes(queue_name.c_str()),
                      if_unused,
                      if_empty);

	Util::CheckLastRpcReply(m_connection, "Deleting Queue");
}

void Channel::BindQueue(const std::string& queue_name,
                        const std::string& exchange_name,
                        const std::string& routing_key)
{
    amqp_queue_bind(m_connection, m_channel,
                    amqp_cstring_bytes(queue_name.c_str()),
                    amqp_cstring_bytes(exchange_name.c_str()),
                    amqp_cstring_bytes(routing_key.c_str()),
                    EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Binding queue");
}

void Channel::UnbindQueue(const std::string& queue_name,
                          const std::string& exchange_name,
                          const std::string& binding_key)
{
    amqp_queue_unbind(m_connection, m_channel,
                      amqp_cstring_bytes(queue_name.c_str()),
                      amqp_cstring_bytes(exchange_name.c_str()),
                      amqp_cstring_bytes(binding_key.c_str()),
                      EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Unbinding queue");
}

void Channel::BasicAck(const BasicMessage::ptr_t message)
{
	BasicAck(message->DeliveryTag());
}

void Channel::BasicAck(uint64_t delivery_tag)
{
	Util::CheckForError(amqp_basic_ack(m_connection, m_channel,
			delivery_tag,
			false), "Ack");

}
void Channel::BasicPublish(const std::string& exchange_name,
                           const std::string& routing_key,
                           const BasicMessage::ptr_t message,
                           bool mandatory,
                           bool immediate)
{
    amqp_basic_publish(m_connection, m_channel,
                       amqp_cstring_bytes(exchange_name.c_str()),
                       amqp_cstring_bytes(routing_key.c_str()),
                       mandatory,
                       immediate,
                       message->getAmqpProperties(),
                       message->getAmqpBody());

	Util::CheckLastRpcReply(m_connection, "Publishing to queue");
}

void Channel::BasicConsume(const std::string& queue,
						   const std::string& consumer_tag,
						   bool no_local,
						   bool no_ack,
						   bool exclusive)
{
	amqp_basic_consume(m_connection, m_channel,
			amqp_cstring_bytes(queue.c_str()),
			amqp_cstring_bytes(consumer_tag.c_str()),
			no_local,
			no_ack,
			exclusive,
      EMPTY_TABLE);

	Util::CheckLastRpcReply(m_connection, "Basic Consume");
}

void Channel::BasicCancel(const std::string& consumer_tag)
{
	amqp_method_number_t replies[2] = { AMQP_BASIC_CANCEL_OK_METHOD, 0 };
	amqp_basic_cancel_t req;
	req.consumer_tag = amqp_cstring_bytes(consumer_tag.c_str());
	req.nowait = 0;

	Util::CheckRpcReply(amqp_simple_rpc(m_connection, m_channel,
				AMQP_BASIC_CANCEL_METHOD,
				replies, &req), "Basic Cancel");
}

BasicMessage::ptr_t Channel::BasicConsumeMessage()
{
	BasicMessage::ptr_t returnval;
	BasicConsumeMessage(returnval, 0);
	return returnval;
}

bool Channel::BasicConsumeMessage(BasicMessage::ptr_t& message, int timeout)
{

	int socketno = amqp_get_sockfd(m_connection);
#ifdef HAVE_WINSOCK2_H
  // Timeouts on Winsock are a DWORD, and are in MS
  uint32_t tv_timeout = timeout * 1000;
  uint32_t tv_zero = 0;
#else
	struct timeval tv_timeout;
	memset(&tv_timeout, 0, sizeof(tv_timeout));
	tv_timeout.tv_sec = timeout;

	struct timeval tv_zero;
	memset(&tv_zero, 0, sizeof(tv_zero));
	tv_zero.tv_sec = 0;
#endif

	while (true)
	{
		amqp_frame_t frame;
		amqp_maybe_release_buffers(m_connection);

		// Possibly set a timeout on receiving
		// We only do this on the first frame otherwise we'd confuse
		// This function if it immediately turns around and gets called again
		if (timeout > 0)
		{
			if (setsockopt(socketno, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_timeout, sizeof(tv_timeout)))
			{

				std::string error_string("Setting socket timeout failed (setsockopt) ");
#ifdef HAVE_STRERROR_S
        const int BUFFER_LENGTH = 256;
        char error_string_buffer[BUFFER_LENGTH] = {0};
        strerror_s(error_string_buffer, errno);
        error_string += error_string_buffer;
#elif defined(HAVE_STRERROR_R)
				const int BUFFER_LENGTH = 256;
				char error_string_buffer[BUFFER_LENGTH] = {0};
				strerror_r(errno, error_string_buffer, BUFFER_LENGTH);
        error_string += error_string_buffer;
#else
        error_string += strerror(errno);
#endif

				throw std::runtime_error(error_string.c_str());
			}
		}

		int ret = amqp_simple_wait_frame(m_connection, &frame);
		// Save errno as it might be overwritten by setsockopt
		int errno_save = errno;

		setsockopt(socketno, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_zero, sizeof(tv_zero));

		if (ret != 0)
		{
#ifdef HAVE_WINSOCK2_H
			int wsa_err = (-ret) & ~(1 << 29);
			if (wsa_err == WSAETIMEDOUT)
			{
				return false;
			}
#else // HAVE_WINSOCK2_H
			// Interrupted system call, just loop around and try it again
			if (errno_save == EINTR)
			{
				continue;
			}
			else if (errno_save == EAGAIN || errno_save == EWOULDBLOCK)
			{
				return false;
			}
#endif
		}

		Util::CheckForError(ret, "Consume Message: method frame");

		if (frame.frame_type != AMQP_FRAME_METHOD || frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD)
			continue;

		amqp_basic_deliver_t* deliver_method = reinterpret_cast<amqp_basic_deliver_t*>(frame.payload.method.decoded);

		// Wait for frame #2, the header frame which contains body size
		Util::CheckForError(amqp_simple_wait_frame(m_connection, &frame), "Consume Message: header frame");

		if (frame.frame_type != AMQP_FRAME_HEADER)
			throw std::runtime_error("Channel::BasicConsumeMessage: receieved unexpected frame type (was expected AMQP_FRAME_HEADER)");

		amqp_basic_properties_t* properties = reinterpret_cast<amqp_basic_properties_t*>(frame.payload.properties.decoded);

		size_t body_size = frame.payload.properties.body_size;
		size_t received_size = 0;
		amqp_bytes_t body = amqp_bytes_malloc(body_size);

		// frame #3 and up:
		while (received_size < body_size)
		{
			Util::CheckForError(amqp_simple_wait_frame(m_connection, &frame), "Consume Message: body frame");

			if (frame.frame_type != AMQP_FRAME_BODY)
				throw std::runtime_error("Channel::BasicConsumeMessge: received unexpected frame type (was expecting AMQP_FRAME_BODY)");

			void* body_ptr = reinterpret_cast<char*>(body.bytes) + received_size;
			memcpy(body_ptr, frame.payload.body_fragment.bytes, frame.payload.body_fragment.len);
			received_size += frame.payload.body_fragment.len;
		}

		message = BasicMessage::Create(body, properties, deliver_method->delivery_tag);
		return true;
	}
}

void Channel::ResetChannel()
{
  Util::CheckRpcReply(amqp_channel_close(m_connection, m_channel, AMQP_REPLY_SUCCESS), "ResetChannel: closing channel");
  m_channel = (m_channel + 1) % std::numeric_limits<uint16_t>::max();
  amqp_channel_open(m_connection, m_channel);
  Util::CheckLastRpcReply(m_connection, "ResetChannel: opening channel");
}

} // namespace AmqpClient
<|endoftext|>


<commit_before>#include "CryFuse.h"

#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <cassert>

#include "cryfs_lib/CryNode.h"
#include "cryfs_lib/CryErrnoException.h"

#define UNUSED(expr) (void)(expr)

using fusepp::path;

namespace cryfs {

CryFuse::CryFuse(CryDevice *device)
  :_device(device) {
}

int CryFuse::getattr(const path &path, struct stat *stbuf) {
  try {
    _device->lstat(path, stbuf);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) {
  //printf("fgetattr(%s, _, _)\n", path.c_str());

  // On FreeBSD, trying to do anything with the mountpoint ends up
  // opening it, and then using the FD for an fgetattr.  So in the
  // special case of a path of "/", I need to do a getattr on the
  // underlying root directory instead of doing the fgetattr().
  // TODO Check if necessary
  if (path.native() == "/") {
    return getattr(path, stbuf);
  }

  try {
	_device->fstat(fileinfo->fh, stbuf);
	return 0;
  } catch(cryfs::CryErrnoException &e) {
	  return -e.getErrno();
  }
}

//TODO
int CryFuse::readlink(const path &path, char *buf, size_t size) {
  //printf("readlink(%s, _, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size,
  //but the posix version does not and also doesn't append one.
  int real_size = ::readlink(real_path.c_str(), buf, size-1);
  if (real_size < 0) {
    return -errno;
  }
  //Terminate the string
  buf[real_size] = '\0';

  return 0;
}

int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) {
  UNUSED(rdev);
  UNUSED(mode);
  UNUSED(path);
  printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode);
  return 0;
}

int CryFuse::mkdir(const path &path, mode_t mode) {
  //printf("mkdir(%s, %d)\n", path.c_str(), mode);
  try {
    _device->mkdir(path, mode);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::unlink(const path &path) {
  //printf("unlink(%s)\n", path.c_str());
  try {
    _device->unlink(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::rmdir(const path &path) {
  try {
    _device->rmdir(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::symlink(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: symlink(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::symlink(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::rename(const path &from, const path &to) {
  //printf("rename(%s, %s)\n", from.c_str(), to.c_str());
  try {
    _device->rename(from, to);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::link(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: link(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::link(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chmod(const path &path, mode_t mode) {
  printf("NOT IMPLEMENTED: chmod(%s, %d)\n", path.c_str(), mode);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chmod(real_path.c_str(), mode);
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chown(const path &path, uid_t uid, gid_t gid) {
  printf("NOT IMPLEMENTED: chown(%s, %d, %d)\n", path.c_str(), uid, gid);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chown(real_path.c_str(), uid, gid);
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::truncate(const path &path, off_t size) {
  //printf("truncate(%s, %zu)\n", path.c_str(), size);
  try {
    _device->truncate(path, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) {
  //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size);
	UNUSED(path);
  try {
    _device->ftruncate(fileinfo->fh, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::utimens(const path &path, const timespec times[2]) {
  //printf("utimens(%s, _)\n", path.c_str());
  try {
    _device->utimens(path, times);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::open(const path &path, fuse_file_info *fileinfo) {
  //printf("open(%s, _)\n", path.c_str());
  try {
	  fileinfo->fh = _device->openFile(path, fileinfo->flags);
	  return 0;
  } catch (CryErrnoException &e) {
	  return -e.getErrno();
  }
}

int CryFuse::release(const path &path, fuse_file_info *fileinfo) {
  //printf("release(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
	  _device->closeFile(fileinfo->fh);
	  return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    //printf("Reading from file %d\n", fileinfo->fh);
    //fflush(stdout);
    return _device->read(fileinfo->fh, buf, size, offset);
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    _device->write(fileinfo->fh, buf, size, offset);
    return size;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::statfs(const path &path, struct statvfs *fsstat) {
  //printf("statfs(%s, _)\n", path.c_str());
  try {
    _device->statfs(path, fsstat);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::flush(const path &path, fuse_file_info *fileinfo) {
  //printf("Called non-implemented flush(%s, _)\n", path.c_str());
  UNUSED(path);
  UNUSED(fileinfo);
  return 0;
}

int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) {
  //printf("fsync(%s, %d, _)\n", path.c_str(), datasync);
  UNUSED(path);
  try {
    if (datasync) {
      _device->fdatasync(fileinfo->fh);
    } else {
      _device->fsync(fileinfo->fh);
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) {
  //printf("opendir(%s, _)\n", path.c_str());
  try {
    fileinfo->fh = _device->openDir(path);
    return 0;
  } catch(CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) {
  UNUSED(path);
  //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset);
  UNUSED(offset);
  try {
    auto entries = _device->readDir(fileinfo->fh);
    for (const auto &entry : *entries) {
      //TODO Also give file attributes (third param of filler)
      if (filler(buf, entry.c_str(), nullptr, 0) != 0) {
        return -ENOMEM;
      }
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) {
  //printf("releasedir(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
    _device->closeDir(fileinfo->fh);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) {
  UNUSED(fileinfo);
  UNUSED(datasync);
  UNUSED(path);
  //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync);
  return 0;
}

void CryFuse::init(fuse_conn_info *conn) {
  UNUSED(conn);
  //printf("init()\n");
}

void CryFuse::destroy() {
  //printf("destroy()\n");
}

int CryFuse::access(const path &path, int mask) {
  //printf("access(%s, %d)\n", path.c_str(), mask);
  try {
    _device->access(path, mask);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) {
  //printf("create(%s, %d, _)\n", path.c_str(), mode);
  try {
    fileinfo->fh = _device->createAndOpenFile(path, mode);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

} /* namespace cryfs */
<commit_msg>Fix error code<commit_after>#include "CryFuse.h"

#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <cassert>

#include "cryfs_lib/CryNode.h"
#include "cryfs_lib/CryErrnoException.h"

#define UNUSED(expr) (void)(expr)

using fusepp::path;

namespace cryfs {

CryFuse::CryFuse(CryDevice *device)
  :_device(device) {
}

int CryFuse::getattr(const path &path, struct stat *stbuf) {
  try {
    _device->lstat(path, stbuf);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) {
  //printf("fgetattr(%s, _, _)\n", path.c_str());

  // On FreeBSD, trying to do anything with the mountpoint ends up
  // opening it, and then using the FD for an fgetattr.  So in the
  // special case of a path of "/", I need to do a getattr on the
  // underlying root directory instead of doing the fgetattr().
  // TODO Check if necessary
  if (path.native() == "/") {
    return getattr(path, stbuf);
  }

  try {
	_device->fstat(fileinfo->fh, stbuf);
	return 0;
  } catch(cryfs::CryErrnoException &e) {
	  return -e.getErrno();
  }
}

//TODO
int CryFuse::readlink(const path &path, char *buf, size_t size) {
  //printf("readlink(%s, _, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size,
  //but the posix version does not and also doesn't append one.
  int real_size = ::readlink(real_path.c_str(), buf, size-1);
  if (real_size < 0) {
    return -errno;
  }
  //Terminate the string
  buf[real_size] = '\0';

  return 0;
}

int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) {
  UNUSED(rdev);
  UNUSED(mode);
  UNUSED(path);
  printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode);
  return ENOSYS;
}

int CryFuse::mkdir(const path &path, mode_t mode) {
  //printf("mkdir(%s, %d)\n", path.c_str(), mode);
  try {
    _device->mkdir(path, mode);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::unlink(const path &path) {
  //printf("unlink(%s)\n", path.c_str());
  try {
    _device->unlink(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::rmdir(const path &path) {
  try {
    _device->rmdir(path);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::symlink(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: symlink(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::symlink(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::rename(const path &from, const path &to) {
  //printf("rename(%s, %s)\n", from.c_str(), to.c_str());
  try {
    _device->rename(from, to);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::link(const path &from, const path &to) {
  printf("NOT IMPLEMENTED: link(%s, %s)\n", from.c_str(), to.c_str());
  //auto real_from = _device->RootDir() / from;
  //auto real_to = _device->RootDir() / to;
  //int retstat = ::link(real_from.c_str(), real_to.c_str());
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chmod(const path &path, mode_t mode) {
  printf("NOT IMPLEMENTED: chmod(%s, %d)\n", path.c_str(), mode);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chmod(real_path.c_str(), mode);
  //return errcode_map(retstat);
  return ENOSYS;
}

//TODO
int CryFuse::chown(const path &path, uid_t uid, gid_t gid) {
  printf("NOT IMPLEMENTED: chown(%s, %d, %d)\n", path.c_str(), uid, gid);
  //auto real_path = _device->RootDir() / path;
  //int retstat = ::chown(real_path.c_str(), uid, gid);
  //return errcode_map(retstat);
  return ENOSYS;
}

int CryFuse::truncate(const path &path, off_t size) {
  //printf("truncate(%s, %zu)\n", path.c_str(), size);
  try {
    _device->truncate(path, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) {
  //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size);
	UNUSED(path);
  try {
    _device->ftruncate(fileinfo->fh, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::utimens(const path &path, const timespec times[2]) {
  //printf("utimens(%s, _)\n", path.c_str());
  try {
    _device->utimens(path, times);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::open(const path &path, fuse_file_info *fileinfo) {
  //printf("open(%s, _)\n", path.c_str());
  try {
	  fileinfo->fh = _device->openFile(path, fileinfo->flags);
	  return 0;
  } catch (CryErrnoException &e) {
	  return -e.getErrno();
  }
}

int CryFuse::release(const path &path, fuse_file_info *fileinfo) {
  //printf("release(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
	  _device->closeFile(fileinfo->fh);
	  return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    //printf("Reading from file %d\n", fileinfo->fh);
    //fflush(stdout);
    return _device->read(fileinfo->fh, buf, size, offset);
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    _device->write(fileinfo->fh, buf, size, offset);
    return size;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::statfs(const path &path, struct statvfs *fsstat) {
  //printf("statfs(%s, _)\n", path.c_str());
  try {
    _device->statfs(path, fsstat);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::flush(const path &path, fuse_file_info *fileinfo) {
  //printf("Called non-implemented flush(%s, _)\n", path.c_str());
  UNUSED(path);
  UNUSED(fileinfo);
  return 0;
}

int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) {
  //printf("fsync(%s, %d, _)\n", path.c_str(), datasync);
  UNUSED(path);
  try {
    if (datasync) {
      _device->fdatasync(fileinfo->fh);
    } else {
      _device->fsync(fileinfo->fh);
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) {
  //printf("opendir(%s, _)\n", path.c_str());
  try {
    fileinfo->fh = _device->openDir(path);
    return 0;
  } catch(CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) {
  UNUSED(path);
  //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset);
  UNUSED(offset);
  try {
    auto entries = _device->readDir(fileinfo->fh);
    for (const auto &entry : *entries) {
      //TODO Also give file attributes (third param of filler)
      if (filler(buf, entry.c_str(), nullptr, 0) != 0) {
        return -ENOMEM;
      }
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) {
  //printf("releasedir(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
    _device->closeDir(fileinfo->fh);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) {
  UNUSED(fileinfo);
  UNUSED(datasync);
  UNUSED(path);
  //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync);
  return 0;
}

void CryFuse::init(fuse_conn_info *conn) {
  UNUSED(conn);
  //printf("init()\n");
}

void CryFuse::destroy() {
  //printf("destroy()\n");
}

int CryFuse::access(const path &path, int mask) {
  //printf("access(%s, %d)\n", path.c_str(), mask);
  try {
    _device->access(path, mask);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) {
  //printf("create(%s, %d, _)\n", path.c_str(), mode);
  try {
    fileinfo->fh = _device->createAndOpenFile(path, mode);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

} /* namespace cryfs */
<|endoftext|>


<commit_before>#include "CryFuse.h"

#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <cassert>

#include "cryfs_lib/CryNode.h"
#include "cryfs_lib/CryErrnoException.h"

#define UNUSED(expr) (void)(expr)

using fusepp::path;

namespace cryfs {

namespace {
  int errcode_map(int exit_status) {
    if (exit_status < 0) {
      return -errno;
    }
    return exit_status;
  }
}

CryFuse::CryFuse(CryDevice *device)
  :_device(device) {
}

int CryFuse::getattr(const path &path, struct stat *stbuf) {
  try {
    _device->lstat(path, stbuf);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) {
  //printf("fgetattr(%s, _, _)\n", path.c_str());

  // On FreeBSD, trying to do anything with the mountpoint ends up
  // opening it, and then using the FD for an fgetattr.  So in the
  // special case of a path of "/", I need to do a getattr on the
  // underlying root directory instead of doing the fgetattr().
  if (path.native() == "/") {
    return getattr(path, stbuf);
  }

  try {
	_device->fstat(fileinfo->fh, stbuf);
	return 0;
  } catch(cryfs::CryErrnoException &e) {
	  return -e.getErrno();
  }
}

int CryFuse::readlink(const path &path, char *buf, size_t size) {
  //printf("readlink(%s, _, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size,
  //but the posix version does not and also doesn't append one.
  int real_size = ::readlink(real_path.c_str(), buf, size-1);
  if (real_size < 0) {
    return -errno;
  }
  //Terminate the string
  buf[real_size] = '\0';

  return 0;
}

int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) {
  UNUSED(rdev);
  UNUSED(mode);
  UNUSED(path);
  printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode);
  return 0;
}

int CryFuse::mkdir(const path &path, mode_t mode) {
  //printf("mkdir(%s, %d)\n", path.c_str(), mode);
  auto real_path = _device->RootDir() / path;
  int retstat = ::mkdir(real_path.c_str(), mode);
  return errcode_map(retstat);
}

int CryFuse::unlink(const path &path) {
  //printf("unlink(%s)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::unlink(real_path.c_str());
  return errcode_map(retstat);
}

int CryFuse::rmdir(const path &path) {
  //printf("rmdir(%s)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::rmdir(real_path.c_str());
  return errcode_map(retstat);
}

int CryFuse::symlink(const path &from, const path &to) {
  //printf("symlink(%s, %s)\n", from.c_str(), to.c_str());
  auto real_from = _device->RootDir() / from;
  auto real_to = _device->RootDir() / to;
  int retstat = ::symlink(real_from.c_str(), real_to.c_str());
  return errcode_map(retstat);
}

int CryFuse::rename(const path &from, const path &to) {
  //printf("rename(%s, %s)\n", from.c_str(), to.c_str());
  auto real_from = _device->RootDir() / from;
  auto real_to = _device->RootDir() / to;
  int retstat = ::rename(real_from.c_str(), real_to.c_str());
  return errcode_map(retstat);
}

int CryFuse::link(const path &from, const path &to) {
  //printf("link(%s, %s)\n", from.c_str(), to.c_str());
  auto real_from = _device->RootDir() / from;
  auto real_to = _device->RootDir() / to;
  int retstat = ::link(real_from.c_str(), real_to.c_str());
  return errcode_map(retstat);
}

int CryFuse::chmod(const path &path, mode_t mode) {
  //printf("chmod(%s, %d)\n", path.c_str(), mode);
  auto real_path = _device->RootDir() / path;
  int retstat = ::chmod(real_path.c_str(), mode);
  return errcode_map(retstat);
}

int CryFuse::chown(const path &path, uid_t uid, gid_t gid) {
  //printf("chown(%s, %d, %d)\n", path.c_str(), uid, gid);
  auto real_path = _device->RootDir() / path;
  int retstat = ::chown(real_path.c_str(), uid, gid);
  return errcode_map(retstat);
}

int CryFuse::truncate(const path &path, off_t size) {
  //printf("truncate(%s, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  int retstat = ::truncate(real_path.c_str(), size);
  return errcode_map(retstat);
}

int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) {
  //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size);
	UNUSED(path);
  int retstat = ::ftruncate(fileinfo->fh, size);
  return errcode_map(retstat);
}

int CryFuse::utimens(const path &path, const timespec times[2]) {
  //printf("utimens(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  struct timeval tv[2];
  tv[0].tv_sec = times[0].tv_sec;
  tv[0].tv_usec = times[0].tv_nsec / 1000;
  tv[1].tv_sec = times[1].tv_sec;
  tv[1].tv_usec = times[1].tv_nsec / 1000;
  int retstat = ::lutimes(real_path.c_str(), tv);
  return errcode_map(retstat);
}

int CryFuse::open(const path &path, fuse_file_info *fileinfo) {
  //printf("open(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int fd = ::open(real_path.c_str(), fileinfo->flags);
  if (fd < 0) {
    return -errno;
  }
  fileinfo->fh = fd;
  return 0;
}

int CryFuse::release(const path &path, fuse_file_info *fileinfo) {
  //printf("release(%s, _)\n", path.c_str());
  UNUSED(path);
  int retstat = ::close(fileinfo->fh);
  return errcode_map(retstat);
}

int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  int retstat = ::pread(fileinfo->fh, buf, size, offset);
  return errcode_map(retstat);
}

int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  int retstat = ::pwrite(fileinfo->fh, buf, size, offset);
  return errcode_map(retstat);
}

int CryFuse::statfs(const path &path, struct statvfs *fsstat) {
  //printf("statfs(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::statvfs(real_path.c_str(), fsstat);
  return errcode_map(retstat);
}

int CryFuse::flush(const path &path, fuse_file_info *fileinfo) {
  //printf("Called non-implemented flush(%s, _)\n", path.c_str());
  UNUSED(path);
  UNUSED(fileinfo);
  return 0;
}

int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) {
  //printf("fsync(%s, %d, _)\n", path.c_str(), datasync);
  UNUSED(path);
  int retstat = 0;
  if (datasync) {
    retstat = ::fdatasync(fileinfo->fh);
  } else {
    retstat = ::fsync(fileinfo->fh);
  }
  return errcode_map(retstat);
}

int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) {
  //printf("opendir(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  DIR *dp = ::opendir(real_path.c_str());
  if (dp == nullptr) {
    return -errno;
  }
  fileinfo->fh = (intptr_t)dp;
  return 0;
}

int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) {
  //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset);
  UNUSED(offset);
  auto real_path = _device->RootDir() / path;

  DIR *dp = (DIR*)(uintptr_t)fileinfo->fh;
  struct dirent *de = ::readdir(dp);
  if (de == nullptr) {
    return -errno;
  }

  do {
    if (filler(buf, de->d_name, nullptr, 0) != 0) {
      return -ENOMEM;
    }
  } while ((de = ::readdir(dp)) != nullptr);

  return 0;
}

int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) {
  //printf("releasedir(%s, _)\n", path.c_str());
  UNUSED(path);
  int retstat = closedir((DIR*)(uintptr_t)fileinfo->fh);
  return errcode_map(retstat);
}

int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) {
  UNUSED(fileinfo);
  UNUSED(datasync);
  UNUSED(path);
  //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync);
  return 0;
}

void CryFuse::init(fuse_conn_info *conn) {
  UNUSED(conn);
  //printf("init()\n");
}

void CryFuse::destroy() {
  //printf("destroy()\n");
}

int CryFuse::access(const path &path, int mask) {
  //printf("access(%s, %d)\n", path.c_str(), mask);
  auto real_path = _device->RootDir() / path;
  int retstat = ::access(real_path.c_str(), mask);
  return errcode_map(retstat);
}

int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) {
  //printf("create(%s, %d, _)\n", path.c_str(), mode);
  auto real_path = _device->RootDir() / path;
  int fd = ::creat(real_path.c_str(), mode);
  if (fd < 0) {
    return -errno;
  }
  fileinfo->fh = fd;
  return 0;
}

} /* namespace cryfs */
<commit_msg>Implemented file operations using our class hierarchy<commit_after>#include "CryFuse.h"

#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <cassert>

#include "cryfs_lib/CryNode.h"
#include "cryfs_lib/CryErrnoException.h"

#define UNUSED(expr) (void)(expr)

using fusepp::path;

namespace cryfs {

namespace {
  int errcode_map(int exit_status) {
    if (exit_status < 0) {
      return -errno;
    }
    return exit_status;
  }
}

CryFuse::CryFuse(CryDevice *device)
  :_device(device) {
}

int CryFuse::getattr(const path &path, struct stat *stbuf) {
  try {
    _device->lstat(path, stbuf);
    return 0;
  } catch(cryfs::CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) {
  //printf("fgetattr(%s, _, _)\n", path.c_str());

  // On FreeBSD, trying to do anything with the mountpoint ends up
  // opening it, and then using the FD for an fgetattr.  So in the
  // special case of a path of "/", I need to do a getattr on the
  // underlying root directory instead of doing the fgetattr().
  // TODO Check if necessary
  if (path.native() == "/") {
    return getattr(path, stbuf);
  }

  try {
	_device->fstat(fileinfo->fh, stbuf);
	return 0;
  } catch(cryfs::CryErrnoException &e) {
	  return -e.getErrno();
  }
}

//TODO
int CryFuse::readlink(const path &path, char *buf, size_t size) {
  //printf("readlink(%s, _, %zu)\n", path.c_str(), size);
  auto real_path = _device->RootDir() / path;
  //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size,
  //but the posix version does not and also doesn't append one.
  int real_size = ::readlink(real_path.c_str(), buf, size-1);
  if (real_size < 0) {
    return -errno;
  }
  //Terminate the string
  buf[real_size] = '\0';

  return 0;
}

int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) {
  UNUSED(rdev);
  UNUSED(mode);
  UNUSED(path);
  printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode);
  return 0;
}

//TODO
int CryFuse::mkdir(const path &path, mode_t mode) {
  //printf("mkdir(%s, %d)\n", path.c_str(), mode);
  auto real_path = _device->RootDir() / path;
  int retstat = ::mkdir(real_path.c_str(), mode);
  return errcode_map(retstat);
}

//TODO
int CryFuse::unlink(const path &path) {
  //printf("unlink(%s)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::unlink(real_path.c_str());
  return errcode_map(retstat);
}

//TODO
int CryFuse::rmdir(const path &path) {
  //printf("rmdir(%s)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::rmdir(real_path.c_str());
  return errcode_map(retstat);
}

//TODO
int CryFuse::symlink(const path &from, const path &to) {
  //printf("symlink(%s, %s)\n", from.c_str(), to.c_str());
  auto real_from = _device->RootDir() / from;
  auto real_to = _device->RootDir() / to;
  int retstat = ::symlink(real_from.c_str(), real_to.c_str());
  return errcode_map(retstat);
}

//TODO
int CryFuse::rename(const path &from, const path &to) {
  //printf("rename(%s, %s)\n", from.c_str(), to.c_str());
  auto real_from = _device->RootDir() / from;
  auto real_to = _device->RootDir() / to;
  int retstat = ::rename(real_from.c_str(), real_to.c_str());
  return errcode_map(retstat);
}

//TODO
int CryFuse::link(const path &from, const path &to) {
  //printf("link(%s, %s)\n", from.c_str(), to.c_str());
  auto real_from = _device->RootDir() / from;
  auto real_to = _device->RootDir() / to;
  int retstat = ::link(real_from.c_str(), real_to.c_str());
  return errcode_map(retstat);
}

//TODO
int CryFuse::chmod(const path &path, mode_t mode) {
  //printf("chmod(%s, %d)\n", path.c_str(), mode);
  auto real_path = _device->RootDir() / path;
  int retstat = ::chmod(real_path.c_str(), mode);
  return errcode_map(retstat);
}

//TODO
int CryFuse::chown(const path &path, uid_t uid, gid_t gid) {
  //printf("chown(%s, %d, %d)\n", path.c_str(), uid, gid);
  auto real_path = _device->RootDir() / path;
  int retstat = ::chown(real_path.c_str(), uid, gid);
  return errcode_map(retstat);
}

int CryFuse::truncate(const path &path, off_t size) {
  //printf("truncate(%s, %zu)\n", path.c_str(), size);
  try {
    _device->truncate(path, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) {
  //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size);
	UNUSED(path);
  try {
    _device->ftruncate(fileinfo->fh, size);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::utimens(const path &path, const timespec times[2]) {
  //printf("utimens(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  struct timeval tv[2];
  tv[0].tv_sec = times[0].tv_sec;
  tv[0].tv_usec = times[0].tv_nsec / 1000;
  tv[1].tv_sec = times[1].tv_sec;
  tv[1].tv_usec = times[1].tv_nsec / 1000;
  int retstat = ::lutimes(real_path.c_str(), tv);
  return errcode_map(retstat);
}

int CryFuse::open(const path &path, fuse_file_info *fileinfo) {
  //printf("open(%s, _)\n", path.c_str());
  try {
	  fileinfo->fh = _device->openFile(path, fileinfo->flags);
	  return 0;
  } catch (CryErrnoException &e) {
	  return -e.getErrno();
  }
}

int CryFuse::release(const path &path, fuse_file_info *fileinfo) {
  //printf("release(%s, _)\n", path.c_str());
  UNUSED(path);
  try {
	  _device->closeFile(fileinfo->fh);
	  return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    _device->read(fileinfo->fh, buf, size, offset);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) {
  //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset);
  UNUSED(path);
  try {
    _device->write(fileinfo->fh, buf, size, offset);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::statfs(const path &path, struct statvfs *fsstat) {
  //printf("statfs(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  int retstat = ::statvfs(real_path.c_str(), fsstat);
  return errcode_map(retstat);
}

//TODO
int CryFuse::flush(const path &path, fuse_file_info *fileinfo) {
  //printf("Called non-implemented flush(%s, _)\n", path.c_str());
  UNUSED(path);
  UNUSED(fileinfo);
  return 0;
}

int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) {
  //printf("fsync(%s, %d, _)\n", path.c_str(), datasync);
  UNUSED(path);
  try {
    if (datasync) {
      _device->fdatasync(fileinfo->fh);
    } else {
      _device->fsync(fileinfo->fh);
    }
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

//TODO
int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) {
  //printf("opendir(%s, _)\n", path.c_str());
  auto real_path = _device->RootDir() / path;
  DIR *dp = ::opendir(real_path.c_str());
  if (dp == nullptr) {
    return -errno;
  }
  fileinfo->fh = (intptr_t)dp;
  return 0;
}

//TODO
int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) {
  //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset);
  UNUSED(offset);
  auto real_path = _device->RootDir() / path;

  DIR *dp = (DIR*)(uintptr_t)fileinfo->fh;
  struct dirent *de = ::readdir(dp);
  if (de == nullptr) {
    return -errno;
  }

  do {
    if (filler(buf, de->d_name, nullptr, 0) != 0) {
      return -ENOMEM;
    }
  } while ((de = ::readdir(dp)) != nullptr);

  return 0;
}

//TODO
int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) {
  //printf("releasedir(%s, _)\n", path.c_str());
  UNUSED(path);
  int retstat = closedir((DIR*)(uintptr_t)fileinfo->fh);
  return errcode_map(retstat);
}

//TODO
int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) {
  UNUSED(fileinfo);
  UNUSED(datasync);
  UNUSED(path);
  //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync);
  return 0;
}

void CryFuse::init(fuse_conn_info *conn) {
  UNUSED(conn);
  //printf("init()\n");
}

void CryFuse::destroy() {
  //printf("destroy()\n");
}

int CryFuse::access(const path &path, int mask) {
  //printf("access(%s, %d)\n", path.c_str(), mask);
  try {
    _device->access(path, mask);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) {
  //printf("create(%s, %d, _)\n", path.c_str(), mode);
  try {
    fileinfo->fh = _device->createFile(path, mode);
    return 0;
  } catch (CryErrnoException &e) {
    return -e.getErrno();
  }
}

} /* namespace cryfs */
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    Cylinder.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include "Cylinder.hh"

// Description
// Construct cylinder with height of 1.0 and radius of 0.5.
vlCylinder::vlCylinder()
{
  this->Height = 1.0;
  this->Radius = 0.5;
}

// Description
// Evaluate cylinder equation R^2 - ((x-x0)^2 + (y-y0)^2 + (z-z0)^2) = 0.
float vlCylinder::EvaluateFunction(float x[3])
{
  return 0;
}

// Description
// Evaluate cylinder function gradient.
void vlCylinder::EvaluateGradient(float x[3], float g[3])
{
}

void vlCylinder::PrintSelf(ostream& os, vlIndent indent)
{
  vlImplicitFunction::PrintSelf(os,indent);

  os << indent << "Height: " << this->Height << "\n";
  os << indent << "Radius: " << this->Radius << "\n";
}
<commit_msg>ENH: Final definition.<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    Cylinder.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include "Cylinder.hh"

// Description
// Construct cylinder radius of 0.5.
vlCylinder::vlCylinder()
{
  this->Radius = 0.5;
}

// Description
// Evaluate cylinder equation R^2 - ((x-x0)^2 + (y-y0)^2 + (z-z0)^2) = 0.
float vlCylinder::EvaluateFunction(float x[3])
{
  return 0;
}

// Description
// Evaluate cylinder function gradient.
void vlCylinder::EvaluateGradient(float x[3], float g[3])
{
}

void vlCylinder::PrintSelf(ostream& os, vlIndent indent)
{
  vlImplicitFunction::PrintSelf(os,indent);

  os << indent << "Radius: " << this->Radius << "\n";
}
<|endoftext|>