]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: move Windows files to a separate folder
authorLucian Petrut <lpetrut@cloudbasesolutions.com>
Tue, 5 May 2020 10:20:46 +0000 (10:20 +0000)
committerLucian Petrut <lpetrut@cloudbasesolutions.com>
Wed, 18 Nov 2020 10:31:17 +0000 (10:31 +0000)
We ended up with quite a few files having the "_win32" suffix.
It's probably better if we move them to a separate folder and drop
the suffix.

Signed-off-by: Lucian Petrut <lpetrut@cloudbasesolutions.com>
21 files changed:
src/common/CMakeLists.txt
src/common/SubProcess_win32.cc [deleted file]
src/common/blkdev_win32.cc [deleted file]
src/common/dlfcn_win32.cc [deleted file]
src/common/dns_resolve_win32.cc [deleted file]
src/common/ifaddrs_win32.cc [deleted file]
src/common/registry_win32.cc [deleted file]
src/common/registry_win32.h [deleted file]
src/common/service_win32.cc [deleted file]
src/common/service_win32.h [deleted file]
src/common/win32/SubProcess.cc [new file with mode: 0644]
src/common/win32/blkdev.cc [new file with mode: 0644]
src/common/win32/dlfcn.cc [new file with mode: 0644]
src/common/win32/dns_resolve.cc [new file with mode: 0644]
src/common/win32/errno.cc [new file with mode: 0644]
src/common/win32/ifaddrs.cc [new file with mode: 0644]
src/common/win32/registry.cc [new file with mode: 0644]
src/common/win32/registry.h [new file with mode: 0644]
src/common/win32/service.cc [new file with mode: 0644]
src/common/win32/service.h [new file with mode: 0644]
src/common/win32_errno.cc [deleted file]

index efd1b24440dd66a7dea57464b704de56f03aa66f..e9a732ba9161f8639f5f04dee4be02412a84f261 100644 (file)
@@ -8,7 +8,7 @@ add_library(common_prioritycache_obj OBJECT
   PriorityCache.cc)
 
 if(WIN32)
