summaryrefslogtreecommitdiffstats
path: root/src/common/win32
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/common/win32
parentInitial commit. (diff)
downloadceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz
ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/common/win32')
-rw-r--r--src/common/win32/SubProcess.cc306
-rw-r--r--src/common/win32/blkdev.cc137
-rw-r--r--src/common/win32/dlfcn.cc38
-rw-r--r--src/common/win32/dns_resolve.cc65
-rw-r--r--src/common/win32/errno.cc652
-rw-r--r--src/common/win32/event_logging.mc35
-rw-r--r--src/common/win32/ifaddrs.cc109
-rw-r--r--src/common/win32/registry.cc165
-rw-r--r--src/common/win32/registry.h38
-rw-r--r--src/common/win32/service.cc156
-rw-r--r--src/common/win32/service.h49
-rw-r--r--src/common/win32/syslog.cc77
12 files changed, 1827 insertions, 0 deletions
diff --git a/src/common/win32/SubProcess.cc b/src/common/win32/SubProcess.cc
new file mode 100644
index 000000000..ce6b851e0
--- /dev/null
+++ b/src/common/win32/SubProcess.cc
@@ -0,0 +1,306 @@
+/*
+ * 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);
+
+ int 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();
+ status = -ECHILD;
+ } else if (status) {
+ errstr << cmd << ": exit status: " << status;
+ }
+ } else {
+ errstr << cmd << ": Waiting for child process failed: " << pid
+ << ". Error code: " << GetLastError();
+ status = -ECHILD;
+ }
+
+ 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
index 000000000..bb815a044
--- /dev/null
+++ b/src/common/win32/blkdev.cc
@@ -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
index 000000000..329d14677
--- /dev/null
+++ b/src/common/win32/dlfcn.cc
@@ -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
index 000000000..8a7c80bff
--- /dev/null
+++ b/src/common/win32/dns_resolve.cc
@@ -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
index 000000000..bac9320a3
--- /dev/null
+++ b/src/common/win32/errno.cc
@@ -0,0 +1,652 @@
+// -*- 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"
+#include "include/fs_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(__s32 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.
+ r = abs(r);
+
+ 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 STATUS_CONNECTION_DISCONNECTED;
+ case ESHUTDOWN: return STATUS_SYSTEM_SHUTDOWN;
+ case ETOOMANYREFS: return STATUS_TOO_MANY_LINKS;
+ 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);
+}
+
+static const ceph::unordered_map<int,NTSTATUS> cephfs_errno_to_ntstatus = {
+ {CEPHFS_EBLOCKLISTED, STATUS_SYSTEM_SHUTDOWN},
+ {CEPHFS_EPERM, STATUS_ACCESS_DENIED},
+ {CEPHFS_ESTALE, STATUS_INVALID_HANDLE},
+ {CEPHFS_ENOSPC, STATUS_DISK_FULL},
+ {CEPHFS_ETIMEDOUT, STATUS_TIMEOUT},
+ {CEPHFS_EIO, STATUS_DATA_ERROR},
+ {CEPHFS_ENOTCONN, STATUS_CONNECTION_DISCONNECTED},
+ {CEPHFS_EEXIST, STATUS_OBJECT_NAME_COLLISION},
+ {CEPHFS_EINTR, STATUS_RETRY},
+ {CEPHFS_EINVAL, STATUS_INVALID_PARAMETER},
+ {CEPHFS_EBADF, STATUS_INVALID_HANDLE},
+ {CEPHFS_EROFS, STATUS_MEDIA_WRITE_PROTECTED},
+ {CEPHFS_EAGAIN, STATUS_RETRY},
+ {CEPHFS_EACCES, STATUS_ACCESS_DENIED},
+ {CEPHFS_ELOOP, STATUS_TOO_MANY_LINKS},
+ {CEPHFS_EISDIR, STATUS_FILE_IS_A_DIRECTORY},
+ {CEPHFS_ENOENT, STATUS_OBJECT_NAME_NOT_FOUND},
+ {CEPHFS_ENOTDIR, STATUS_NOT_A_DIRECTORY},
+ {CEPHFS_ENAMETOOLONG, STATUS_NAME_TOO_LONG},
+ {CEPHFS_EBUSY, STATUS_DEVICE_BUSY},
+ {CEPHFS_EDQUOT, STATUS_QUOTA_EXCEEDED},
+ {CEPHFS_EFBIG, STATUS_FILE_TOO_LARGE},
+ {CEPHFS_ERANGE, STATUS_INVALID_PARAMETER},
+ {CEPHFS_ENXIO, STATUS_NOT_FOUND},
+ {CEPHFS_ECANCELED, STATUS_REQUEST_CANCELED},
+ {CEPHFS_ENODATA, STATUS_NOT_FOUND},
+ {CEPHFS_EOPNOTSUPP, STATUS_NOT_SUPPORTED},
+ {CEPHFS_EXDEV, STATUS_NOT_SAME_DEVICE},
+ {CEPHFS_ENOMEM, STATUS_NO_MEMORY},
+ {CEPHFS_ENOTRECOVERABLE, STATUS_INTERNAL_ERROR},
+ {CEPHFS_ENOSYS, STATUS_NOT_IMPLEMENTED},
+ {CEPHFS_ENOTEMPTY, STATUS_DIRECTORY_NOT_EMPTY},
+ {CEPHFS_EDEADLK, STATUS_POSSIBLE_DEADLOCK},
+ {CEPHFS_EDOM, STATUS_INVALID_PARAMETER},
+ {CEPHFS_EMLINK, STATUS_TOO_MANY_LINKS},
+ {CEPHFS_ETIME, STATUS_TIMEOUT},
+ {CEPHFS_EOLDSNAPC, STATUS_DATA_ERROR}
+};
+
+__u32 cephfs_errno_to_ntsatus(int cephfs_errno)
+{
+ cephfs_errno = abs(cephfs_errno);
+
+ if (cephfs_errno == 0)
+ return 0;
+
+ auto it = cephfs_errno_to_ntstatus.find(cephfs_errno);
+ if (it != cephfs_errno_to_ntstatus.end())
+ return it->second;
+ return STATUS_INTERNAL_ERROR;
+}
diff --git a/src/common/win32/event_logging.mc b/src/common/win32/event_logging.mc
new file mode 100644
index 000000000..3d08889aa
--- /dev/null
+++ b/src/common/win32/event_logging.mc
@@ -0,0 +1,35 @@
+SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
+ Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
+ Warning=0x2:STATUS_SEVERITY_WARNING
+ Error=0x3:STATUS_SEVERITY_ERROR
+ )
+
+
+MessageId=0x0001
+Severity=Success
+SymbolicName=SUCCESS_EVENTMSG
+Language=English
+%1
+.
+
+MessageId=0x0002
+Severity=Informational
+SymbolicName=INFO_EVENTMSG
+Language=English
+%1
+.
+
+MessageId=0x0003
+Severity=Warning
+SymbolicName=WARN_EVENTMSG
+Language=English
+%1
+.
+
+MessageId=0x0004
+Severity=Error
+SymbolicName=ERROR_EVENTMSG
+Language=English
+%1
+.
+
diff --git a/src/common/win32/ifaddrs.cc b/src/common/win32/ifaddrs.cc
new file mode 100644
index 000000000..d7de4a5ff
--- /dev/null
+++ b/src/common/win32/ifaddrs.cc
@@ -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
index 000000000..85ab80df9
--- /dev/null
+++ b/src/common/win32/registry.cc
@@ -0,0 +1,165 @@
+/*
+ * 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, bool& value)
+{
+ DWORD value_dw = 0;
+ int r = get(lpValue, value_dw);
+ if (!r) {
+ value = !!value_dw;
+ }
+ return r;
+}
+
+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
index 000000000..fdaf9708a
--- /dev/null
+++ b/src/common/win32/registry.h
@@ -0,0 +1,38 @@
+/*
+ * 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, bool& value);
+ 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
index 000000000..846c5d09d
--- /dev/null
+++ b/src/common/win32/service.cc
@@ -0,0 +1,156 @@
+/*
+ * 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) {
+ lderr(s_service->cct) << "Could not initialize service control handler. "
+ << "Error: " << GetLastError() << dendl;
+ return;
+ }
+
+ s_service->set_status(SERVICE_START_PENDING);
+
+ // TODO: should we expect exceptions?
+ ldout(s_service->cct, 5) << "Starting service." << dendl;
+ int err = s_service->run_hook();
+ if (err) {
+ lderr(s_service->cct) << "Failed to start service. Error code: "
+ << err << dendl;
+ s_service->shutdown(true);
+ } else {
+ ldout(s_service->cct, 5) << "Successfully started service." << dendl;
+ s_service->set_status(SERVICE_RUNNING);
+ }
+}
+
+void ServiceBase::shutdown(bool ignore_errors)
+{
+ 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;
+ if (ignore_errors) {
+ derr << "Ignoring shutdown hook failure, marking the service as stopped."
+ << dendl;
+ set_status(SERVICE_STOPPED);
+ } else {
+ derr << "Reverting to original service state." << dendl;
+ set_status(original_state);
+ }
+ } else {
+ dout(5) << "Shutdown hook completed." << dendl;
+ 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 {
+ dout(5) << "Successfully stopped service." << dendl;
+ 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) {
+ dout(5) << "Updating service service status (" << current_state
+ << ") and exit code(" << exit_code << ")." << dendl;
+ ::SetServiceStatus(hstatus, &status);
+ } else {
+ derr << "Service control handler not initialized. Cannot "
+ << "update service status (" << current_state
+ << ") and exit code(" << exit_code << ")." << dendl;
+ }
+}
diff --git a/src/common/win32/service.h b/src/common/win32/service.h
new file mode 100644
index 000000000..20d37a876
--- /dev/null
+++ b/src/common/win32/service.h
@@ -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(bool ignore_errors = false);
+ 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/syslog.cc b/src/common/win32/syslog.cc
new file mode 100644
index 000000000..7a1a90c9b
--- /dev/null
+++ b/src/common/win32/syslog.cc
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include <syslog.h>
+#include "event_logging.h"
+#include "common/code_environment.h"
+
+static HANDLE g_event_source = NULL;
+
+bool get_event_source()
+{
+ if (!g_event_source) {
+ HANDLE temp = RegisterEventSourceA(NULL, get_process_name_cpp().c_str());
+ if (!temp)
+ return false;
+
+ if (InterlockedCompareExchangePointer(&g_event_source, temp, NULL)) {
+ // There already was an event source, let's cleanup the one that we've
+ // just created.
+ DeregisterEventSource(temp);
+ }
+ }
+
+ return true;
+}
+
+void write_event_log_entry(int level, const char* msg)
+{
+ if (!get_event_source()) {
+ return;
+ }
+
+ WORD type;
+ DWORD event_id;
+ switch (level) {
+ case LOG_DEBUG:
+ event_id = SUCCESS_EVENTMSG;
+ type = EVENTLOG_SUCCESS;
+ break;
+
+ case LOG_INFO:
+ case LOG_NOTICE:
+ event_id = INFO_EVENTMSG;
+ type = EVENTLOG_INFORMATION_TYPE;
+ break;
+
+ case LOG_WARNING:
+ event_id = WARN_EVENTMSG;
+ type = EVENTLOG_WARNING_TYPE;
+ break;
+
+ default:
+ event_id = ERROR_EVENTMSG;
+ type = EVENTLOG_ERROR_TYPE;
+ }
+
+ ReportEventA(g_event_source, type,
+ 0, event_id, NULL, 1, 0, &msg, NULL);
+}
+
+void syslog(int priority, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ size_t length = (size_t)_vscprintf(format, args) + 1;
+
+ char* buffer = (char*) malloc(length);
+ if (NULL == buffer) {
+ va_end(args);
+ return;
+ }
+
+ vsnprintf_s(buffer, length, length - 1, format, args);
+ va_end(args);
+
+ write_event_log_entry(LOG_PRI(priority), buffer);
+ free(buffer);
+}