-  add_library(dlfcn_win32 STATIC dlfcn_win32.cc win32_errno.cc)
+  add_library(dlfcn_win32 STATIC win32/dlfcn.cc win32/errno.cc)
 endif()
 
 set(common_srcs
@@ -105,12 +105,12 @@ set(common_srcs
 
 if(WIN32)
   list(APPEND common_srcs
-    blkdev_win32.cc
-    dns_resolve_win32.cc
-    SubProcess_win32.cc
-    ifaddrs_win32.c
-    registry_win32.cc
-    service_win32.cc)
+    win32/blkdev.cc
+    win32/dns_resolve.cc
+    win32/ifaddrs.cc
+    win32/registry.cc
+    win32/service.cc
+    win32/SubProcess.cc)
 else()
   list(APPEND common_srcs
     blkdev.cc
@@ -138,7 +138,7 @@ elseif(SUN)
 elseif(AIX)
   list(APPEND common_srcs aix_errno.cc)
 elseif(WIN32)
-  list(APPEND common_srcs win32_errno.cc)
+  list(APPEND common_srcs win32/errno.cc)
 endif()
 
 if(WITH_EVENTTRACE)
diff --git a/src/common/SubProcess_win32.cc b/src/common/SubProcess_win32.cc
deleted file mode 100644 (file)
index 0e4d13d..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-#include "SubProcess.h"
-
-#include <stdarg.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <iostream>
-#include <iomanip>
-
-#include "common/errno.h"
-#include "include/ceph_assert.h"
-#include "include/compat.h"
-
-SubProcess::SubProcess(const char *cmd_, std_fd_op stdin_op_, std_fd_op stdout_op_, std_fd_op stderr_op_) :
-  cmd(cmd_),
-  cmd_args(),
-  stdin_op(stdin_op_),
-  stdout_op(stdout_op_),
-  stderr_op(stderr_op_),
-  stdin_pipe_out_fd(-1),
-  stdout_pipe_in_fd(-1),
-  stderr_pipe_in_fd(-1),
-  pid(0),
-  errstr() {
-}
-
-SubProcess::~SubProcess() {
-  ceph_assert(!is_spawned());
-  ceph_assert(stdin_pipe_out_fd == -1);
-  ceph_assert(stdout_pipe_in_fd == -1);
-  ceph_assert(stderr_pipe_in_fd == -1);
-}
-
-void SubProcess::add_cmd_args(const char *arg, ...) {
-  ceph_assert(!is_spawned());
-
-  va_list ap;
-  va_start(ap, arg);
-  const char *p = arg;
-  do {
-    add_cmd_arg(p);
-    p = va_arg(ap, const char*);
-  } while (p != NULL);
-  va_end(ap);
-}
-
-void SubProcess::add_cmd_arg(const char *arg) {
-  ceph_assert(!is_spawned());
-
-  cmd_args.push_back(arg);
-}
-
-int SubProcess::get_stdin() const {
-  ceph_assert(is_spawned());
-  ceph_assert(stdin_op == PIPE);
-
-  return stdin_pipe_out_fd;
-}
-
-int SubProcess::get_stdout() const {
-  ceph_assert(is_spawned());
-  ceph_assert(stdout_op == PIPE);
-
-  return stdout_pipe_in_fd;
-}
-
-int SubProcess::get_stderr() const {
-  ceph_assert(is_spawned());
-  ceph_assert(stderr_op == PIPE);
-
-  return stderr_pipe_in_fd;
-}
-
-void SubProcess::close(int &fd) {
-  if (fd == -1)
-    return;
-
-  ::close(fd);
-  fd = -1;
-}
-
-void SubProcess::close_stdin() {
-  ceph_assert(is_spawned());
-  ceph_assert(stdin_op == PIPE);
-
-  close(stdin_pipe_out_fd);
-}
-
-void SubProcess::close_stdout() {
-  ceph_assert(is_spawned());
-  ceph_assert(stdout_op == PIPE);
-
-  close(stdout_pipe_in_fd);
-}
-
-void SubProcess::close_stderr() {
-  ceph_assert(is_spawned());
-  ceph_assert(stderr_op == PIPE);
-
-  close(stderr_pipe_in_fd);
-}
-
-const std::string SubProcess::err() const {
-  return errstr.str();
-}
-
-SubProcessTimed::SubProcessTimed(const char *cmd, std_fd_op stdin_op,
-                 std_fd_op stdout_op, std_fd_op stderr_op,
-                 int timeout_, int sigkill_) :
-  SubProcess(cmd, stdin_op, stdout_op, stderr_op),
-  timeout(timeout_),
-  sigkill(sigkill_) {
-}
-
-static bool timedout = false;
-void timeout_sighandler(int sig) {
-  timedout = true;
-}
-
-void SubProcess::close_h(HANDLE &handle) {
-  if (handle == INVALID_HANDLE_VALUE)
-    return;
-
-  CloseHandle(handle);
-  handle = INVALID_HANDLE_VALUE;
-}
-
-int SubProcess::join() {
-  ceph_assert(is_spawned());
-
-  close(stdin_pipe_out_fd);
-  close(stdout_pipe_in_fd);
-  close(stderr_pipe_in_fd);
-
-  DWORD status = 0;
-
-  if (WaitForSingleObject(proc_handle, INFINITE) != WAIT_FAILED) {
-    if (!GetExitCodeProcess(proc_handle, &status)) {
-      errstr << cmd << ": Could not get exit code: " << pid
-             << ". Error code: " << GetLastError();
-    } else if (status) {
-      errstr << cmd << ": exit status: " << status;
-    }
-  } else {
-    errstr << cmd << ": Waiting for child process failed: " << pid
-           << ". Error code: " << GetLastError();
-  }
-
-  close_h(proc_handle);
-  pid = 0;
-  return status;
-}
-
-void SubProcess::kill(int signo) const {
-  ceph_assert(is_spawned());
-  ceph_assert(TerminateProcess(proc_handle, 128 + SIGTERM));
-}
-
-int SubProcess::spawn() {
-  std::ostringstream cmdline;
-  cmdline << cmd;
-  for (auto& arg : cmd_args) {
-    cmdline << " " << std::quoted(arg);
-  }
-
-  STARTUPINFO si = {0};
-  PROCESS_INFORMATION pi = {0};
-  SECURITY_ATTRIBUTES sa = {0};
-
-  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-  sa.bInheritHandle = TRUE;
-  sa.lpSecurityDescriptor = NULL;
-
-  HANDLE stdin_r = INVALID_HANDLE_VALUE, stdin_w = INVALID_HANDLE_VALUE,
-         stdout_r = INVALID_HANDLE_VALUE, stdout_w = INVALID_HANDLE_VALUE,
-         stderr_r = INVALID_HANDLE_VALUE, stderr_w = INVALID_HANDLE_VALUE;
-
-  if ((stdin_op == PIPE && !CreatePipe(&stdin_r, &stdin_w, &sa, 0)) ||
-      (stdout_op == PIPE && !CreatePipe(&stdout_r, &stdout_w, &sa, 0)) ||
-      (stderr_op == PIPE && !CreatePipe(&stderr_r, &stderr_w, &sa, 0))) {
-    errstr << cmd << ": CreatePipe failed: " << GetLastError();
-    return -1;
-  }
-
-  // The following handles will be used by the parent process and
-  // must be marked as non-inheritable.
-  if ((stdin_op == PIPE && !SetHandleInformation(stdin_w, HANDLE_FLAG_INHERIT, 0)) ||
-      (stdout_op == PIPE && !SetHandleInformation(stdout_r, HANDLE_FLAG_INHERIT, 0)) ||
-      (stderr_op == PIPE && !SetHandleInformation(stderr_r, HANDLE_FLAG_INHERIT, 0))) {
-    errstr << cmd << ": SetHandleInformation failed: "
-           << GetLastError();
-    goto fail;
-  }
-
-  si.cb = sizeof(STARTUPINFO);
-  si.hStdInput = stdin_op == KEEP ? GetStdHandle(STD_INPUT_HANDLE) : stdin_r;
-  si.hStdOutput = stdout_op == KEEP ? GetStdHandle(STD_OUTPUT_HANDLE) : stdout_w;
-  si.hStdError = stderr_op == KEEP ? GetStdHandle(STD_ERROR_HANDLE) : stderr_w;
-  si.dwFlags |= STARTF_USESTDHANDLES;
-
-  stdin_pipe_out_fd = stdin_op == PIPE ? _open_osfhandle((intptr_t)stdin_w, 0) : -1;
-  stdout_pipe_in_fd = stdout_op == PIPE ? _open_osfhandle((intptr_t)stdout_r, _O_RDONLY) : - 1;
-  stderr_pipe_in_fd = stderr_op == PIPE ? _open_osfhandle((intptr_t)stderr_r, _O_RDONLY) : -1;
-
-  if (stdin_op == PIPE && stdin_pipe_out_fd == -1 ||
-      stdout_op == PIPE && stdout_pipe_in_fd == -1 ||
-      stderr_op == PIPE && stderr_pipe_in_fd == -1) {
-    errstr << cmd << ": _open_osfhandle failed: " << GetLastError();
-    goto fail;
-  }
-
-  // We've transfered ownership from those handles.
-  stdin_w = stdout_r = stderr_r = INVALID_HANDLE_VALUE;
-
-  if (!CreateProcess(
-      NULL, const_cast<char*>(cmdline.str().c_str()),
-      NULL, NULL, /* No special security attributes */
-      1, /* Inherit handles marked as inheritable */
-      0, /* No special flags */
-      NULL, /* Use the same environment variables */
-      NULL, /* use the same cwd */
-      &si, &pi)) {
-    errstr << cmd << ": CreateProcess failed: " << GetLastError();
-    goto fail;
-  }
-
-  proc_handle = pi.hProcess;
-  pid = GetProcessId(proc_handle);
-  if (!pid) {
-    errstr << cmd << ": Could not get child process id.";
-    goto fail;
-  }
-
-  // The following are used by the subprocess.
-  CloseHandle(stdin_r);
-  CloseHandle(stdout_w);
-  CloseHandle(stderr_w);
-  CloseHandle(pi.hThread);
-  return 0;
-
-fail:
-  // fd copies
-  close(stdin_pipe_out_fd);
-  close(stdout_pipe_in_fd);
-  close(stderr_pipe_in_fd);
-
-  // the original handles
-  close_h(stdin_r);
-  close_h(stdin_w);
-  close_h(stdout_r);
-  close_h(stdout_w);
-  close_h(stderr_r);
-  close_h(stderr_w);
-
-  // We may consider mapping some of the Windows errors.
-  return -1;
-}
-
-void SubProcess::exec() {
-}
-
-int SubProcessTimed::spawn() {
-  if (auto ret = SubProcess::spawn(); ret < 0) {
-    return ret;
-  }
-
-  if (timeout > 0) {
-    waiter = std::thread([&](){
-      DWORD wait_status = WaitForSingleObject(proc_handle, timeout * 1000);
-      ceph_assert(wait_status != WAIT_FAILED);
-      if (wait_status == WAIT_TIMEOUT) {
-        // 128 + sigkill is just the return code, which is expected by
-        // the unit tests and possibly by other code. We can't pick a
-        // termination signal unless we use window events.
-        ceph_assert(TerminateProcess(proc_handle, 128 + sigkill));
-        timedout = 1;
-      }
-    });
-  }
-  return 0;
-}
-
-int SubProcessTimed::join() {
-  ceph_assert(is_spawned());
-
-  if (waiter.joinable()) {
-    waiter.join();
-  }
-
-  return SubProcess::join();;
-}
-
-void SubProcessTimed::exec() {
-}
diff --git a/src/common/blkdev_win32.cc b/src/common/blkdev_win32.cc
deleted file mode 100644 (file)
index c3e28e3..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2020 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include <errno.h>
-#include "blkdev.h"
-
-int get_device_by_path(const char *path, char* partition, char* device,
-               size_t max)
-{
-  return -EOPNOTSUPP;
-}
-
-
-BlkDev::BlkDev(int f)
-  : fd(f)
-{}
-
-BlkDev::BlkDev(const std::string& devname)
-  : devname(devname)
-{}
-
-int BlkDev::get_devid(dev_t *id) const
-{
-  return -EOPNOTSUPP;
-}
-
-const char *BlkDev::sysfsdir() const {
-  assert(false);  // Should never be called on Windows
-  return "";
-}
-
-int BlkDev::dev(char *dev, size_t max) const
-{
-  return -EOPNOTSUPP;
-}
-
-int BlkDev::get_size(int64_t *psize) const
-{
-  return -EOPNOTSUPP;
-}
-
-bool BlkDev::support_discard() const
-{
-  return false;
-}
-
-int BlkDev::discard(int64_t offset, int64_t len) const
-{
-  return -EOPNOTSUPP;
-}
-
-bool BlkDev::is_rotational() const
-{
-  return false;
-}
-
-int BlkDev::model(char *model, size_t max) const
-{
-  return -EOPNOTSUPP;
-}
-
-int BlkDev::serial(char *serial, size_t max) const
-{
-  return -EOPNOTSUPP;
-}
-
-int BlkDev::partition(char *partition, size_t max) const
-{
-  return -EOPNOTSUPP;
-}
-
-int BlkDev::wholedisk(char *wd, size_t max) const
-{
-  return -EOPNOTSUPP;
-}
-
-void get_dm_parents(const std::string& dev, std::set<std::string> *ls)
-{
-}
-
-void get_raw_devices(const std::string& in,
-             std::set<std::string> *ls)
-{
-}
-
-int get_vdo_stats_handle(const char *devname, std::string *vdo_name)
-{
-  return -1;
-}
-
-int64_t get_vdo_stat(int fd, const char *property)
-{
-  return 0;
-}
-
-bool get_vdo_utilization(int fd, uint64_t *total, uint64_t *avail)
-{
-  return false;
-}
-
-std::string get_device_id(const std::string& devname,
-              std::string *err)
-{
-  if (err) {
-    *err = "not implemented";
-  }
-  return std::string();
-}
-
-int block_device_run_smartctl(const char *device, int timeout,
-                  std::string *result)
-{
-  return -EOPNOTSUPP;
-}
-
-int block_device_get_metrics(const std::string& devname, int timeout,
-                             json_spirit::mValue *result)
-{
-  return -EOPNOTSUPP;
-}
-
-int block_device_run_nvme(const char *device, const char *vendor, int timeout,
-            std::string *result)
-{
-  return -EOPNOTSUPP;
-}
diff --git a/src/common/dlfcn_win32.cc b/src/common/dlfcn_win32.cc
deleted file mode 100644 (file)
index 329d146..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2020 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include <sstream>
-#include <windows.h>
-
-#include "common/errno.h"
-#include "include/dlfcn_compat.h"
-
-
-void* dlopen(const char *filename, int flags) {
-  return LoadLibrary(filename);
-}
-
-int dlclose(void* handle) {
-  //FreeLibrary returns 0 on error, as opposed to dlclose.
-  return !FreeLibrary(handle);
-}
-
-void* dlsym(void* handle, const char* symbol) {
-  return (void*)GetProcAddress(handle, symbol);
-}
-
-dl_errmsg_t dlerror() {
-  return win32_lasterror_str();
-}
-
diff --git a/src/common/dns_resolve_win32.cc b/src/common/dns_resolve_win32.cc
deleted file mode 100644 (file)
index b7a888b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2019 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include "include/scope_guard.h"
-#include "dns_resolve.h"
-#include "common/debug.h"
-
-#define dout_subsys ceph_subsys_
-
-
-namespace ceph {
-
-int ResolvHWrapper::res_query(const char *hostname, int cls,
-    int type, u_char *buf, int bufsz) {
-  return -1;
-}
-
-int ResolvHWrapper::res_search(const char *hostname, int cls,
-    int type, u_char *buf, int bufsz) {
-  return -1;
-}
-
-DNSResolver::~DNSResolver()
-{
-  delete resolv_h;
-}
-
-int DNSResolver::resolve_cname(CephContext *cct, const string& hostname,
-    string *cname, bool *found)
-{
-  return -ENOTSUP;
-}
-
-int DNSResolver::resolve_ip_addr(CephContext *cct, const string& hostname,
-    entity_addr_t *addr)
-{
-  return -ENOTSUP;
-}
-
-int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name,
-    const SRV_Protocol trans_protocol,
-    map<string, DNSResolver::Record> *srv_hosts)
-{
-  return this->resolve_srv_hosts(cct, service_name, trans_protocol, "", srv_hosts);
-}
-
-int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name,
-    const SRV_Protocol trans_protocol, const string& domain,
-    map<string, DNSResolver::Record> *srv_hosts)
-{
-  return -ENOTSUP;
-}
-
-}
diff --git a/src/common/ifaddrs_win32.cc b/src/common/ifaddrs_win32.cc
deleted file mode 100644 (file)
index d7de4a5..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <errno.h>
-#include <winsock2.h>
-#include <wincrypt.h>
-#include <iphlpapi.h>
-#include <ws2tcpip.h>
-#include <ifaddrs.h>
-#include <stdio.h>
-
-#include "include/compat.h"
-
-int getifaddrs(struct ifaddrs **ifap)
-{
-  int ret = 0;
-
-  DWORD size, res = 0;
-  res = GetAdaptersAddresses(
-    AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
-    NULL, NULL, &size);
-  if (res != ERROR_BUFFER_OVERFLOW) {
-    errno = ENOMEM;
-    return -1;
-  }
-
-  PIP_ADAPTER_ADDRESSES adapter_addrs = (PIP_ADAPTER_ADDRESSES)malloc(size);
-  res = GetAdaptersAddresses(
-    AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
-    NULL, adapter_addrs, &size);
-  if (res != ERROR_SUCCESS) {
-    errno = ENOMEM;
-    return -1;
-  }
-
-  struct ifaddrs *out_list_head = NULL;
-  struct ifaddrs *out_list_curr;
-
-  for (PIP_ADAPTER_ADDRESSES curr_addrs = adapter_addrs;
-       curr_addrs != NULL;
-       curr_addrs = curr_addrs->Next) {
-    if (curr_addrs->OperStatus != 1)
-      continue;
-
-    for (PIP_ADAPTER_UNICAST_ADDRESS unicast_addrs = curr_addrs->FirstUnicastAddress;
-         unicast_addrs != NULL;
-         unicast_addrs = unicast_addrs->Next) {
-      SOCKADDR* unicast_sockaddr = unicast_addrs->Address.lpSockaddr;
-      if (unicast_sockaddr->sa_family != AF_INET &&
-          unicast_sockaddr->sa_family != AF_INET6)
-        continue;
-      out_list_curr = calloc(sizeof(*out_list_curr), 1);
-      if (!out_list_curr) {
-        errno = ENOMEM;
-        ret = -1;
-        goto out;
-      }
-
-      out_list_curr->ifa_next = out_list_head;
-      out_list_head = out_list_curr;
-
-      out_list_curr->ifa_flags = IFF_UP;
-      if (curr_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
-        out_list_curr->ifa_flags |= IFF_LOOPBACK;
-
-      out_list_curr->ifa_addr = (struct sockaddr *) &out_list_curr->in_addrs;
-      out_list_curr->ifa_netmask = (struct sockaddr *) &out_list_curr->in_netmasks;
-      out_list_curr->ifa_name = out_list_curr->ad_name;
-
-      if (unicast_sockaddr->sa_family == AF_INET) {
-        ULONG subnet_mask = 0;
-        if (ConvertLengthToIpv4Mask(unicast_addrs->OnLinkPrefixLength, &subnet_mask)) {
-          errno = ENODATA;
-          ret = -1;
-          goto out;
-        }
-        struct sockaddr_in *addr4 = (struct sockaddr_in *) &out_list_curr->in_addrs;
-        struct sockaddr_in *netmask4 = (struct sockaddr_in *) &out_list_curr->in_netmasks;
-        netmask4->sin_family = unicast_sockaddr->sa_family;
-        addr4->sin_family = unicast_sockaddr->sa_family;
-        netmask4->sin_addr.S_un.S_addr = subnet_mask;
-        addr4->sin_addr = ((struct sockaddr_in*) unicast_sockaddr)->sin_addr;
-      } else {
-        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &out_list_curr->in_addrs;
-        (*addr6) = *(struct sockaddr_in6 *) unicast_sockaddr;
-      }
-      out_list_curr->speed = curr_addrs->TransmitLinkSpeed;
-      // TODO maybe use friendly name instead of adapter GUID
-      sprintf_s(out_list_curr->ad_name,
-                sizeof(out_list_curr->ad_name),
-                curr_addrs->AdapterName);
-    }
-  }
-  ret = 0;
-out:
-  free(adapter_addrs);
-  if (ret && out_list_head)
-    free(out_list_head);
-  else if (ifap)
-    *ifap = out_list_head;
-
-  return ret;
-}
-
-void freeifaddrs(struct ifaddrs *ifa)
-{
-  while (ifa) {
-    struct ifaddrs *next = ifa->ifa_next;
-    free(ifa);
-    ifa = next;
-  }
-}
diff --git a/src/common/registry_win32.cc b/src/common/registry_win32.cc
deleted file mode 100644 (file)
index eb809a4..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2020 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#define dout_context cct
-#define dout_subsys ceph_subsys_
-
-#include "common/debug.h"
-#include "common/errno.h"
-#include "common/registry_win32.h"
-
-RegistryKey::RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey,
-                         bool create_value): cct(cct_)
-{
-  DWORD status = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey);
-
-  if (status == ERROR_FILE_NOT_FOUND && create_value)
-  {
-    ldout(cct_, 10) << "Creating registry key: " << strKey << dendl;
-    status = RegCreateKeyEx(
-        hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE,
-        KEY_ALL_ACCESS, NULL, &hKey, NULL);
-  }
-
-  if (ERROR_SUCCESS != status) {
-    if (ERROR_FILE_NOT_FOUND == status) {
-      missingKey = true;
-    } else {
-      lderr(cct_) << "Error: " << win32_strerror(status)
-                  << ". Could not open registry key: "
-                  << strKey << dendl;
-    }
-  }
-}
-
-RegistryKey::~RegistryKey() {
-  if (!hKey)
-    return;
-
-  DWORD status = RegCloseKey(hKey);
-  if (ERROR_SUCCESS != status) {
-    derr << "Error: " << win32_strerror(status)
-         << ". Could not close registry key." << dendl;
-  } else {
-    hKey = NULL;
-  }
-}
-
-int RegistryKey::remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey)
-{
-  DWORD status = RegDeleteKeyEx(hRootKey, strKey, KEY_WOW64_64KEY, 0);
-
-  if (status == ERROR_FILE_NOT_FOUND)
-  {
-    ldout(cct_, 20) << "Registry key : " << strKey
-                    << " does not exist." << dendl;
-    return 0;
-  }
-
-  if (ERROR_SUCCESS != status) {
-    lderr(cct_) << "Error: " << win32_strerror(status)
-                << ". Could not delete registry key: "
-                << strKey << dendl;
-    return -EINVAL;
-  }
-
-  return 0;
-}
-
-int RegistryKey::flush() {
-  DWORD status = RegFlushKey(hKey);
-  if (ERROR_SUCCESS != status) {
-    derr << "Error: " << win32_strerror(status)
-         << ". Could not flush registry key." << dendl;
-    return -EINVAL;
-  }
-
-  return 0;
-}
-
-int RegistryKey::set(LPCTSTR lpValue, DWORD data)
-{
-  DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_DWORD,
-                               (LPBYTE)&data, sizeof(DWORD));
-  if (ERROR_SUCCESS != status) {
-    derr << "Error: " << win32_strerror(status)
-         << ". Could not set registry value: " << (char*)lpValue << dendl;
-    return -EINVAL;
-  }
-
-  return 0;
-}
-
-int RegistryKey::set(LPCTSTR lpValue, std::string data)
-{
-  DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_SZ,
-                               (LPBYTE)data.c_str(), data.length());
-  if (ERROR_SUCCESS != status) {
-    derr << "Error: " << win32_strerror(status)
-         << ". Could not set registry value: "
-         << (char*)lpValue << dendl;
-    return -EINVAL;
-  }
-  return 0;
-}
-
-int RegistryKey::get(LPCTSTR lpValue, DWORD* value)
-{
-  DWORD data;
-  DWORD size = sizeof(data);
-  DWORD type = REG_DWORD;
-  DWORD status = RegQueryValueEx(hKey, lpValue, NULL,
-                                 &type, (LPBYTE)&data, &size);
-  if (ERROR_SUCCESS != status) {
-    derr << "Error: " << win32_strerror(status)
-         << ". Could not get registry value: "
-         << (char*)lpValue << dendl;
-    return -EINVAL;
-  }
-  *value = data;
-
-  return 0;
-}
-
-int RegistryKey::get(LPCTSTR lpValue, std::string& value)
-{
-  std::string data{""};
-  DWORD size = 0;
-  DWORD type = REG_SZ;
-  DWORD status = RegQueryValueEx(hKey, lpValue, NULL, &type,
-                                 (LPBYTE)data.c_str(), &size);
-  if (ERROR_MORE_DATA == status) {
-    data.resize(size);
-    status = RegQueryValueEx(hKey, lpValue, NULL, &type,
-                             (LPBYTE)data.c_str(), &size);
-  }
-
-  if (ERROR_SUCCESS != status) {
-    derr << "Error: " << win32_strerror(status)
-         << ". Could not get registry value: "
-         << (char*)lpValue << dendl;
-    return -EINVAL;
-  }
-  value.assign(data.c_str());
-
-  return 0;
-}
diff --git a/src/common/registry_win32.h b/src/common/registry_win32.h
deleted file mode 100644 (file)
index 974d662..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2019 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include "include/compat.h"
-#include "common/ceph_context.h"
-
-
-class RegistryKey {
-public:
-  RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey, bool create_value);
-  ~RegistryKey();
-
-  static remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey);
-
-  int flush();
-
-  int set(LPCTSTR lpValue, DWORD data);
-  int set(LPCTSTR lpValue, std::string data);
-
-  int get(LPCTSTR lpValue, DWORD* value);
-  int get(LPCTSTR lpValue, std::string& value);
-
-  HKEY hKey = NULL;
-  bool missingKey = false;
-
-private:
-  CephContext *cct;
-};
diff --git a/src/common/service_win32.cc b/src/common/service_win32.cc
deleted file mode 100644 (file)
index 6297531..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2019 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#define dout_context cct
-#define dout_subsys ceph_subsys_
-
-#include "common/debug.h"
-#include "common/errno.h"
-#include "common/service_win32.h"
-
-// Initialize the singleton service instance.
-ServiceBase *ServiceBase::s_service = NULL;
-
-ServiceBase::ServiceBase(CephContext *cct_): cct(cct_)
-{
-  status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
-  status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
-  status.dwCurrentState = SERVICE_START_PENDING;
-  status.dwWin32ExitCode = NO_ERROR;
-  status.dwCheckPoint = 0;
-  /* The estimated time required for the stop operation in ms. */
-  status.dwWaitHint = 0;
-}
-
-/* Register service action callbacks */
-int ServiceBase::initialize(ServiceBase *service)
-{
-  s_service = service;
-
-  SERVICE_TABLE_ENTRY service_table[] = {
-    {"", (LPSERVICE_MAIN_FUNCTION)run},
-    {NULL, NULL}
-  };
-
-  /* StartServiceCtrlDispatcher blocks until the service is stopped. */
-  if (!StartServiceCtrlDispatcher(service_table)) {
-    int err = GetLastError();
-    lderr(service->cct) << "StartServiceCtrlDispatcher error: "
-                        << err << dendl;
-    return -EINVAL;
-  }
-  return 0;
-}
-
-void WINAPI ServiceBase::run()
-{
-  assert(s_service != NULL);
-
-  /* Register the control handler. This function is called by the service
-   * manager to stop the service. The service name that we're passing here
-   * doesn't have to be valid as we're using SERVICE_WIN32_OWN_PROCESS. */
-  s_service->hstatus = RegisterServiceCtrlHandler(
-    "", (LPHANDLER_FUNCTION)control_handler);
-  if (!s_service->hstatus) {
-    return;
-  }
-
-  s_service->set_status(SERVICE_START_PENDING);
-
-  // TODO: should we expect exceptions?
-  int err = s_service->run_hook();
-  if (err) {
-    lderr(s_service->cct) << "Failed to start service. Error code: "
-                          << err << dendl;
-    s_service->set_status(SERVICE_STOPPED);
-  } else {
-    s_service->set_status(SERVICE_RUNNING);
-  }
-}
-
-void ServiceBase::shutdown()
-{
-  DWORD original_state = status.dwCurrentState;
-  set_status(SERVICE_STOP_PENDING);
-
-  int err = shutdown_hook();
-  if (err) {
-    derr << "Shutdown service hook failed. Error code: " << err << dendl;
-    set_status(original_state);
-  } else {
-    set_status(SERVICE_STOPPED);
-  }
-}
-
-void ServiceBase::stop()
-{
-  DWORD original_state = status.dwCurrentState;
-  set_status(SERVICE_STOP_PENDING);
-
-  int err = stop_hook();
-  if (err) {
-    derr << "Service stop hook failed. Error code: " << err << dendl;
-    set_status(original_state);
-  } else {
-    set_status(SERVICE_STOPPED);
-  }
-}
-
-/* This function is registered with the Windows services manager through
- * a call to RegisterServiceCtrlHandler() and will be called by the Windows
- * service manager asynchronously to stop the service. */
-void ServiceBase::control_handler(DWORD request)
-{
-  switch (request) {
-  case SERVICE_CONTROL_STOP:
-    s_service->stop();
-    break;
-  case SERVICE_CONTROL_SHUTDOWN:
-    s_service->shutdown();
-    break;
-  default:
-    break;
-  }
-}
-
-void ServiceBase::set_status(DWORD current_state, DWORD exit_code) {
-  static DWORD dwCheckPoint = 1;
-  if (current_state == SERVICE_RUNNING || current_state == SERVICE_STOPPED) {
-    status.dwCheckPoint = dwCheckPoint++;
-  }
-
-  status.dwCurrentState = current_state;
-  status.dwWin32ExitCode = exit_code;
-
-  if (hstatus) {
-    ::SetServiceStatus(hstatus, &status);
-  }
-}
diff --git a/src/common/service_win32.h b/src/common/service_win32.h
deleted file mode 100644 (file)
index 5adcdea..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2019 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include "include/compat.h"
-#include "common/ceph_context.h"
-
-class ServiceBase {
-
-public:
-  ServiceBase(CephContext *cct_);
-  virtual ~ServiceBase() {};
-
-  static int initialize(ServiceBase *service);
-protected:
-  static void run();
-  static void control_handler(DWORD request);
-
-  void shutdown();
-  void stop();
-
-  void set_status(DWORD current_state, DWORD exit_code = NO_ERROR);
-
-  /* Subclasses should implement the following service hooks. */
-  virtual int run_hook() = 0;
-  /* Invoked when the service is requested to stop. */
-  virtual int stop_hook() = 0;
-  /* Invoked when the system is shutting down. */
-  virtual int shutdown_hook() = 0;
-
-  CephContext *cct;
-
-private:
-  /* A handle used when reporting the current status. */
-  SERVICE_STATUS_HANDLE hstatus;
-  /* The current service status. */
-  SERVICE_STATUS status;
-
-  /* singleton service instance */
-  static ServiceBase *s_service;
-};
diff --git a/src/common/win32/SubProcess.cc b/src/common/win32/SubProcess.cc
new file mode 100644 (file)
index 0000000..565cb47
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2020 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <iostream>
+#include <iomanip>
+
+#include "common/SubProcess.h"
+#include "common/errno.h"
+#include "include/ceph_assert.h"
+#include "include/compat.h"
+
+SubProcess::SubProcess(const char *cmd_, std_fd_op stdin_op_, std_fd_op stdout_op_, std_fd_op stderr_op_) :
+  cmd(cmd_),
+  cmd_args(),
+  stdin_op(stdin_op_),
+  stdout_op(stdout_op_),
+  stderr_op(stderr_op_),
+  stdin_pipe_out_fd(-1),
+  stdout_pipe_in_fd(-1),
+  stderr_pipe_in_fd(-1),
+  pid(0),
+  errstr() {
+}
+
+SubProcess::~SubProcess() {
+  ceph_assert(!is_spawned());
+  ceph_assert(stdin_pipe_out_fd == -1);
+  ceph_assert(stdout_pipe_in_fd == -1);
+  ceph_assert(stderr_pipe_in_fd == -1);
+}
+
+void SubProcess::add_cmd_args(const char *arg, ...) {
+  ceph_assert(!is_spawned());
+
+  va_list ap;
+  va_start(ap, arg);
+  const char *p = arg;
+  do {
+    add_cmd_arg(p);
+    p = va_arg(ap, const char*);
+  } while (p != NULL);
+  va_end(ap);
+}
+
+void SubProcess::add_cmd_arg(const char *arg) {
+  ceph_assert(!is_spawned());
+
+  cmd_args.push_back(arg);
+}
+
+int SubProcess::get_stdin() const {
+  ceph_assert(is_spawned());
+  ceph_assert(stdin_op == PIPE);
+
+  return stdin_pipe_out_fd;
+}
+
+int SubProcess::get_stdout() const {
+  ceph_assert(is_spawned());
+  ceph_assert(stdout_op == PIPE);
+
+  return stdout_pipe_in_fd;
+}
+
+int SubProcess::get_stderr() const {
+  ceph_assert(is_spawned());
+  ceph_assert(stderr_op == PIPE);
+
+  return stderr_pipe_in_fd;
+}
+
+void SubProcess::close(int &fd) {
+  if (fd == -1)
+    return;
+
+  ::close(fd);
+  fd = -1;
+}
+
+void SubProcess::close_stdin() {
+  ceph_assert(is_spawned());
+  ceph_assert(stdin_op == PIPE);
+
+  close(stdin_pipe_out_fd);
+}
+
+void SubProcess::close_stdout() {
+  ceph_assert(is_spawned());
+  ceph_assert(stdout_op == PIPE);
+
+  close(stdout_pipe_in_fd);
+}
+
+void SubProcess::close_stderr() {
+  ceph_assert(is_spawned());
+  ceph_assert(stderr_op == PIPE);
+
+  close(stderr_pipe_in_fd);
+}
+
+const std::string SubProcess::err() const {
+  return errstr.str();
+}
+
+SubProcessTimed::SubProcessTimed(const char *cmd, std_fd_op stdin_op,
+                 std_fd_op stdout_op, std_fd_op stderr_op,
+                 int timeout_, int sigkill_) :
+  SubProcess(cmd, stdin_op, stdout_op, stderr_op),
+  timeout(timeout_),
+  sigkill(sigkill_) {
+}
+
+static bool timedout = false;
+void timeout_sighandler(int sig) {
+  timedout = true;
+}
+
+void SubProcess::close_h(HANDLE &handle) {
+  if (handle == INVALID_HANDLE_VALUE)
+    return;
+
+  CloseHandle(handle);
+  handle = INVALID_HANDLE_VALUE;
+}
+
+int SubProcess::join() {
+  ceph_assert(is_spawned());
+
+  close(stdin_pipe_out_fd);
+  close(stdout_pipe_in_fd);
+  close(stderr_pipe_in_fd);
+
+  DWORD status = 0;
+
+  if (WaitForSingleObject(proc_handle, INFINITE) != WAIT_FAILED) {
+    if (!GetExitCodeProcess(proc_handle, &status)) {
+      errstr << cmd << ": Could not get exit code: " << pid
+             << ". Error code: " << GetLastError();
+    } else if (status) {
+      errstr << cmd << ": exit status: " << status;
+    }
+  } else {
+    errstr << cmd << ": Waiting for child process failed: " << pid
+           << ". Error code: " << GetLastError();
+  }
+
+  close_h(proc_handle);
+  pid = 0;
+  return status;
+}
+
+void SubProcess::kill(int signo) const {
+  ceph_assert(is_spawned());
+  ceph_assert(TerminateProcess(proc_handle, 128 + SIGTERM));
+}
+
+int SubProcess::spawn() {
+  std::ostringstream cmdline;
+  cmdline << cmd;
+  for (auto& arg : cmd_args) {
+    cmdline << " " << std::quoted(arg);
+  }
+
+  STARTUPINFO si = {0};
+  PROCESS_INFORMATION pi = {0};
+  SECURITY_ATTRIBUTES sa = {0};
+
+  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+  sa.bInheritHandle = TRUE;
+  sa.lpSecurityDescriptor = NULL;
+
+  HANDLE stdin_r = INVALID_HANDLE_VALUE, stdin_w = INVALID_HANDLE_VALUE,
+         stdout_r = INVALID_HANDLE_VALUE, stdout_w = INVALID_HANDLE_VALUE,
+         stderr_r = INVALID_HANDLE_VALUE, stderr_w = INVALID_HANDLE_VALUE;
+
+  if ((stdin_op == PIPE && !CreatePipe(&stdin_r, &stdin_w, &sa, 0)) ||
+      (stdout_op == PIPE && !CreatePipe(&stdout_r, &stdout_w, &sa, 0)) ||
+      (stderr_op == PIPE && !CreatePipe(&stderr_r, &stderr_w, &sa, 0))) {
+    errstr << cmd << ": CreatePipe failed: " << GetLastError();
+    return -1;
+  }
+
+  // The following handles will be used by the parent process and
+  // must be marked as non-inheritable.
+  if ((stdin_op == PIPE && !SetHandleInformation(stdin_w, HANDLE_FLAG_INHERIT, 0)) ||
+      (stdout_op == PIPE && !SetHandleInformation(stdout_r, HANDLE_FLAG_INHERIT, 0)) ||
+      (stderr_op == PIPE && !SetHandleInformation(stderr_r, HANDLE_FLAG_INHERIT, 0))) {
+    errstr << cmd << ": SetHandleInformation failed: "
+           << GetLastError();
+    goto fail;
+  }
+
+  si.cb = sizeof(STARTUPINFO);
+  si.hStdInput = stdin_op == KEEP ? GetStdHandle(STD_INPUT_HANDLE) : stdin_r;
+  si.hStdOutput = stdout_op == KEEP ? GetStdHandle(STD_OUTPUT_HANDLE) : stdout_w;
+  si.hStdError = stderr_op == KEEP ? GetStdHandle(STD_ERROR_HANDLE) : stderr_w;
+  si.dwFlags |= STARTF_USESTDHANDLES;
+
+  stdin_pipe_out_fd = stdin_op == PIPE ? _open_osfhandle((intptr_t)stdin_w, 0) : -1;
+  stdout_pipe_in_fd = stdout_op == PIPE ? _open_osfhandle((intptr_t)stdout_r, _O_RDONLY) : - 1;
+  stderr_pipe_in_fd = stderr_op == PIPE ? _open_osfhandle((intptr_t)stderr_r, _O_RDONLY) : -1;
+
+  if (stdin_op == PIPE && stdin_pipe_out_fd == -1 ||
+      stdout_op == PIPE && stdout_pipe_in_fd == -1 ||
+      stderr_op == PIPE && stderr_pipe_in_fd == -1) {
+    errstr << cmd << ": _open_osfhandle failed: " << GetLastError();
+    goto fail;
+  }
+
+  // We've transfered ownership from those handles.
+  stdin_w = stdout_r = stderr_r = INVALID_HANDLE_VALUE;
+
+  if (!CreateProcess(
+      NULL, const_cast<char*>(cmdline.str().c_str()),
+      NULL, NULL, /* No special security attributes */
+      1, /* Inherit handles marked as inheritable */
+      0, /* No special flags */
+      NULL, /* Use the same environment variables */
+      NULL, /* use the same cwd */
+      &si, &pi)) {
+    errstr << cmd << ": CreateProcess failed: " << GetLastError();
+    goto fail;
+  }
+
+  proc_handle = pi.hProcess;
+  pid = GetProcessId(proc_handle);
+  if (!pid) {
+    errstr << cmd << ": Could not get child process id.";
+    goto fail;
+  }
+
+  // The following are used by the subprocess.
+  CloseHandle(stdin_r);
+  CloseHandle(stdout_w);
+  CloseHandle(stderr_w);
+  CloseHandle(pi.hThread);
+  return 0;
+
+fail:
+  // fd copies
+  close(stdin_pipe_out_fd);
+  close(stdout_pipe_in_fd);
+  close(stderr_pipe_in_fd);
+
+  // the original handles
+  close_h(stdin_r);
+  close_h(stdin_w);
+  close_h(stdout_r);
+  close_h(stdout_w);
+  close_h(stderr_r);
+  close_h(stderr_w);
+
+  // We may consider mapping some of the Windows errors.
+  return -1;
+}
+
+void SubProcess::exec() {
+}
+
+int SubProcessTimed::spawn() {
+  if (auto ret = SubProcess::spawn(); ret < 0) {
+    return ret;
+  }
+
+  if (timeout > 0) {
+    waiter = std::thread([&](){
+      DWORD wait_status = WaitForSingleObject(proc_handle, timeout * 1000);
+      ceph_assert(wait_status != WAIT_FAILED);
+      if (wait_status == WAIT_TIMEOUT) {
+        // 128 + sigkill is just the return code, which is expected by
+        // the unit tests and possibly by other code. We can't pick a
+        // termination signal unless we use window events.
+        ceph_assert(TerminateProcess(proc_handle, 128 + sigkill));
+        timedout = 1;
+      }
+    });
+  }
+  return 0;
+}
+
+int SubProcessTimed::join() {
+  ceph_assert(is_spawned());
+
+  if (waiter.joinable()) {
+    waiter.join();
+  }
+
+  return SubProcess::join();;
+}
+
+void SubProcessTimed::exec() {
+}
diff --git a/src/common/win32/blkdev.cc b/src/common/win32/blkdev.cc
new file mode 100644 (file)
index 0000000..bb815a0
--- /dev/null
@@ -0,0 +1,137 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2020 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include <errno.h>
+#include "common/blkdev.h"
+
+int get_device_by_path(const char *path, char* partition, char* device,
+               size_t max)
+{
+  return -EOPNOTSUPP;
+}
+
+
+BlkDev::BlkDev(int f)
+  : fd(f)
+{}
+
+BlkDev::BlkDev(const std::string& devname)
+  : devname(devname)
+{}
+
+int BlkDev::get_devid(dev_t *id) const
+{
+  return -EOPNOTSUPP;
+}
+
+const char *BlkDev::sysfsdir() const {
+  assert(false);  // Should never be called on Windows
+  return "";
+}
+
+int BlkDev::dev(char *dev, size_t max) const
+{
+  return -EOPNOTSUPP;
+}
+
+int BlkDev::get_size(int64_t *psize) const
+{
+  return -EOPNOTSUPP;
+}
+
+bool BlkDev::support_discard() const
+{
+  return false;
+}
+
+int BlkDev::discard(int64_t offset, int64_t len) const
+{
+  return -EOPNOTSUPP;
+}
+
+bool BlkDev::is_rotational() const
+{
+  return false;
+}
+
+int BlkDev::model(char *model, size_t max) const
+{
+  return -EOPNOTSUPP;
+}
+
+int BlkDev::serial(char *serial, size_t max) const
+{
+  return -EOPNOTSUPP;
+}
+
+int BlkDev::partition(char *partition, size_t max) const
+{
+  return -EOPNOTSUPP;
+}
+
+int BlkDev::wholedisk(char *wd, size_t max) const
+{
+  return -EOPNOTSUPP;
+}
+
+void get_dm_parents(const std::string& dev, std::set<std::string> *ls)
+{
+}
+
+void get_raw_devices(const std::string& in,
+             std::set<std::string> *ls)
+{
+}
+
+int get_vdo_stats_handle(const char *devname, std::string *vdo_name)
+{
+  return -1;
+}
+
+int64_t get_vdo_stat(int fd, const char *property)
+{
+  return 0;
+}
+
+bool get_vdo_utilization(int fd, uint64_t *total, uint64_t *avail)
+{
+  return false;
+}
+
+std::string get_device_id(const std::string& devname,
+              std::string *err)
+{
+  if (err) {
+    *err = "not implemented";
+  }
+  return std::string();
+}
+
+int block_device_run_smartctl(const char *device, int timeout,
+                  std::string *result)
+{
+  return -EOPNOTSUPP;
+}
+
+int block_device_get_metrics(const std::string& devname, int timeout,
+                             json_spirit::mValue *result)
+{
+  return -EOPNOTSUPP;
+}
+
+int block_device_run_nvme(const char *device, const char *vendor, int timeout,
+            std::string *result)
+{
+  return -EOPNOTSUPP;
+}
diff --git a/src/common/win32/dlfcn.cc b/src/common/win32/dlfcn.cc
new file mode 100644 (file)
index 0000000..329d146
--- /dev/null
@@ -0,0 +1,38 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2020 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include <sstream>
+#include <windows.h>
+
+#include "common/errno.h"
+#include "include/dlfcn_compat.h"
+
+
+void* dlopen(const char *filename, int flags) {
+  return LoadLibrary(filename);
+}
+
+int dlclose(void* handle) {
+  //FreeLibrary returns 0 on error, as opposed to dlclose.
+  return !FreeLibrary(handle);
+}
+
+void* dlsym(void* handle, const char* symbol) {
+  return (void*)GetProcAddress(handle, symbol);
+}
+
+dl_errmsg_t dlerror() {
+  return win32_lasterror_str();
+}
+
diff --git a/src/common/win32/dns_resolve.cc b/src/common/win32/dns_resolve.cc
new file mode 100644 (file)
index 0000000..8a7c80b
--- /dev/null
@@ -0,0 +1,65 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2019 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "include/scope_guard.h"
+#include "common/dns_resolve.h"
+#include "common/debug.h"
+
+#define dout_subsys ceph_subsys_
+
+
+namespace ceph {
+
+int ResolvHWrapper::res_query(const char *hostname, int cls,
+    int type, u_char *buf, int bufsz) {
+  return -1;
+}
+
+int ResolvHWrapper::res_search(const char *hostname, int cls,
+    int type, u_char *buf, int bufsz) {
+  return -1;
+}
+
+DNSResolver::~DNSResolver()
+{
+  delete resolv_h;
+}
+
+int DNSResolver::resolve_cname(CephContext *cct, const string& hostname,
+    string *cname, bool *found)
+{
+  return -ENOTSUP;
+}
+
+int DNSResolver::resolve_ip_addr(CephContext *cct, const string& hostname,
+    entity_addr_t *addr)
+{
+  return -ENOTSUP;
+}
+
+int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name,
+    const SRV_Protocol trans_protocol,
+    map<string, DNSResolver::Record> *srv_hosts)
+{
+  return this->resolve_srv_hosts(cct, service_name, trans_protocol, "", srv_hosts);
+}
+
+int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name,
+    const SRV_Protocol trans_protocol, const string& domain,
+    map<string, DNSResolver::Record> *srv_hosts)
+{
+  return -ENOTSUP;
+}
+
+}
diff --git a/src/common/win32/errno.cc b/src/common/win32/errno.cc
new file mode 100644 (file)
index 0000000..2575377
--- /dev/null
@@ -0,0 +1,596 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2020 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "include/int_types.h"
+#include <ntdef.h>
+#include <ntstatus.h>
+
+#include "include/compat.h"
+#include "include/int_types.h"
+#include "include/types.h"
+
+// We're only converting errors defined in errno.h, not standard Windows
+// system error codes that are usually retrievied using GetLastErrorCode().
+// TODO: consider converting WinSock2 (WSA*) error codes, which are quite
+// similar to the errno.h ones.
+
+__u32 ceph_to_hostos_errno_unsigned(__u32 r)
+{
+  // using an array like like freebsd_errno.cc might be more readable but
+  // we have some large values defined by Boost.
+  switch(r) {
+    case 1: return EPERM;
+    case 2: return ENOENT;
+    case 3: return ESRCH;
+    case 4: return EINTR;
+    case 5: return EIO;
+    case 6: return ENXIO;
+    case 7: return E2BIG;
+    case 8: return ENOEXEC;
+    case 9: return EBADF;
+    case 10: return ECHILD;
+    // same as EWOULDBLOCK
+    case 11: return EAGAIN;
+    case 12: return ENOMEM;
+    case 13: return EACCES;
+    case 14: return EFAULT;
+    case 15: return ENOTBLK;
+    case 16: return EBUSY;
+    case 17: return EEXIST;
+    case 18: return EXDEV;
+    case 19: return ENODEV;
+    case 20: return ENOTDIR;
+    case 21: return EISDIR;
+    case 22: return EINVAL;
+    case 23: return ENFILE;
+    case 24: return EMFILE;
+    case 25: return ENOTTY;
+    case 26: return ETXTBSY;
+    case 27: return EFBIG;
+    case 28: return ENOSPC;
+    case 29: return ESPIPE;
+    case 30: return EROFS;
+    case 31: return EMLINK;
+    case 32: return EPIPE;
+    case 33: return EDOM;
+    case 34: return ERANGE;
+    // same as EDEADLK
+    case 35: return EDEADLOCK;
+    case 36: return ENAMETOOLONG;
+    case 37: return ENOLCK;
+    case 38: return ENOSYS;
+    case 39: return ENOTEMPTY;
+    case 40: return ELOOP;
+    case 42: return ENOMSG;
+    case 43: return EIDRM;
+    case 44: return ECHRNG;
+    case 45: return EL2NSYNC;
+    case 46: return EL3HLT;
+    case 47: return EL3RST;
+    case 48: return ELNRNG;
+    case 49: return EUNATCH;
+    case 50: return ENOCSI;
+    case 51: return EL2HLT;
+    case 52: return EBADE;
+    case 53: return EBADR;
+    case 54: return EXFULL;
+    case 55: return ENOANO;
+    case 56: return EBADRQC;
+    case 57: return EBADSLT;
+    case 59: return EBFONT;
+    case 60: return ENOSTR;
+    case 61: return ENODATA;
+    case 62: return ETIME;
+    case 63: return ENOSR;
+    case 64: return ENONET;
+    case 65: return ENOPKG;
+    case 66: return EREMOTE;
+    case 67: return ENOLINK;
+    case 68: return EADV;
+    case 69: return ESRMNT;
+    case 70: return ECOMM;
+    case 71: return EPROTO;
+    case 72: return EMULTIHOP;
+    case 73: return EDOTDOT;
+    case 74: return EBADMSG;
+    case 75: return EOVERFLOW;
+    case 76: return ENOTUNIQ;
+    case 77: return EBADFD;
+    case 78: return EREMCHG;
+    case 79: return ELIBACC;
+    case 80: return ELIBBAD;
+    case 81: return ELIBSCN;
+    case 82: return ELIBMAX;
+    case 83: return ELIBEXEC;
+    case 84: return EILSEQ;
+    case 85: return ERESTART;
+    case 86: return ESTRPIPE;
+    case 87: return EUSERS;
+    case 88: return ENOTSOCK;
+    case 89: return EDESTADDRREQ;
+    case 90: return EMSGSIZE;
+    case 91: return EPROTOTYPE;
+    case 92: return ENOPROTOOPT;
+    case 93: return EPROTONOSUPPORT;
+    case 94: return ESOCKTNOSUPPORT;
+    // same as ENOTSUP
+    case 95: return EOPNOTSUPP;
+    case 96: return EPFNOSUPPORT;
+    case 97: return EAFNOSUPPORT;
+    case 98: return EADDRINUSE;
+    case 99: return EADDRNOTAVAIL;
+    case 100: return ENETDOWN;
+    case 101: return ENETUNREACH;
+    case 102: return ENETRESET;
+    case 103: return ECONNABORTED;
+    case 104: return ECONNRESET;
+    case 105: return ENOBUFS;
+    case 106: return EISCONN;
+    case 107: return ENOTCONN;
+    case 108: return ESHUTDOWN;
+    case 109: return ETOOMANYREFS;
+    case 110: return ETIMEDOUT;
+    case 111: return ECONNREFUSED;
+    case 112: return EHOSTDOWN;
+    case 113: return EHOSTUNREACH;
+    case 114: return EALREADY;
+    case 115: return EINPROGRESS;
+    case 116: return ESTALE;
+    case 117: return EUCLEAN;
+    case 118: return ENOTNAM;
+    case 119: return ENAVAIL;
+    case 120: return EISNAM;
+    case 121: return EREMOTEIO;
+    case 122: return EDQUOT;
+    case 123: return ENOMEDIUM;
+    case 124: return EMEDIUMTYPE;
+    case 125: return ECANCELED;
+    case 126: return ENOKEY;
+    case 127: return EKEYEXPIRED;
+    case 128: return EKEYREVOKED;
+    case 129: return EKEYREJECTED;
+    case 130: return EOWNERDEAD;
+    case 131: return ENOTRECOVERABLE;
+    case 132: return ERFKILL;
+    case 133: return EHWPOISON;
+    default:
+      return r;
+  }
+}
+
+__u32 hostos_to_ceph_errno_unsigned(__u32 r) {
+  // Windows errno -> Linux errno
+  switch(r) {
+    case EPERM: return 1;
+    case ENOENT: return 2;
+    case ESRCH: return 3;
+    case EINTR: return 4;
+    case EIO: return 5;
+    case ENXIO: return 6;
+    case E2BIG: return 7;
+    case ENOEXEC: return 8;
+    case EBADF: return 9;
+    case ECHILD: return 10;
+    case EAGAIN: return 11;
+    case EWOULDBLOCK: return 11;
+    case ENOMEM: return 12;
+    case EACCES: return 13;
+    case EFAULT: return 14;
+    case ENOTBLK: return 15;
+    case EBUSY: return 16;
+    case EEXIST: return 17;
+    case EXDEV: return 18;
+    case ENODEV: return 19;
+    case ENOTDIR: return 20;
+    case EISDIR: return 21;
+    case EINVAL: return 22;
+    case ENFILE: return 23;
+    case EMFILE: return 24;
+    case ENOTTY: return 25;
+    case ETXTBSY: return 26;
+    case EFBIG: return 27;
+    case ENOSPC: return 28;
+    case ESPIPE: return 29;
+    case EROFS: return 30;
+    case EMLINK: return 31;
+    case EPIPE: return 32;
+    case EDOM: return 33;
+    case ERANGE: return 34;
+    // same as EDEADLOCK
+    // case EDEADLK: return 35;
+    case EDEADLOCK: return 35;
+    case ENAMETOOLONG: return 36;
+    case ENOLCK: return 37;
+    case ENOSYS: return 38;
+    case ENOTEMPTY: return 39;
+    case ELOOP: return 40;
+    case ENOMSG: return 42;
+    case EIDRM: return 43;
+    case ECHRNG: return 44;
+    case EL2NSYNC: return 45;
+    case EL3HLT: return 46;
+    case EL3RST: return 47;
+    case ELNRNG: return 48;
+    case EUNATCH: return 49;
+    case ENOCSI: return 50;
+    case EL2HLT: return 51;
+    case EBADE: return 52;
+    case EBADR: return 53;
+    case EXFULL: return 54;
+    case ENOANO: return 55;
+    case EBADRQC: return 56;
+    case EBADSLT: return 57;
+    case EBFONT: return 59;
+    case ENOSTR: return 60;
+    case ENODATA: return 61;
+    case ETIME: return 62;
+    case ENOSR: return 63;
+    case ENONET: return 64;
+    case ENOPKG: return 65;
+    case EREMOTE: return 66;
+    case ENOLINK: return 67;
+    case EADV: return 68;
+    case ESRMNT: return 69;
+    case ECOMM: return 70;
+    case EPROTO: return 71;
+    case EMULTIHOP: return 72;
+    case EDOTDOT: return 73;
+    case EBADMSG: return 74;
+    case EOVERFLOW: return 75;
+    case ENOTUNIQ: return 76;
+    case EBADFD: return 77;
+    case EREMCHG: return 78;
+    case ELIBACC: return 79;
+    case ELIBBAD: return 80;
+    case ELIBSCN: return 81;
+    case ELIBMAX: return 82;
+    case ELIBEXEC: return 83;
+    case EILSEQ: return 84;
+    // compat.h defines ERESTART as EINTR
+    // case ERESTART: return 85;
+    case ESTRPIPE: return 86;
+    case EUSERS: return 87;
+    case ENOTSOCK: return 88;
+    case EDESTADDRREQ: return 89;
+    case EMSGSIZE: return 90;
+    case EPROTOTYPE: return 91;
+    case ENOPROTOOPT: return 92;
+    case EPROTONOSUPPORT: return 93;
+    case ESOCKTNOSUPPORT: return 94;
+    case EOPNOTSUPP: return 95;
+    case ENOTSUP: return 95;
+    case EPFNOSUPPORT: return 96;
+    case EAFNOSUPPORT: return 97;
+    case EADDRINUSE: return 98;
+    case EADDRNOTAVAIL: return 99;
+    case ENETDOWN: return 100;
+    case ENETUNREACH: return 101;
+    case ENETRESET: return 102;
+    case ECONNABORTED: return 103;
+    case ECONNRESET: return 104;
+    case ENOBUFS: return 105;
+    case EISCONN: return 106;
+    case ENOTCONN: return 107;
+    case ESHUTDOWN: return 108;
+    case ETOOMANYREFS: return 109;
+    case ETIMEDOUT: return 110;
+    case ECONNREFUSED: return 111;
+    case EHOSTDOWN: return 112;
+    case EHOSTUNREACH: return 113;
+    case EALREADY: return 114;
+    case EINPROGRESS: return 115;
+    case ESTALE: return 116;
+    case EUCLEAN: return 117;
+    case ENOTNAM: return 118;
+    case ENAVAIL: return 119;
+    case EISNAM: return 120;
+    case EREMOTEIO: return 121;
+    case EDQUOT: return 122;
+    case ENOMEDIUM: return 123;
+    case EMEDIUMTYPE: return 124;
+    case ECANCELED: return 125;
+    case ENOKEY: return 126;
+    case EKEYEXPIRED: return 127;
+    case EKEYREVOKED: return 128;
+    case EKEYREJECTED: return 129;
+    case EOWNERDEAD: return 130;
+    case ENOTRECOVERABLE: return 131;
+    case ERFKILL: return 132;
+    case EHWPOISON: return 133;
+    default:
+      return r;
+ }
+}
+
+__s32 wsae_to_errno_unsigned(__s32 r)
+{
+  switch(r) {
+    case WSAEINTR: return EINTR;
+    case WSAEBADF: return EBADF;
+    case WSAEACCES: return EACCES;
+    case WSAEFAULT: return EFAULT;
+    case WSAEINVAL: return EINVAL;
+    case WSAEMFILE: return EMFILE;
+    // Linux defines WSAEWOULDBLOCK as EAGAIN, but not Windows headers.
+    // Since all ceph code uses EAGAIN instead of EWOULDBLOCK, we'll do
+    // the same here.
+    case WSAEWOULDBLOCK: return EAGAIN;
+    // Some functions (e.g. connect) can return WSAEWOULDBLOCK instead of
+    // EINPROGRESS.
+    case WSAEINPROGRESS: return EINPROGRESS;
+    case WSAEALREADY: return EALREADY;
+    case WSAENOTSOCK: return ENOTSOCK;
+    case WSAEDESTADDRREQ: return EDESTADDRREQ;
+    case WSAEMSGSIZE: return EMSGSIZE;
+    case WSAEPROTOTYPE: return EPROTOTYPE;
+    case WSAENOPROTOOPT: return ENOPROTOOPT;
+    case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
+    case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT;
+    case WSAEOPNOTSUPP: return EOPNOTSUPP;
+    case WSAEPFNOSUPPORT: return EPFNOSUPPORT;
+    case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
+    case WSAEADDRINUSE: return EADDRINUSE;
+    case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
+    case WSAENETDOWN: return ENETDOWN;
+    case WSAENETUNREACH: return ENETUNREACH;
+    case WSAENETRESET: return ENETRESET;
+    case WSAECONNABORTED: return ECONNABORTED;
+    case WSAECONNRESET: return ECONNRESET;
+    case WSAENOBUFS: return ENOBUFS;
+    case WSAEISCONN: return EISCONN;
+    case WSAENOTCONN: return ENOTCONN;
+    case WSAESHUTDOWN: return ESHUTDOWN;
+    case WSAETOOMANYREFS: return ETOOMANYREFS;
+    case WSAETIMEDOUT: return ETIMEDOUT;
+    case WSAECONNREFUSED: return ECONNREFUSED;
+    case WSAELOOP: return ELOOP;
+    case WSAENAMETOOLONG: return ENAMETOOLONG;
+    case WSAEHOSTDOWN: return EHOSTDOWN;
+    case WSAEHOSTUNREACH: return EHOSTUNREACH;
+    case WSAENOTEMPTY: return ENOTEMPTY;
+    // case WSAEPROCLIM
+    case WSAEUSERS: return EUSERS;
+    case WSAEDQUOT: return EDQUOT;
+    case WSAESTALE: return ESTALE;
+    case WSAEREMOTE: return EREMOTE;
+    // case WSASYSNOTREADY
+    // case WSAVERNOTSUPPORTED
+    // case WSANOTINITIALISED
+    case WSAEDISCON: return ESHUTDOWN;
+    // case WSAENOMORE
+    case WSAECANCELLED: return ECANCELED;
+    // We might return EINVAL, but it's probably better if we propagate the
+    // original error code here.
+    // case WSAEINVALIDPROCTABLE
+    // case WSAEINVALIDPROVIDER
+    // case WSAEPROVIDERFAILEDINIT
+    // case WSASYSCALLFAILURE
+    // case WSASERVICE_NOT_FOUND:
+    // case WSATYPE_NOT_FOUND:
+    // case WSA_E_NO_MORE:
+    case WSA_E_CANCELLED: return ECANCELED;
+    case WSAEREFUSED: return ECONNREFUSED;
+    case WSAHOST_NOT_FOUND: return EHOSTUNREACH;
+    case WSATRY_AGAIN: return EAGAIN;
+    // case WSANO_RECOVERY
+    // case WSANO_DATA:
+    default: return r;
+  }
+}
+
+// converts from linux errno values to host values
+__s32 ceph_to_hostos_errno(__s32 r)
+{
+  int sign = (r < 0 ? -1 : 1);
+  return ceph_to_hostos_errno_unsigned(abs(r)) * sign;
+}
+
+// converts Host OS errno values to linux/Ceph values
+__s32 hostos_to_ceph_errno(__s32 r)
+{
+  int sign = (r < 0 ? -1 : 1);
+  return hostos_to_ceph_errno_unsigned(abs(r)) * sign;
+}
+
+__s32 wsae_to_errno(__s32 r)
+{
+  int sign = (r < 0 ? -1 : 1);
+  return wsae_to_errno_unsigned(abs(r)) * sign;
+}
+
+__u32 errno_to_ntstatus(__u32 r) {
+  // errno -> NTSTATUS
+  // In some cases, there might be more than one applicable NTSTATUS
+  // value or there might be none. Certain values can be overridden
+  // when the caller (or whoever is supposed to handle the error) is
+  // expecting a different NTSTATUS value.
+  switch(r) {
+    case 0: return 0;
+    case EPERM: return STATUS_ACCESS_DENIED;
+    case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND;
+    case ESRCH: return STATUS_NOT_FOUND;
+    case EINTR: return STATUS_RETRY;
+    case EIO: return STATUS_DATA_ERROR;
+    case ENXIO: return STATUS_NOT_FOUND;
+    case E2BIG: return STATUS_FILE_TOO_LARGE;
+    case ENOEXEC: return STATUS_ACCESS_DENIED;
+    case EBADF: return STATUS_INVALID_HANDLE;
+    case ECHILD: return STATUS_INTERNAL_ERROR;
+    case EAGAIN: return STATUS_RETRY;
+    case EWOULDBLOCK: return STATUS_RETRY;
+    case ENOMEM: return STATUS_NO_MEMORY;
+    case EACCES: return STATUS_ACCESS_DENIED;
+    case EFAULT: return STATUS_INVALID_ADDRESS;
+    case ENOTBLK: return STATUS_BAD_DEVICE_TYPE;
+    case EBUSY: return STATUS_DEVICE_BUSY;
+    case EEXIST: return STATUS_OBJECT_NAME_COLLISION;
+    case EXDEV: return STATUS_NOT_SAME_DEVICE;
+    case ENODEV: return STATUS_SYSTEM_DEVICE_NOT_FOUND;
+    case ENOTDIR: return STATUS_NOT_A_DIRECTORY;
+    case EISDIR: return STATUS_FILE_IS_A_DIRECTORY;
+    case EINVAL: return STATUS_INVALID_PARAMETER;
+    case ENFILE: return STATUS_TOO_MANY_OPENED_FILES;
+    case EMFILE: return STATUS_TOO_MANY_OPENED_FILES;
+    case ENOTTY: return STATUS_INVALID_PARAMETER;
+    case ETXTBSY: return STATUS_DEVICE_BUSY;
+    case EFBIG: return STATUS_FILE_TOO_LARGE;
+    case ENOSPC: return STATUS_DISK_FULL;
+    case ESPIPE: return STATUS_INVALID_PARAMETER;
+    case EROFS: return STATUS_MEDIA_WRITE_PROTECTED;
+    case EMLINK: return STATUS_TOO_MANY_LINKS;
+    case EPIPE: return STATUS_PIPE_BROKEN;
+    case EDOM: return STATUS_INVALID_PARAMETER;
+    case ERANGE: return STATUS_INVALID_PARAMETER;
+    // same as EDEADLOCK
+    // case EDEADLK: return 35;
+    case EDEADLOCK: return STATUS_POSSIBLE_DEADLOCK;
+    case ENAMETOOLONG: return STATUS_NAME_TOO_LONG;
+    case ENOLCK: return STATUS_NOT_LOCKED;
+    case ENOSYS: return STATUS_NOT_IMPLEMENTED;
+    case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
+    case ELOOP: return STATUS_TOO_MANY_LINKS;
+    case ENOMSG: return STATUS_MESSAGE_NOT_FOUND;
+    case EIDRM: return STATUS_INVALID_PARAMETER;
+    case ECHRNG: return STATUS_INVALID_PARAMETER;
+    case EL2NSYNC: return STATUS_INTERNAL_ERROR;
+    case EL3HLT: return STATUS_INTERNAL_ERROR;
+    case EL3RST: return STATUS_INTERNAL_ERROR;
+    case ELNRNG: return STATUS_INTERNAL_ERROR;
+    case EUNATCH: return STATUS_INTERNAL_ERROR;
+    case ENOCSI: return STATUS_INTERNAL_ERROR;
+    case EL2HLT: return STATUS_INTERNAL_ERROR;
+    case EBADE: return STATUS_INTERNAL_ERROR;
+    case EBADR: return STATUS_INVALID_HANDLE;
+    case EXFULL: return STATUS_DISK_FULL;
+    case ENOANO: return STATUS_INTERNAL_ERROR;
+    case EBADRQC: return STATUS_INVALID_PARAMETER;
+    case EBADSLT: return STATUS_INVALID_PARAMETER;
+    case EBFONT: return STATUS_INVALID_PARAMETER;
+    case ENOSTR: return STATUS_INVALID_PARAMETER;
+    case ENODATA: return STATUS_NOT_FOUND;
+    case ETIME: return STATUS_TIMEOUT;
+    case ENOSR: return STATUS_INSUFFICIENT_RESOURCES;
+    case ENONET: return STATUS_NETWORK_UNREACHABLE;
+    case ENOPKG: return STATUS_NO_SUCH_PACKAGE;
+    case EREMOTE: return STATUS_INVALID_PARAMETER;
+    case ENOLINK: return STATUS_INTERNAL_ERROR;
+    case EADV: return STATUS_INTERNAL_ERROR;
+    case ESRMNT: return STATUS_INTERNAL_ERROR;
+    case ECOMM: return STATUS_INTERNAL_ERROR;
+    case EPROTO: return STATUS_PROTOCOL_NOT_SUPPORTED;
+    case EMULTIHOP: return STATUS_INTERNAL_ERROR;
+    case EDOTDOT: return STATUS_INTERNAL_ERROR;
+    case EBADMSG: return STATUS_INVALID_PARAMETER;
+    case EOVERFLOW: return STATUS_BUFFER_OVERFLOW;
+    case ENOTUNIQ: return STATUS_DUPLICATE_NAME;
+    case EBADFD: return STATUS_INVALID_HANDLE;
+    case EREMCHG: return STATUS_FILE_RENAMED;
+    case ELIBACC: return STATUS_DLL_NOT_FOUND;
+    case ELIBBAD: return STATUS_BAD_DLL_ENTRYPOINT;
+    case ELIBSCN: return STATUS_BAD_DLL_ENTRYPOINT;
+    case ELIBMAX: return STATUS_TOO_MANY_OPENED_FILES;
+    case ELIBEXEC: return STATUS_INVALID_PARAMETER;
+    case EILSEQ: return STATUS_INVALID_PARAMETER;
+    // compat.h defines ERESTART as EINTR
+    // case ERESTART: return 85;
+    case ESTRPIPE: return STATUS_RETRY;
+    case EUSERS: return STATUS_TOO_MANY_SIDS;
+    case ENOTSOCK: return STATUS_INVALID_HANDLE;
+    case EDESTADDRREQ: return STATUS_INVALID_PARAMETER;
+    case EMSGSIZE: return STATUS_BUFFER_OVERFLOW;
+    case EPROTOTYPE: return STATUS_INVALID_PARAMETER;
+    case ENOPROTOOPT: return STATUS_PROTOCOL_NOT_SUPPORTED;
+    case EPROTONOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED;
+    case ESOCKTNOSUPPORT: return STATUS_NOT_SUPPORTED;
+    case EOPNOTSUPP: return STATUS_NOT_SUPPORTED;
+    case ENOTSUP: return STATUS_NOT_SUPPORTED;
+    case EPFNOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED;
+    case EAFNOSUPPORT: return STATUS_NOT_SUPPORTED;
+    case EADDRINUSE: return STATUS_ADDRESS_ALREADY_EXISTS;
+    case EADDRNOTAVAIL: return STATUS_INVALID_ADDRESS;
+    case ENETDOWN: return STATUS_NETWORK_UNREACHABLE;
+    case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
+    case ENETRESET: return STATUS_CONNECTION_RESET;
+    case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
+    case ECONNRESET: return STATUS_CONNECTION_DISCONNECTED;
+    case ENOBUFS: return STATUS_BUFFER_TOO_SMALL;
+    case EISCONN: return STATUS_CONNECTION_ACTIVE;
+    case ENOTCONN: return 107;
+    case ESHUTDOWN: return 108;
+    case ETOOMANYREFS: return 109;
+    case ETIMEDOUT: return STATUS_TIMEOUT;
+    case ECONNREFUSED: return STATUS_CONNECTION_REFUSED;
+    case EHOSTDOWN: return STATUS_FILE_CLOSED;
+    case EHOSTUNREACH: return STATUS_HOST_UNREACHABLE;
+    case EALREADY: return STATUS_PENDING;
+    case EINPROGRESS: return STATUS_PENDING;
+    case ESTALE: return STATUS_INVALID_HANDLE;
+    case EUCLEAN: return STATUS_INVALID_PARAMETER;
+    case ENOTNAM: return STATUS_INVALID_PARAMETER;
+    case ENAVAIL: return STATUS_INVALID_PARAMETER;
+    case EISNAM: return STATUS_INVALID_PARAMETER;
+    case EREMOTEIO: return STATUS_DATA_ERROR;
+    case EDQUOT: return STATUS_QUOTA_EXCEEDED;
+    case ENOMEDIUM: return STATUS_NO_MEDIA;
+    case EMEDIUMTYPE: return STATUS_INVALID_PARAMETER;
+    case ECANCELED: return STATUS_REQUEST_CANCELED;
+    case ENOKEY: return STATUS_NO_USER_KEYS;
+    case EKEYEXPIRED: return STATUS_SMARTCARD_CERT_EXPIRED;
+    case EKEYREVOKED: return STATUS_IMAGE_CERT_REVOKED;
+    case EKEYREJECTED: return STATUS_ACCESS_DENIED;
+    case EOWNERDEAD: return STATUS_INTERNAL_ERROR;
+    case ENOTRECOVERABLE: return STATUS_INTERNAL_ERROR;
+    case ERFKILL: return STATUS_INTERNAL_ERROR;
+    case EHWPOISON: return STATUS_INTERNAL_ERROR;
+    default:
+      return STATUS_INTERNAL_ERROR;
+ }
+}
+
+std::string win32_strerror(int err)
+{
+  // As opposed to dlerror messages, this has to be freed.
+  LPSTR msg = NULL;
+  DWORD msg_len = ::FormatMessageA(
+    FORMAT_MESSAGE_ALLOCATE_BUFFER |
+    FORMAT_MESSAGE_FROM_SYSTEM |
+    FORMAT_MESSAGE_IGNORE_INSERTS,
+    NULL,
+    err,
+    0,
+    (LPSTR) &msg,
+    0,
+    NULL);
+
+  std::ostringstream msg_stream;
+  msg_stream << "(" << err << ") ";
+  if (!msg_len) {
+    msg_stream << "Unknown error";
+  }
+  else {
+    msg_stream << msg;
+    ::LocalFree(msg);
+  }
+  return msg_stream.str();
+}
+
+std::string win32_lasterror_str()
+{
+  DWORD err = ::GetLastError();
+  return win32_strerror(err);
+}
diff --git a/src/common/win32/ifaddrs.cc b/src/common/win32/ifaddrs.cc
new file mode 100644 (file)
index 0000000..d7de4a5
--- /dev/null
@@ -0,0 +1,109 @@
+#include <errno.h>
+#include <winsock2.h>
+#include <wincrypt.h>
+#include <iphlpapi.h>
+#include <ws2tcpip.h>
+#include <ifaddrs.h>
+#include <stdio.h>
+
+#include "include/compat.h"
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+  int ret = 0;
+
+  DWORD size, res = 0;
+  res = GetAdaptersAddresses(
+    AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
+    NULL, NULL, &size);
+  if (res != ERROR_BUFFER_OVERFLOW) {
+    errno = ENOMEM;
+    return -1;
+  }
+
+  PIP_ADAPTER_ADDRESSES adapter_addrs = (PIP_ADAPTER_ADDRESSES)malloc(size);
+  res = GetAdaptersAddresses(
+    AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
+    NULL, adapter_addrs, &size);
+  if (res != ERROR_SUCCESS) {
+    errno = ENOMEM;
+    return -1;
+  }
+
+  struct ifaddrs *out_list_head = NULL;
+  struct ifaddrs *out_list_curr;
+
+  for (PIP_ADAPTER_ADDRESSES curr_addrs = adapter_addrs;
+       curr_addrs != NULL;
+       curr_addrs = curr_addrs->Next) {
+    if (curr_addrs->OperStatus != 1)
+      continue;
+
+    for (PIP_ADAPTER_UNICAST_ADDRESS unicast_addrs = curr_addrs->FirstUnicastAddress;
+         unicast_addrs != NULL;
+         unicast_addrs = unicast_addrs->Next) {
+      SOCKADDR* unicast_sockaddr = unicast_addrs->Address.lpSockaddr;
+      if (unicast_sockaddr->sa_family != AF_INET &&
+          unicast_sockaddr->sa_family != AF_INET6)
+        continue;
+      out_list_curr = calloc(sizeof(*out_list_curr), 1);
+      if (!out_list_curr) {
+        errno = ENOMEM;
+        ret = -1;
+        goto out;
+      }
+
+      out_list_curr->ifa_next = out_list_head;
+      out_list_head = out_list_curr;
+
+      out_list_curr->ifa_flags = IFF_UP;
+      if (curr_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
+        out_list_curr->ifa_flags |= IFF_LOOPBACK;
+
+      out_list_curr->ifa_addr = (struct sockaddr *) &out_list_curr->in_addrs;
+      out_list_curr->ifa_netmask = (struct sockaddr *) &out_list_curr->in_netmasks;
+      out_list_curr->ifa_name = out_list_curr->ad_name;
+
+      if (unicast_sockaddr->sa_family == AF_INET) {
+        ULONG subnet_mask = 0;
+        if (ConvertLengthToIpv4Mask(unicast_addrs->OnLinkPrefixLength, &subnet_mask)) {
+          errno = ENODATA;
+          ret = -1;
+          goto out;
+        }
+        struct sockaddr_in *addr4 = (struct sockaddr_in *) &out_list_curr->in_addrs;
+        struct sockaddr_in *netmask4 = (struct sockaddr_in *) &out_list_curr->in_netmasks;
+        netmask4->sin_family = unicast_sockaddr->sa_family;
+        addr4->sin_family = unicast_sockaddr->sa_family;
+        netmask4->sin_addr.S_un.S_addr = subnet_mask;
+        addr4->sin_addr = ((struct sockaddr_in*) unicast_sockaddr)->sin_addr;
+      } else {
+        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &out_list_curr->in_addrs;
+        (*addr6) = *(struct sockaddr_in6 *) unicast_sockaddr;
+      }
+      out_list_curr->speed = curr_addrs->TransmitLinkSpeed;
+      // TODO maybe use friendly name instead of adapter GUID
+      sprintf_s(out_list_curr->ad_name,
+                sizeof(out_list_curr->ad_name),
+                curr_addrs->AdapterName);
+    }
+  }
+  ret = 0;
+out:
+  free(adapter_addrs);
+  if (ret && out_list_head)
+    free(out_list_head);
+  else if (ifap)
+    *ifap = out_list_head;
+
+  return ret;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+  while (ifa) {
+    struct ifaddrs *next = ifa->ifa_next;
+    free(ifa);
+    ifa = next;
+  }
+}
diff --git a/src/common/win32/registry.cc b/src/common/win32/registry.cc
new file mode 100644 (file)
index 0000000..d032e3b
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2020 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#define dout_context cct
+#define dout_subsys ceph_subsys_
+
+#include "common/debug.h"
+#include "common/errno.h"
+#include "common/win32/registry.h"
+
+RegistryKey::RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey,
+                         bool create_value): cct(cct_)
+{
+  DWORD status = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey);
+
+  if (status == ERROR_FILE_NOT_FOUND && create_value)
+  {
+    ldout(cct_, 10) << "Creating registry key: " << strKey << dendl;
+    status = RegCreateKeyEx(
+        hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE,
+        KEY_ALL_ACCESS, NULL, &hKey, NULL);
+  }
+
+  if (ERROR_SUCCESS != status) {
+    if (ERROR_FILE_NOT_FOUND == status) {
+      missingKey = true;
+    } else {
+      lderr(cct_) << "Error: " << win32_strerror(status)
+                  << ". Could not open registry key: "
+                  << strKey << dendl;
+    }
+  }
+}
+
+RegistryKey::~RegistryKey() {
+  if (!hKey)
+    return;
+
+  DWORD status = RegCloseKey(hKey);
+  if (ERROR_SUCCESS != status) {
+    derr << "Error: " << win32_strerror(status)
+         << ". Could not close registry key." << dendl;
+  } else {
+    hKey = NULL;
+  }
+}
+
+int RegistryKey::remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey)
+{
+  DWORD status = RegDeleteKeyEx(hRootKey, strKey, KEY_WOW64_64KEY, 0);
+
+  if (status == ERROR_FILE_NOT_FOUND)
+  {
+    ldout(cct_, 20) << "Registry key : " << strKey
+                    << " does not exist." << dendl;
+    return 0;
+  }
+
+  if (ERROR_SUCCESS != status) {
+    lderr(cct_) << "Error: " << win32_strerror(status)
+                << ". Could not delete registry key: "
+                << strKey << dendl;
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+int RegistryKey::flush() {
+  DWORD status = RegFlushKey(hKey);
+  if (ERROR_SUCCESS != status) {
+    derr << "Error: " << win32_strerror(status)
+         << ". Could not flush registry key." << dendl;
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+int RegistryKey::set(LPCTSTR lpValue, DWORD data)
+{
+  DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_DWORD,
+                               (LPBYTE)&data, sizeof(DWORD));
+  if (ERROR_SUCCESS != status) {
+    derr << "Error: " << win32_strerror(status)
+         << ". Could not set registry value: " << (char*)lpValue << dendl;
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+int RegistryKey::set(LPCTSTR lpValue, std::string data)
+{
+  DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_SZ,
+                               (LPBYTE)data.c_str(), data.length());
+  if (ERROR_SUCCESS != status) {
+    derr << "Error: " << win32_strerror(status)
+         << ". Could not set registry value: "
+         << (char*)lpValue << dendl;
+    return -EINVAL;
+  }
+  return 0;
+}
+
+int RegistryKey::get(LPCTSTR lpValue, DWORD* value)
+{
+  DWORD data;
+  DWORD size = sizeof(data);
+  DWORD type = REG_DWORD;
+  DWORD status = RegQueryValueEx(hKey, lpValue, NULL,
+                                 &type, (LPBYTE)&data, &size);
+  if (ERROR_SUCCESS != status) {
+    derr << "Error: " << win32_strerror(status)
+         << ". Could not get registry value: "
+         << (char*)lpValue << dendl;
+    return -EINVAL;
+  }
+  *value = data;
+
+  return 0;
+}
+
+int RegistryKey::get(LPCTSTR lpValue, std::string& value)
+{
+  std::string data{""};
+  DWORD size = 0;
+  DWORD type = REG_SZ;
+  DWORD status = RegQueryValueEx(hKey, lpValue, NULL, &type,
+                                 (LPBYTE)data.c_str(), &size);
+  if (ERROR_MORE_DATA == status) {
+    data.resize(size);
+    status = RegQueryValueEx(hKey, lpValue, NULL, &type,
+                             (LPBYTE)data.c_str(), &size);
+  }
+
+  if (ERROR_SUCCESS != status) {
+    derr << "Error: " << win32_strerror(status)
+         << ". Could not get registry value: "
+         << (char*)lpValue << dendl;
+    return -EINVAL;
+  }
+  value.assign(data.c_str());
+
+  return 0;
+}
diff --git a/src/common/win32/registry.h b/src/common/win32/registry.h
new file mode 100644 (file)
index 0000000..974d662
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2019 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "include/compat.h"
+#include "common/ceph_context.h"
+
+
+class RegistryKey {
+public:
+  RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey, bool create_value);
+  ~RegistryKey();
+
+  static remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey);
+
+  int flush();
+
+  int set(LPCTSTR lpValue, DWORD data);
+  int set(LPCTSTR lpValue, std::string data);
+
+  int get(LPCTSTR lpValue, DWORD* value);
+  int get(LPCTSTR lpValue, std::string& value);
+
+  HKEY hKey = NULL;
+  bool missingKey = false;
+
+private:
+  CephContext *cct;
+};
diff --git a/src/common/win32/service.cc b/src/common/win32/service.cc
new file mode 100644 (file)
index 0000000..df0e834
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2019 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#define dout_context cct
+#define dout_subsys ceph_subsys_
+
+#include "common/debug.h"
+#include "common/errno.h"
+#include "common/win32/service.h"
+
+// Initialize the singleton service instance.
+ServiceBase *ServiceBase::s_service = NULL;
+
+ServiceBase::ServiceBase(CephContext *cct_): cct(cct_)
+{
+  status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+  status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+  status.dwCurrentState = SERVICE_START_PENDING;
+  status.dwWin32ExitCode = NO_ERROR;
+  status.dwCheckPoint = 0;
+  /* The estimated time required for the stop operation in ms. */
+  status.dwWaitHint = 0;
+}
+
+/* Register service action callbacks */
+int ServiceBase::initialize(ServiceBase *service)
+{
+  s_service = service;
+
+  SERVICE_TABLE_ENTRY service_table[] = {
+    {"", (LPSERVICE_MAIN_FUNCTION)run},
+    {NULL, NULL}
+  };
+
+  /* StartServiceCtrlDispatcher blocks until the service is stopped. */
+  if (!StartServiceCtrlDispatcher(service_table)) {
+    int err = GetLastError();
+    lderr(service->cct) << "StartServiceCtrlDispatcher error: "
+                        << err << dendl;
+    return -EINVAL;
+  }
+  return 0;
+}
+
+void WINAPI ServiceBase::run()
+{
+  assert(s_service != NULL);
+
+  /* Register the control handler. This function is called by the service
+   * manager to stop the service. The service name that we're passing here
+   * doesn't have to be valid as we're using SERVICE_WIN32_OWN_PROCESS. */
+  s_service->hstatus = RegisterServiceCtrlHandler(
+    "", (LPHANDLER_FUNCTION)control_handler);
+  if (!s_service->hstatus) {
+    return;
+  }
+
+  s_service->set_status(SERVICE_START_PENDING);
+
+  // TODO: should we expect exceptions?
+  int err = s_service->run_hook();
+  if (err) {
+    lderr(s_service->cct) << "Failed to start service. Error code: "
+                          << err << dendl;
+    s_service->set_status(SERVICE_STOPPED);
+  } else {
+    s_service->set_status(SERVICE_RUNNING);
+  }
+}
+
+void ServiceBase::shutdown()
+{
+  DWORD original_state = status.dwCurrentState;
+  set_status(SERVICE_STOP_PENDING);
+
+  int err = shutdown_hook();
+  if (err) {
+    derr << "Shutdown service hook failed. Error code: " << err << dendl;
+    set_status(original_state);
+  } else {
+    set_status(SERVICE_STOPPED);
+  }
+}
+
+void ServiceBase::stop()
+{
+  DWORD original_state = status.dwCurrentState;
+  set_status(SERVICE_STOP_PENDING);
+
+  int err = stop_hook();
+  if (err) {
+    derr << "Service stop hook failed. Error code: " << err << dendl;
+    set_status(original_state);
+  } else {
+    set_status(SERVICE_STOPPED);
+  }
+}
+
+/* This function is registered with the Windows services manager through
+ * a call to RegisterServiceCtrlHandler() and will be called by the Windows
+ * service manager asynchronously to stop the service. */
+void ServiceBase::control_handler(DWORD request)
+{
+  switch (request) {
+  case SERVICE_CONTROL_STOP:
+    s_service->stop();
+    break;
+  case SERVICE_CONTROL_SHUTDOWN:
+    s_service->shutdown();
+    break;
+  default:
+    break;
+  }
+}
+
+void ServiceBase::set_status(DWORD current_state, DWORD exit_code) {
+  static DWORD dwCheckPoint = 1;
+  if (current_state == SERVICE_RUNNING || current_state == SERVICE_STOPPED) {
+    status.dwCheckPoint = dwCheckPoint++;
+  }
+
+  status.dwCurrentState = current_state;
+  status.dwWin32ExitCode = exit_code;
+
+  if (hstatus) {
+    ::SetServiceStatus(hstatus, &status);
+  }
+}
diff --git a/src/common/win32/service.h b/src/common/win32/service.h
new file mode 100644 (file)
index 0000000..5adcdea
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2019 SUSE LINUX GmbH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "include/compat.h"
+#include "common/ceph_context.h"
+
+class ServiceBase {
+
+public:
+  ServiceBase(CephContext *cct_);
+  virtual ~ServiceBase() {};
+
+  static int initialize(ServiceBase *service);
+protected:
+  static void run();
+  static void control_handler(DWORD request);
+
+  void shutdown();
+  void stop();
+
+  void set_status(DWORD current_state, DWORD exit_code = NO_ERROR);
+
+  /* Subclasses should implement the following service hooks. */
+  virtual int run_hook() = 0;
+  /* Invoked when the service is requested to stop. */
+  virtual int stop_hook() = 0;
+  /* Invoked when the system is shutting down. */
+  virtual int shutdown_hook() = 0;
+
+  CephContext *cct;
+
+private:
+  /* A handle used when reporting the current status. */
+  SERVICE_STATUS_HANDLE hstatus;
+  /* The current service status. */
+  SERVICE_STATUS status;
+
+  /* singleton service instance */
+  static ServiceBase *s_service;
+};
diff --git a/src/common/win32_errno.cc b/src/common/win32_errno.cc
deleted file mode 100644 (file)
index 2575377..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2020 SUSE LINUX GmbH
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-
-#include <errno.h>
-#include <stdlib.h>
-
-#include "include/int_types.h"
-#include <ntdef.h>
-#include <ntstatus.h>
-
-#include "include/compat.h"
-#include "include/int_types.h"
-#include "include/types.h"
-
-// We're only converting errors defined in errno.h, not standard Windows
-// system error codes that are usually retrievied using GetLastErrorCode().
-// TODO: consider converting WinSock2 (WSA*) error codes, which are quite
-// similar to the errno.h ones.
-
-__u32 ceph_to_hostos_errno_unsigned(__u32 r)
-{
-  // using an array like like freebsd_errno.cc might be more readable but
-  // we have some large values defined by Boost.
-  switch(r) {
-    case 1: return EPERM;
-    case 2: return ENOENT;
-    case 3: return ESRCH;
-    case 4: return EINTR;
-    case 5: return EIO;
-    case 6: return ENXIO;
-    case 7: return E2BIG;
-    case 8: return ENOEXEC;
-    case 9: return EBADF;
-    case 10: return ECHILD;
-    // same as EWOULDBLOCK
-    case 11: return EAGAIN;
-    case 12: return ENOMEM;
-    case 13: return EACCES;
-    case 14: return EFAULT;
-    case 15: return ENOTBLK;
-    case 16: return EBUSY;
-    case 17: return EEXIST;
-    case 18: return EXDEV;
-    case 19: return ENODEV;
-    case 20: return ENOTDIR;
-    case 21: return EISDIR;
-    case 22: return EINVAL;
-    case 23: return ENFILE;
-    case 24: return EMFILE;
-    case 25: return ENOTTY;
-    case 26: return ETXTBSY;
-    case 27: return EFBIG;
-    case 28: return ENOSPC;
-    case 29: return ESPIPE;
-    case 30: return EROFS;
-    case 31: return EMLINK;
-    case 32: return EPIPE;
-    case 33: return EDOM;
-    case 34: return ERANGE;
-    // same as EDEADLK
-    case 35: return EDEADLOCK;
-    case 36: return ENAMETOOLONG;
-    case 37: return ENOLCK;
-    case 38: return ENOSYS;
-    case 39: return ENOTEMPTY;
-    case 40: return ELOOP;
-    case 42: return ENOMSG;
-    case 43: return EIDRM;
-    case 44: return ECHRNG;
-    case 45: return EL2NSYNC;
-    case 46: return EL3HLT;
-    case 47: return EL3RST;
-    case 48: return ELNRNG;
-    case 49: return EUNATCH;
-    case 50: return ENOCSI;
-    case 51: return EL2HLT;
-    case 52: return EBADE;
-    case 53: return EBADR;
-    case 54: return EXFULL;
-    case 55: return ENOANO;
-    case 56: return EBADRQC;
-    case 57: return EBADSLT;
-    case 59: return EBFONT;
-    case 60: return ENOSTR;
-    case 61: return ENODATA;
-    case 62: return ETIME;
-    case 63: return ENOSR;
-    case 64: return ENONET;
-    case 65: return ENOPKG;
-    case 66: return EREMOTE;
-    case 67: return ENOLINK;
-    case 68: return EADV;
-    case 69: return ESRMNT;
-    case 70: return ECOMM;
-    case 71: return EPROTO;
-    case 72: return EMULTIHOP;
-    case 73: return EDOTDOT;
-    case 74: return EBADMSG;
-    case 75: return EOVERFLOW;
-    case 76: return ENOTUNIQ;
-    case 77: return EBADFD;
-    case 78: return EREMCHG;
-    case 79: return ELIBACC;
-    case 80: return ELIBBAD;
-    case 81: return ELIBSCN;
-    case 82: return ELIBMAX;
-    case 83: return ELIBEXEC;
-    case 84: return EILSEQ;
-    case 85: return ERESTART;
-    case 86: return ESTRPIPE;
-    case 87: return EUSERS;
-    case 88: return ENOTSOCK;
-    case 89: return EDESTADDRREQ;
-    case 90: return EMSGSIZE;
-    case 91: return EPROTOTYPE;
-    case 92: return ENOPROTOOPT;
-    case 93: return EPROTONOSUPPORT;
-    case 94: return ESOCKTNOSUPPORT;
-    // same as ENOTSUP
-    case 95: return EOPNOTSUPP;
-    case 96: return EPFNOSUPPORT;
-    case 97: return EAFNOSUPPORT;
-    case 98: return EADDRINUSE;
-    case 99: return EADDRNOTAVAIL;
-    case 100: return ENETDOWN;
-    case 101: return ENETUNREACH;
-    case 102: return ENETRESET;
-    case 103: return ECONNABORTED;
-    case 104: return ECONNRESET;
-    case 105: return ENOBUFS;
-    case 106: return EISCONN;
-    case 107: return ENOTCONN;
-    case 108: return ESHUTDOWN;
-    case 109: return ETOOMANYREFS;
-    case 110: return ETIMEDOUT;
-    case 111: return ECONNREFUSED;
-    case 112: return EHOSTDOWN;
-    case 113: return EHOSTUNREACH;
-    case 114: return EALREADY;
-    case 115: return EINPROGRESS;
-    case 116: return ESTALE;
-    case 117: return EUCLEAN;
-    case 118: return ENOTNAM;
-    case 119: return ENAVAIL;
-    case 120: return EISNAM;
-    case 121: return EREMOTEIO;
-    case 122: return EDQUOT;
-    case 123: return ENOMEDIUM;
-    case 124: return EMEDIUMTYPE;
-    case 125: return ECANCELED;
-    case 126: return ENOKEY;
-    case 127: return EKEYEXPIRED;
-    case 128: return EKEYREVOKED;
-    case 129: return EKEYREJECTED;
-    case 130: return EOWNERDEAD;
-    case 131: return ENOTRECOVERABLE;
-    case 132: return ERFKILL;
-    case 133: return EHWPOISON;
-    default:
-      return r;
-  }
-}
-
-__u32 hostos_to_ceph_errno_unsigned(__u32 r) {
-  // Windows errno -> Linux errno
-  switch(r) {
-    case EPERM: return 1;
-    case ENOENT: return 2;
-    case ESRCH: return 3;
-    case EINTR: return 4;
-    case EIO: return 5;
-    case ENXIO: return 6;
-    case E2BIG: return 7;
-    case ENOEXEC: return 8;
-    case EBADF: return 9;
-    case ECHILD: return 10;
-    case EAGAIN: return 11;
-    case EWOULDBLOCK: return 11;
-    case ENOMEM: return 12;
-    case EACCES: return 13;
-    case EFAULT: return 14;
-    case ENOTBLK: return 15;
-    case EBUSY: return 16;
-    case EEXIST: return 17;
-    case EXDEV: return 18;
-    case ENODEV: return 19;
-    case ENOTDIR: return 20;
-    case EISDIR: return 21;
-    case EINVAL: return 22;
-    case ENFILE: return 23;
-    case EMFILE: return 24;
-    case ENOTTY: return 25;
-    case ETXTBSY: return 26;
-    case EFBIG: return 27;
-    case ENOSPC: return 28;
-    case ESPIPE: return 29;
-    case EROFS: return 30;
-    case EMLINK: return 31;
-    case EPIPE: return 32;
-    case EDOM: return 33;
-    case ERANGE: return 34;
-    // same as EDEADLOCK
-    // case EDEADLK: return 35;
-    case EDEADLOCK: return 35;
-    case ENAMETOOLONG: return 36;
-    case ENOLCK: return 37;
-    case ENOSYS: return 38;
-    case ENOTEMPTY: return 39;
-    case ELOOP: return 40;
-    case ENOMSG: return 42;
-    case EIDRM: return 43;
-    case ECHRNG: return 44;
-    case EL2NSYNC: return 45;
-    case EL3HLT: return 46;
-    case EL3RST: return 47;
-    case ELNRNG: return 48;
-    case EUNATCH: return 49;
-    case ENOCSI: return 50;
-    case EL2HLT: return 51;
-    case EBADE: return 52;
-    case EBADR: return 53;
-    case EXFULL: return 54;
-    case ENOANO: return 55;
-    case EBADRQC: return 56;
-    case EBADSLT: return 57;
-    case EBFONT: return 59;
-    case ENOSTR: return 60;
-    case ENODATA: return 61;
-    case ETIME: return 62;
-    case ENOSR: return 63;
-    case ENONET: return 64;
-    case ENOPKG: return 65;
-    case EREMOTE: return 66;
-    case ENOLINK: return 67;
-    case EADV: return 68;
-    case ESRMNT: return 69;
-    case ECOMM: return 70;
-    case EPROTO: return 71;
-    case EMULTIHOP: return 72;
-    case EDOTDOT: return 73;
-    case EBADMSG: return 74;
-    case EOVERFLOW: return 75;
-    case ENOTUNIQ: return 76;
-    case EBADFD: return 77;
-    case EREMCHG: return 78;
-    case ELIBACC: return 79;
-    case ELIBBAD: return 80;
-    case ELIBSCN: return 81;
-    case ELIBMAX: return 82;
-    case ELIBEXEC: return 83;
-    case EILSEQ: return 84;
-    // compat.h defines ERESTART as EINTR
-    // case ERESTART: return 85;
-    case ESTRPIPE: return 86;
-    case EUSERS: return 87;
-    case ENOTSOCK: return 88;
-    case EDESTADDRREQ: return 89;
-    case EMSGSIZE: return 90;
-    case EPROTOTYPE: return 91;
-    case ENOPROTOOPT: return 92;
-    case EPROTONOSUPPORT: return 93;
-    case ESOCKTNOSUPPORT: return 94;
-    case EOPNOTSUPP: return 95;
-    case ENOTSUP: return 95;
-    case EPFNOSUPPORT: return 96;
-    case EAFNOSUPPORT: return 97;
-    case EADDRINUSE: return 98;
-    case EADDRNOTAVAIL: return 99;
-    case ENETDOWN: return 100;
-    case ENETUNREACH: return 101;
-    case ENETRESET: return 102;
-    case ECONNABORTED: return 103;
-    case ECONNRESET: return 104;
-    case ENOBUFS: return 105;
-    case EISCONN: return 106;
-    case ENOTCONN: return 107;
-    case ESHUTDOWN: return 108;
-    case ETOOMANYREFS: return 109;
-    case ETIMEDOUT: return 110;
-    case ECONNREFUSED: return 111;
-    case EHOSTDOWN: return 112;
-    case EHOSTUNREACH: return 113;
-    case EALREADY: return 114;
-    case EINPROGRESS: return 115;
-    case ESTALE: return 116;
-    case EUCLEAN: return 117;
-    case ENOTNAM: return 118;
-    case ENAVAIL: return 119;
-    case EISNAM: return 120;
-    case EREMOTEIO: return 121;
-    case EDQUOT: return 122;
-    case ENOMEDIUM: return 123;
-    case EMEDIUMTYPE: return 124;
-    case ECANCELED: return 125;
-    case ENOKEY: return 126;
-    case EKEYEXPIRED: return 127;
-    case EKEYREVOKED: return 128;
-    case EKEYREJECTED: return 129;
-    case EOWNERDEAD: return 130;
-    case ENOTRECOVERABLE: return 131;
-    case ERFKILL: return 132;
-    case EHWPOISON: return 133;
-    default:
-      return r;
- }
-}
-
-__s32 wsae_to_errno_unsigned(__s32 r)
-{
-  switch(r) {
-    case WSAEINTR: return EINTR;
-    case WSAEBADF: return EBADF;
-    case WSAEACCES: return EACCES;
-    case WSAEFAULT: return EFAULT;
-    case WSAEINVAL: return EINVAL;
-    case WSAEMFILE: return EMFILE;
-    // Linux defines WSAEWOULDBLOCK as EAGAIN, but not Windows headers.
-    // Since all ceph code uses EAGAIN instead of EWOULDBLOCK, we'll do
-    // the same here.
-    case WSAEWOULDBLOCK: return EAGAIN;
-    // Some functions (e.g. connect) can return WSAEWOULDBLOCK instead of
-    // EINPROGRESS.
-    case WSAEINPROGRESS: return EINPROGRESS;
-    case WSAEALREADY: return EALREADY;
-    case WSAENOTSOCK: return ENOTSOCK;
-    case WSAEDESTADDRREQ: return EDESTADDRREQ;
-    case WSAEMSGSIZE: return EMSGSIZE;
-    case WSAEPROTOTYPE: return EPROTOTYPE;
-    case WSAENOPROTOOPT: return ENOPROTOOPT;
-    case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
-    case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT;
-    case WSAEOPNOTSUPP: return EOPNOTSUPP;
-    case WSAEPFNOSUPPORT: return EPFNOSUPPORT;
-    case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
-    case WSAEADDRINUSE: return EADDRINUSE;
-    case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
-    case WSAENETDOWN: return ENETDOWN;
-    case WSAENETUNREACH: return ENETUNREACH;
-    case WSAENETRESET: return ENETRESET;
-    case WSAECONNABORTED: return ECONNABORTED;
-    case WSAECONNRESET: return ECONNRESET;
-    case WSAENOBUFS: return ENOBUFS;
-    case WSAEISCONN: return EISCONN;
-    case WSAENOTCONN: return ENOTCONN;
-    case WSAESHUTDOWN: return ESHUTDOWN;
-    case WSAETOOMANYREFS: return ETOOMANYREFS;
-    case WSAETIMEDOUT: return ETIMEDOUT;
-    case WSAECONNREFUSED: return ECONNREFUSED;
-    case WSAELOOP: return ELOOP;
-    case WSAENAMETOOLONG: return ENAMETOOLONG;
-    case WSAEHOSTDOWN: return EHOSTDOWN;
-    case WSAEHOSTUNREACH: return EHOSTUNREACH;
-    case WSAENOTEMPTY: return ENOTEMPTY;
-    // case WSAEPROCLIM
-    case WSAEUSERS: return EUSERS;
-    case WSAEDQUOT: return EDQUOT;
-    case WSAESTALE: return ESTALE;
-    case WSAEREMOTE: return EREMOTE;
-    // case WSASYSNOTREADY
-    // case WSAVERNOTSUPPORTED
-    // case WSANOTINITIALISED
-    case WSAEDISCON: return ESHUTDOWN;
-    // case WSAENOMORE
-    case WSAECANCELLED: return ECANCELED;
-    // We might return EINVAL, but it's probably better if we propagate the
-    // original error code here.
-    // case WSAEINVALIDPROCTABLE
-    // case WSAEINVALIDPROVIDER
-    // case WSAEPROVIDERFAILEDINIT
-    // case WSASYSCALLFAILURE
-    // case WSASERVICE_NOT_FOUND:
-    // case WSATYPE_NOT_FOUND:
-    // case WSA_E_NO_MORE:
-    case WSA_E_CANCELLED: return ECANCELED;
-    case WSAEREFUSED: return ECONNREFUSED;
-    case WSAHOST_NOT_FOUND: return EHOSTUNREACH;
-    case WSATRY_AGAIN: return EAGAIN;
-    // case WSANO_RECOVERY
-    // case WSANO_DATA:
-    default: return r;
-  }
-}
-
-// converts from linux errno values to host values
-__s32 ceph_to_hostos_errno(__s32 r)
-{
-  int sign = (r < 0 ? -1 : 1);
-  return ceph_to_hostos_errno_unsigned(abs(r)) * sign;
-}
-
-// converts Host OS errno values to linux/Ceph values
-__s32 hostos_to_ceph_errno(__s32 r)
-{
-  int sign = (r < 0 ? -1 : 1);
-  return hostos_to_ceph_errno_unsigned(abs(r)) * sign;
-}
-
-__s32 wsae_to_errno(__s32 r)
-{
-  int sign = (r < 0 ? -1 : 1);
-  return wsae_to_errno_unsigned(abs(r)) * sign;
-}
-
-__u32 errno_to_ntstatus(__u32 r) {
-  // errno -> NTSTATUS
-  // In some cases, there might be more than one applicable NTSTATUS
-  // value or there might be none. Certain values can be overridden
-  // when the caller (or whoever is supposed to handle the error) is
-  // expecting a different NTSTATUS value.
-  switch(r) {
-    case 0: return 0;
-    case EPERM: return STATUS_ACCESS_DENIED;
-    case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND;
-    case ESRCH: return STATUS_NOT_FOUND;
-    case EINTR: return STATUS_RETRY;
-    case EIO: return STATUS_DATA_ERROR;
-    case ENXIO: return STATUS_NOT_FOUND;
-    case E2BIG: return STATUS_FILE_TOO_LARGE;
-    case ENOEXEC: return STATUS_ACCESS_DENIED;
-    case EBADF: return STATUS_INVALID_HANDLE;
-    case ECHILD: return STATUS_INTERNAL_ERROR;
-    case EAGAIN: return STATUS_RETRY;
-    case EWOULDBLOCK: return STATUS_RETRY;
-    case ENOMEM: return STATUS_NO_MEMORY;
-    case EACCES: return STATUS_ACCESS_DENIED;
-    case EFAULT: return STATUS_INVALID_ADDRESS;
-    case ENOTBLK: return STATUS_BAD_DEVICE_TYPE;
-    case EBUSY: return STATUS_DEVICE_BUSY;
-    case EEXIST: return STATUS_OBJECT_NAME_COLLISION;
-    case EXDEV: return STATUS_NOT_SAME_DEVICE;
-    case ENODEV: return STATUS_SYSTEM_DEVICE_NOT_FOUND;
-    case ENOTDIR: return STATUS_NOT_A_DIRECTORY;
-    case EISDIR: return STATUS_FILE_IS_A_DIRECTORY;
-    case EINVAL: return STATUS_INVALID_PARAMETER;
-    case ENFILE: return STATUS_TOO_MANY_OPENED_FILES;
-    case EMFILE: return STATUS_TOO_MANY_OPENED_FILES;
-    case ENOTTY: return STATUS_INVALID_PARAMETER;
-    case ETXTBSY: return STATUS_DEVICE_BUSY;
-    case EFBIG: return STATUS_FILE_TOO_LARGE;
-    case ENOSPC: return STATUS_DISK_FULL;
-    case ESPIPE: return STATUS_INVALID_PARAMETER;
-    case EROFS: return STATUS_MEDIA_WRITE_PROTECTED;
-    case EMLINK: return STATUS_TOO_MANY_LINKS;
-    case EPIPE: return STATUS_PIPE_BROKEN;
-    case EDOM: return STATUS_INVALID_PARAMETER;
-    case ERANGE: return STATUS_INVALID_PARAMETER;
-    // same as EDEADLOCK
-    // case EDEADLK: return 35;
-    case EDEADLOCK: return STATUS_POSSIBLE_DEADLOCK;
-    case ENAMETOOLONG: return STATUS_NAME_TOO_LONG;
-    case ENOLCK: return STATUS_NOT_LOCKED;
-    case ENOSYS: return STATUS_NOT_IMPLEMENTED;
-    case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
-    case ELOOP: return STATUS_TOO_MANY_LINKS;
-    case ENOMSG: return STATUS_MESSAGE_NOT_FOUND;
-    case EIDRM: return STATUS_INVALID_PARAMETER;
-    case ECHRNG: return STATUS_INVALID_PARAMETER;
-    case EL2NSYNC: return STATUS_INTERNAL_ERROR;
-    case EL3HLT: return STATUS_INTERNAL_ERROR;
-    case EL3RST: return STATUS_INTERNAL_ERROR;
-    case ELNRNG: return STATUS_INTERNAL_ERROR;
-    case EUNATCH: return STATUS_INTERNAL_ERROR;
-    case ENOCSI: return STATUS_INTERNAL_ERROR;
-    case EL2HLT: return STATUS_INTERNAL_ERROR;
-    case EBADE: return STATUS_INTERNAL_ERROR;
-    case EBADR: return STATUS_INVALID_HANDLE;
-    case EXFULL: return STATUS_DISK_FULL;
-    case ENOANO: return STATUS_INTERNAL_ERROR;
-    case EBADRQC: return STATUS_INVALID_PARAMETER;
-    case EBADSLT: return STATUS_INVALID_PARAMETER;
-    case EBFONT: return STATUS_INVALID_PARAMETER;
-    case ENOSTR: return STATUS_INVALID_PARAMETER;
-    case ENODATA: return STATUS_NOT_FOUND;
-    case ETIME: return STATUS_TIMEOUT;
-    case ENOSR: return STATUS_INSUFFICIENT_RESOURCES;
-    case ENONET: return STATUS_NETWORK_UNREACHABLE;
-    case ENOPKG: return STATUS_NO_SUCH_PACKAGE;
-    case EREMOTE: return STATUS_INVALID_PARAMETER;
-    case ENOLINK: return STATUS_INTERNAL_ERROR;
-    case EADV: return STATUS_INTERNAL_ERROR;
-    case ESRMNT: return STATUS_INTERNAL_ERROR;
-    case ECOMM: return STATUS_INTERNAL_ERROR;
-    case EPROTO: return STATUS_PROTOCOL_NOT_SUPPORTED;
-    case EMULTIHOP: return STATUS_INTERNAL_ERROR;
-    case EDOTDOT: return STATUS_INTERNAL_ERROR;
-    case EBADMSG: return STATUS_INVALID_PARAMETER;
-    case EOVERFLOW: return STATUS_BUFFER_OVERFLOW;
-    case ENOTUNIQ: return STATUS_DUPLICATE_NAME;
-    case EBADFD: return STATUS_INVALID_HANDLE;
-    case EREMCHG: return STATUS_FILE_RENAMED;
-    case ELIBACC: return STATUS_DLL_NOT_FOUND;
-    case ELIBBAD: return STATUS_BAD_DLL_ENTRYPOINT;
-    case ELIBSCN: return STATUS_BAD_DLL_ENTRYPOINT;
-    case ELIBMAX: return STATUS_TOO_MANY_OPENED_FILES;
-    case ELIBEXEC: return STATUS_INVALID_PARAMETER;
-    case EILSEQ: return STATUS_INVALID_PARAMETER;
-    // compat.h defines ERESTART as EINTR
-    // case ERESTART: return 85;
-    case ESTRPIPE: return STATUS_RETRY;
-    case EUSERS: return STATUS_TOO_MANY_SIDS;
-    case ENOTSOCK: return STATUS_INVALID_HANDLE;
-    case EDESTADDRREQ: return STATUS_INVALID_PARAMETER;
-    case EMSGSIZE: return STATUS_BUFFER_OVERFLOW;
-    case EPROTOTYPE: return STATUS_INVALID_PARAMETER;
-    case ENOPROTOOPT: return STATUS_PROTOCOL_NOT_SUPPORTED;
-    case EPROTONOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED;
-    case ESOCKTNOSUPPORT: return STATUS_NOT_SUPPORTED;
-    case EOPNOTSUPP: return STATUS_NOT_SUPPORTED;
-    case ENOTSUP: return STATUS_NOT_SUPPORTED;
-    case EPFNOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED;
-    case EAFNOSUPPORT: return STATUS_NOT_SUPPORTED;
-    case EADDRINUSE: return STATUS_ADDRESS_ALREADY_EXISTS;
-    case EADDRNOTAVAIL: return STATUS_INVALID_ADDRESS;
-    case ENETDOWN: return STATUS_NETWORK_UNREACHABLE;
-    case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
-    case ENETRESET: return STATUS_CONNECTION_RESET;
-    case ECONNABORTED: return STATUS_CONNECTION_ABORTED;
-    case ECONNRESET: return STATUS_CONNECTION_DISCONNECTED;
-    case ENOBUFS: return STATUS_BUFFER_TOO_SMALL;
-    case EISCONN: return STATUS_CONNECTION_ACTIVE;
-    case ENOTCONN: return 107;
-    case ESHUTDOWN: return 108;
-    case ETOOMANYREFS: return 109;
-    case ETIMEDOUT: return STATUS_TIMEOUT;
-    case ECONNREFUSED: return STATUS_CONNECTION_REFUSED;
-    case EHOSTDOWN: return STATUS_FILE_CLOSED;
-    case EHOSTUNREACH: return STATUS_HOST_UNREACHABLE;
-    case EALREADY: return STATUS_PENDING;
-    case EINPROGRESS: return STATUS_PENDING;
-    case ESTALE: return STATUS_INVALID_HANDLE;
-    case EUCLEAN: return STATUS_INVALID_PARAMETER;
-    case ENOTNAM: return STATUS_INVALID_PARAMETER;
-    case ENAVAIL: return STATUS_INVALID_PARAMETER;
-    case EISNAM: return STATUS_INVALID_PARAMETER;
-    case EREMOTEIO: return STATUS_DATA_ERROR;
-    case EDQUOT: return STATUS_QUOTA_EXCEEDED;
-    case ENOMEDIUM: return STATUS_NO_MEDIA;
-    case EMEDIUMTYPE: return STATUS_INVALID_PARAMETER;
-    case ECANCELED: return STATUS_REQUEST_CANCELED;
-    case ENOKEY: return STATUS_NO_USER_KEYS;
-    case EKEYEXPIRED: return STATUS_SMARTCARD_CERT_EXPIRED;
-    case EKEYREVOKED: return STATUS_IMAGE_CERT_REVOKED;
-    case EKEYREJECTED: return STATUS_ACCESS_DENIED;
-    case EOWNERDEAD: return STATUS_INTERNAL_ERROR;
-    case ENOTRECOVERABLE: return STATUS_INTERNAL_ERROR;
-    case ERFKILL: return STATUS_INTERNAL_ERROR;
-    case EHWPOISON: return STATUS_INTERNAL_ERROR;
-    default:
-      return STATUS_INTERNAL_ERROR;
- }
-}
-
-std::string win32_strerror(int err)
-{
-  // As opposed to dlerror messages, this has to be freed.
-  LPSTR msg = NULL;
-  DWORD msg_len = ::FormatMessageA(
-    FORMAT_MESSAGE_ALLOCATE_BUFFER |
-    FORMAT_MESSAGE_FROM_SYSTEM |
-    FORMAT_MESSAGE_IGNORE_INSERTS,
-    NULL,
-    err,
-    0,
-    (LPSTR) &msg,
-    0,
-    NULL);
-
-  std::ostringstream msg_stream;
-  msg_stream << "(" << err << ") ";
-  if (!msg_len) {
-    msg_stream << "Unknown error";
-  }
-  else {
-    msg_stream << msg;
-    ::LocalFree(msg);
-  }
-  return msg_stream.str();
-}
-
-std::string win32_lasterror_str()
-{
-  DWORD err = ::GetLastError();
-  return win32_strerror(err);
-}