252132d975
Change-Id: Icc9cd3410cde2589ea51385c651243e11cc2f1d9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155855 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
910 lines
22 KiB
C++
910 lines
22 KiB
C++
/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <string_view>
|
|
|
|
#include <config_features.h>
|
|
|
|
#include "uunxapi.hxx"
|
|
#include "system.hxx"
|
|
#include "unixerrnostring.hxx"
|
|
#include <limits.h>
|
|
#include <rtl/ustring.hxx>
|
|
#include <osl/thread.h>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <utime.h>
|
|
|
|
#ifdef ANDROID
|
|
#include <osl/detail/android-bootstrap.h>
|
|
#endif
|
|
|
|
OString osl::OUStringToOString(std::u16string_view s)
|
|
{
|
|
return rtl::OUStringToOString(s, osl_getThreadTextEncoding());
|
|
}
|
|
|
|
#if HAVE_FEATURE_MACOSX_SANDBOX
|
|
|
|
#include <Foundation/Foundation.h>
|
|
#include <Security/Security.h>
|
|
#include <mach-o/dyld.h>
|
|
|
|
static NSUserDefaults *userDefaults = NULL;
|
|
static bool isSandboxed = false;
|
|
|
|
static void do_once()
|
|
{
|
|
SecCodeRef code;
|
|
OSStatus rc = SecCodeCopySelf(kSecCSDefaultFlags, &code);
|
|
|
|
SecStaticCodeRef staticCode;
|
|
if (rc == errSecSuccess)
|
|
rc = SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &staticCode);
|
|
|
|
CFDictionaryRef signingInformation;
|
|
if (rc == errSecSuccess)
|
|
rc = SecCodeCopySigningInformation(staticCode, kSecCSRequirementInformation, &signingInformation);
|
|
|
|
CFDictionaryRef entitlements = NULL;
|
|
if (rc == errSecSuccess)
|
|
entitlements = (CFDictionaryRef) CFDictionaryGetValue(signingInformation, kSecCodeInfoEntitlementsDict);
|
|
|
|
if (entitlements != NULL)
|
|
if (CFDictionaryGetValue(entitlements, CFSTR("com.apple.security.app-sandbox")) != NULL)
|
|
isSandboxed = true;
|
|
|
|
if (isSandboxed)
|
|
userDefaults = [NSUserDefaults standardUserDefaults];
|
|
}
|
|
|
|
typedef struct {
|
|
NSURL *scopeURL;
|
|
NSAutoreleasePool *pool;
|
|
} accessFilePathState;
|
|
|
|
static accessFilePathState *
|
|
prepare_to_access_file_path( const char *cpFilePath )
|
|
{
|
|
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
|
pthread_once(&once, &do_once);
|
|
NSURL *fileURL = nil;
|
|
NSData *data = nil;
|
|
BOOL stale;
|
|
accessFilePathState *state;
|
|
|
|
if (!isSandboxed)
|
|
return NULL;
|
|
|
|
// If malloc() fails we are screwed anyway
|
|
state = (accessFilePathState*) malloc(sizeof(accessFilePathState));
|
|
|
|
state->pool = [[NSAutoreleasePool alloc] init];
|
|
state->scopeURL = nil;
|
|
|
|
if (userDefaults != nil)
|
|
fileURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:cpFilePath]];
|
|
|
|
if (fileURL != nil)
|
|
data = [userDefaults dataForKey:[@"bookmarkFor:" stringByAppendingString:[fileURL absoluteString]]];
|
|
|
|
if (data != nil)
|
|
state->scopeURL = [NSURL URLByResolvingBookmarkData:data
|
|
options:NSURLBookmarkResolutionWithSecurityScope
|
|
relativeToURL:nil
|
|
bookmarkDataIsStale:&stale
|
|
error:nil];
|
|
if (state->scopeURL != nil)
|
|
[state->scopeURL startAccessingSecurityScopedResource];
|
|
|
|
return state;
|
|
}
|
|
|
|
static void
|
|
done_accessing_file_path( const char * /*cpFilePath*/, accessFilePathState *state )
|
|
{
|
|
if (!isSandboxed)
|
|
return;
|
|
|
|
int saved_errno = errno;
|
|
|
|
if (state->scopeURL != nil)
|
|
[state->scopeURL stopAccessingSecurityScopedResource];
|
|
[state->pool release];
|
|
free(state);
|
|
|
|
errno = saved_errno;
|
|
}
|
|
|
|
#else
|
|
|
|
typedef void accessFilePathState;
|
|
|
|
#define prepare_to_access_file_path( cpFilePath ) nullptr
|
|
|
|
#define done_accessing_file_path( cpFilePath, state ) ((void) cpFilePath, (void) state)
|
|
|
|
#endif
|
|
|
|
#ifdef MACOSX
|
|
/*
|
|
* Helper function for resolving Mac native alias files (not the same as unix alias files)
|
|
* and to return the resolved alias as OString
|
|
*/
|
|
static OString macxp_resolveAliasAndConvert(OString const & p)
|
|
{
|
|
char path[PATH_MAX];
|
|
if (p.getLength() < PATH_MAX)
|
|
{
|
|
strcpy(path, p.getStr());
|
|
macxp_resolveAlias(path, PATH_MAX);
|
|
return path;
|
|
}
|
|
return p;
|
|
}
|
|
#endif /* MACOSX */
|
|
|
|
int osl::access(const OString& pstrPath, int mode)
|
|
{
|
|
OString fn = pstrPath;
|
|
#ifdef ANDROID
|
|
if (fn == "/assets" || fn.startsWith("/assets/"))
|
|
{
|
|
struct stat stat;
|
|
if (lo_apk_lstat(fn.getStr(), &stat) == -1)
|
|
return -1;
|
|
if (mode & W_OK)
|
|
{
|
|
errno = EACCES;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MACOSX
|
|
fn = macxp_resolveAliasAndConvert(fn);
|
|
#endif
|
|
|
|
accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
|
|
|
|
int result = ::access(fn.getStr(), mode);
|
|
int saved_errno = errno;
|
|
if (result == -1)
|
|
SAL_INFO("sal.file", "access(" << fn << ",0" << std::oct << mode << std::dec << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "access(" << fn << ",0" << std::oct << mode << std::dec << "): OK");
|
|
|
|
done_accessing_file_path(fn.getStr(), state);
|
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
namespace {
|
|
|
|
OString toOString(OString const & s) { return s; }
|
|
|
|
OString toOString(std::u16string_view s) { return osl::OUStringToOString(s); }
|
|
|
|
template<typename T> T fromOString(OString const &) = delete;
|
|
|
|
template<> OString fromOString(OString const & s) { return s; }
|
|
|
|
template<> OUString fromOString(OString const & s)
|
|
{ return OStringToOUString(s, osl_getThreadTextEncoding()); }
|
|
|
|
template<typename T> bool realpath_(const T& pstrFileName, T& ppstrResolvedName)
|
|
{
|
|
OString fn = toOString(pstrFileName);
|
|
#if defined ANDROID || defined(EMSCRIPTEN)
|
|
#if defined ANDROID
|
|
if (fn == "/assets" || fn.startsWith("/assets/"))
|
|
#else
|
|
if (fn == "/instdir" || fn.startsWith("/instdir/"))
|
|
#endif
|
|
{
|
|
if (osl::access(fn, F_OK) == -1)
|
|
return false;
|
|
|
|
ppstrResolvedName = pstrFileName;
|
|
|
|
return true;
|
|
}
|
|
#endif // ANDROID || EMSCRIPTEN
|
|
|
|
#ifdef MACOSX
|
|
fn = macxp_resolveAliasAndConvert(fn);
|
|
#endif
|
|
|
|
accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
|
|
|
|
char rp[PATH_MAX];
|
|
bool bRet = realpath(fn.getStr(), rp);
|
|
int saved_errno = errno;
|
|
if (!bRet)
|
|
SAL_INFO("sal.file", "realpath(" << fn << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "realpath(" << fn << "): OK");
|
|
|
|
done_accessing_file_path(fn.getStr(), state);
|
|
|
|
if (bRet)
|
|
{
|
|
ppstrResolvedName = fromOString<T>(OString(rp));
|
|
}
|
|
|
|
errno = saved_errno;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
}
|
|
|
|
bool osl::realpath(const OUString& pustrFileName, OUString& ppustrResolvedName)
|
|
{
|
|
return realpath_(pustrFileName, ppustrResolvedName);
|
|
}
|
|
|
|
bool osl::realpath(const OString& pstrFileName, OString& ppstrResolvedName)
|
|
{
|
|
return realpath_(pstrFileName, ppstrResolvedName);
|
|
}
|
|
|
|
int stat_c(const char* cpPath, struct stat* buf)
|
|
{
|
|
#ifdef ANDROID
|
|
if (strncmp(cpPath, "/assets", sizeof("/assets")-1) == 0 &&
|
|
(cpPath[sizeof("/assets")-1] == '\0' ||
|
|
cpPath[sizeof("/assets")-1] == '/'))
|
|
return lo_apk_lstat(cpPath, buf);
|
|
#endif
|
|
|
|
accessFilePathState *state = prepare_to_access_file_path(cpPath);
|
|
|
|
int result = stat(cpPath, buf);
|
|
int saved_errno = errno;
|
|
if (result == -1)
|
|
SAL_INFO("sal.file", "stat(" << cpPath << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "stat(" << cpPath << "): OK");
|
|
|
|
done_accessing_file_path(cpPath, state);
|
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
int lstat_c(const char* cpPath, struct stat* buf)
|
|
{
|
|
#ifdef ANDROID
|
|
if (strncmp(cpPath, "/assets", sizeof("/assets")-1) == 0 &&
|
|
(cpPath[sizeof("/assets")-1] == '\0' ||
|
|
cpPath[sizeof("/assets")-1] == '/'))
|
|
return lo_apk_lstat(cpPath, buf);
|
|
#endif
|
|
|
|
accessFilePathState *state = prepare_to_access_file_path(cpPath);
|
|
|
|
int result = lstat(cpPath, buf);
|
|
int saved_errno = errno;
|
|
if (result == -1)
|
|
SAL_INFO("sal.file", "lstat(" << cpPath << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "lstat(" << cpPath << "): OK");
|
|
|
|
done_accessing_file_path(cpPath, state);
|
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
namespace {
|
|
|
|
template<typename T> int lstat_(const T& pstrPath, struct stat& buf)
|
|
{
|
|
OString fn = toOString(pstrPath);
|
|
|
|
#ifdef MACOSX
|
|
fn = macxp_resolveAliasAndConvert(fn);
|
|
#endif
|
|
|
|
return lstat_c(fn.getStr(), &buf);
|
|
}
|
|
|
|
}
|
|
|
|
int osl::lstat(const OUString& pustrPath, struct stat& buf)
|
|
{
|
|
return lstat_(pustrPath, buf);
|
|
}
|
|
|
|
int osl::lstat(const OString& pstrPath, struct stat& buf)
|
|
{
|
|
return lstat_(pstrPath, buf);
|
|
}
|
|
|
|
int osl::mkdir(const OString& path, mode_t mode)
|
|
{
|
|
accessFilePathState *state = prepare_to_access_file_path(path.getStr());
|
|
|
|
int result = ::mkdir(path.getStr(), mode);
|
|
int saved_errno = errno;
|
|
if (result == -1)
|
|
SAL_INFO("sal.file", "mkdir(" << path << ",0" << std::oct << mode << std::dec << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "mkdir(" << path << ",0" << std::oct << mode << std::dec << "): OK");
|
|
|
|
done_accessing_file_path(path.getStr(), state);
|
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
int open_c(const OString& path, int oflag, int mode)
|
|
{
|
|
accessFilePathState *state = prepare_to_access_file_path(path.getStr());
|
|
|
|
int result = open(path.getStr(), oflag, mode);
|
|
int saved_errno = errno;
|
|
if (result == -1)
|
|
SAL_INFO("sal.file", "open(" << path << ",0" << std::oct << oflag << ",0" << mode << std::dec << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "open(" << path << ",0" << std::oct << oflag << ",0" << mode << std::dec << ") => " << result);
|
|
|
|
#if HAVE_FEATURE_MACOSX_SANDBOX
|
|
if (isSandboxed && result != -1 && (oflag & O_CREAT) && (oflag & O_EXCL))
|
|
{
|
|
// A new file was created. Check if it is outside the sandbox.
|
|
// (In that case it must be one the user selected as export or
|
|
// save destination in a file dialog, otherwise we wouldn't
|
|
// have been able to create it.) Create and store a security
|
|
// scoped bookmark for it so that we can access the file in
|
|
// the future, too. (For the "Recent Files" functionality.)
|
|
const char *sandbox = [NSHomeDirectory() UTF8String];
|
|
if (!(strncmp(sandbox, path.getStr(), strlen(sandbox)) == 0 &&
|
|
path[strlen(sandbox)] == '/'))
|
|
{
|
|
auto cpPath = path.getStr();
|
|
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:cpPath]];
|
|
NSData *data = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
|
|
includingResourceValuesForKeys:nil
|
|
relativeToURL:nil
|
|
error:nil];
|
|
if (data != NULL)
|
|
{
|
|
[userDefaults setObject:data
|
|
forKey:[@"bookmarkFor:" stringByAppendingString:[url absoluteString]]];
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
done_accessing_file_path(path.getStr(), state);
|
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
int utime_c(const char *cpPath, struct utimbuf *times)
|
|
{
|
|
accessFilePathState *state = prepare_to_access_file_path(cpPath);
|
|
|
|
int result = utime(cpPath, times);
|
|
|
|
done_accessing_file_path(cpPath, state);
|
|
|
|
return result;
|
|
}
|
|
|
|
int ftruncate_with_name(int fd, sal_uInt64 uSize, const OString& path)
|
|
{
|
|
/* When sandboxed on macOS, ftruncate(), even if it takes an
|
|
* already open file descriptor which was returned from an open()
|
|
* call already checked by the sandbox, still requires a security
|
|
* scope bookmark for the file to be active in case the file is
|
|
* one that the sandbox doesn't otherwise allow access to. Luckily
|
|
* LibreOffice usually calls ftruncate() through the helpful C++
|
|
* abstraction layer that keeps the pathname around.
|
|
*/
|
|
|
|
OString fn(path);
|
|
|
|
#ifdef MACOSX
|
|
fn = macxp_resolveAliasAndConvert(fn);
|
|
#endif
|
|
|
|
accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
|
|
|
|
int result = ftruncate(fd, uSize);
|
|
int saved_errno = errno;
|
|
if (result < 0)
|
|
SAL_INFO("sal.file", "ftruncate(" << fd << "," << uSize << "): " << UnixErrnoString(saved_errno));
|
|
else
|
|
SAL_INFO("sal.file", "ftruncate(" << fd << "," << uSize << "): OK");
|
|
|
|
done_accessing_file_path(fn.getStr(), state);
|
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
std::string UnixErrnoString(int nErrno)
|
|
{
|
|
// Errnos from <asm-generic/errno-base.h> and <asm-generic/errno.h> on Linux and <sys/errno.h>
|
|
// on macOS.
|
|
switch (nErrno)
|
|
{
|
|
case EPERM:
|
|
return "EPERM";
|
|
case ENOENT:
|
|
return "ENOENT";
|
|
case ESRCH:
|
|
return "ESRCH";
|
|
case EINTR:
|
|
return "EINTR";
|
|
case EIO:
|
|
return "EIO";
|
|
case ENXIO:
|
|
return "ENXIO";
|
|
case E2BIG:
|
|
return "E2BIG";
|
|
case ENOEXEC:
|
|
return "ENOEXEC";
|
|
case EBADF:
|
|
return "EBADF";
|
|
case ECHILD:
|
|
return "ECHILD";
|
|
case EAGAIN:
|
|
return "EAGAIN";
|
|
case ENOMEM:
|
|
return "ENOMEM";
|
|
case EACCES:
|
|
return "EACCES";
|
|
case EFAULT:
|
|
return "EFAULT";
|
|
#ifdef ENOTBLK
|
|
case ENOTBLK:
|
|
return "ENOTBLK";
|
|
#endif
|
|
case EBUSY:
|
|
return "EBUSY";
|
|
case EEXIST:
|
|
return "EEXIST";
|
|
case EXDEV:
|
|
return "EXDEV";
|
|
case ENODEV:
|
|
return "ENODEV";
|
|
case ENOTDIR:
|
|
return "ENOTDIR";
|
|
case EISDIR:
|
|
return "EISDIR";
|
|
case EINVAL:
|
|
return "EINVAL";
|
|
case ENFILE:
|
|
return "ENFILE";
|
|
case EMFILE:
|
|
return "EMFILE";
|
|
case ENOTTY:
|
|
return "ENOTTY";
|
|
case ETXTBSY:
|
|
return "ETXTBSY";
|
|
case EFBIG:
|
|
return "EFBIG";
|
|
case ENOSPC:
|
|
return "ENOSPC";
|
|
case ESPIPE:
|
|
return "ESPIPE";
|
|
case EROFS:
|
|
return "EROFS";
|
|
case EMLINK:
|
|
return "EMLINK";
|
|
case EPIPE:
|
|
return "EPIPE";
|
|
case EDOM:
|
|
return "EDOM";
|
|
case ERANGE:
|
|
return "ERANGE";
|
|
case EDEADLK:
|
|
return "EDEADLK";
|
|
case ENAMETOOLONG:
|
|
return "ENAMETOOLONG";
|
|
case ENOLCK:
|
|
return "ENOLCK";
|
|
case ENOSYS:
|
|
return "ENOSYS";
|
|
case ENOTEMPTY:
|
|
return "ENOTEMPTY";
|
|
case ELOOP:
|
|
return "ELOOP";
|
|
case ENOMSG:
|
|
return "ENOMSG";
|
|
case EIDRM:
|
|
return "EIDRM";
|
|
#ifdef ECHRNG
|
|
case ECHRNG:
|
|
return "ECHRNG";
|
|
#endif
|
|
#ifdef EL2NSYNC
|
|
case EL2NSYNC:
|
|
return "EL2NSYNC";
|
|
#endif
|
|
#ifdef EL3HLT
|
|
case EL3HLT:
|
|
return "EL3HLT";
|
|
#endif
|
|
#ifdef EL3RST
|
|
case EL3RST:
|
|
return "EL3RST";
|
|
#endif
|
|
#ifdef ELNRNG
|
|
case ELNRNG:
|
|
return "ELNRNG";
|
|
#endif
|
|
#ifdef EUNATCH
|
|
case EUNATCH:
|
|
return "EUNATCH";
|
|
#endif
|
|
#ifdef ENOCSI
|
|
case ENOCSI:
|
|
return "ENOCSI";
|
|
#endif
|
|
#ifdef EL2HLT
|
|
case EL2HLT:
|
|
return "EL2HLT";
|
|
#endif
|
|
#ifdef EBADE
|
|
case EBADE:
|
|
return "EBADE";
|
|
#endif
|
|
#ifdef EBADR
|
|
case EBADR:
|
|
return "EBADR";
|
|
#endif
|
|
#ifdef EXFULL
|
|
case EXFULL:
|
|
return "EXFULL";
|
|
#endif
|
|
#ifdef ENOANO
|
|
case ENOANO:
|
|
return "ENOANO";
|
|
#endif
|
|
#ifdef EBADRQC
|
|
case EBADRQC:
|
|
return "EBADRQC";
|
|
#endif
|
|
#ifdef EBADSLT
|
|
case EBADSLT:
|
|
return "EBADSLT";
|
|
#endif
|
|
#ifdef EBFONT
|
|
case EBFONT:
|
|
return "EBFONT";
|
|
#endif
|
|
case ENOSTR:
|
|
return "ENOSTR";
|
|
case ENODATA:
|
|
return "ENODATA";
|
|
case ETIME:
|
|
return "ETIME";
|
|
case ENOSR:
|
|
return "ENOSR";
|
|
#ifdef ENONET
|
|
case ENONET:
|
|
return "ENONET";
|
|
#endif
|
|
#ifdef ENOPKG
|
|
case ENOPKG:
|
|
return "ENOPKG";
|
|
#endif
|
|
#ifdef EREMOTE
|
|
case EREMOTE:
|
|
return "EREMOTE";
|
|
#endif
|
|
case ENOLINK:
|
|
return "ENOLINK";
|
|
#ifdef EADV
|
|
case EADV:
|
|
return "EADV";
|
|
#endif
|
|
#ifdef ESRMNT
|
|
case ESRMNT:
|
|
return "ESRMNT";
|
|
#endif
|
|
#ifdef ECOMM
|
|
case ECOMM:
|
|
return "ECOMM";
|
|
#endif
|
|
case EPROTO:
|
|
return "EPROTO";
|
|
case EMULTIHOP:
|
|
return "EMULTIHOP";
|
|
#ifdef EDOTDOT
|
|
case EDOTDOT:
|
|
return "EDOTDOT";
|
|
#endif
|
|
case EBADMSG:
|
|
return "EBADMSG";
|
|
case EOVERFLOW:
|
|
return "EOVERFLOW";
|
|
#ifdef ENOTUNIQ
|
|
case ENOTUNIQ:
|
|
return "ENOTUNIQ";
|
|
#endif
|
|
#ifdef EBADFD
|
|
case EBADFD:
|
|
return "EBADFD";
|
|
#endif
|
|
#ifdef EREMCHG
|
|
case EREMCHG:
|
|
return "EREMCHG";
|
|
#endif
|
|
#ifdef ELIBACC
|
|
case ELIBACC:
|
|
return "ELIBACC";
|
|
#endif
|
|
#ifdef ELIBBAD
|
|
case ELIBBAD:
|
|
return "ELIBBAD";
|
|
#endif
|
|
#ifdef ELIBSCN
|
|
case ELIBSCN:
|
|
return "ELIBSCN";
|
|
#endif
|
|
#ifdef ELIBMAX
|
|
case ELIBMAX:
|
|
return "ELIBMAX";
|
|
#endif
|
|
#ifdef ELIBEXEC
|
|
case ELIBEXEC:
|
|
return "ELIBEXEC";
|
|
#endif
|
|
case EILSEQ:
|
|
return "EILSEQ";
|
|
#ifdef ERESTART
|
|
case ERESTART:
|
|
return "ERESTART";
|
|
#endif
|
|
#ifdef ESTRPIPE
|
|
case ESTRPIPE:
|
|
return "ESTRPIPE";
|
|
#endif
|
|
#ifdef EUSERS
|
|
case EUSERS:
|
|
return "EUSERS";
|
|
#endif
|
|
case ENOTSOCK:
|
|
return "ENOTSOCK";
|
|
case EDESTADDRREQ:
|
|
return "EDESTADDRREQ";
|
|
case EMSGSIZE:
|
|
return "EMSGSIZE";
|
|
case EPROTOTYPE:
|
|
return "EPROTOTYPE";
|
|
case ENOPROTOOPT:
|
|
return "ENOPROTOOPT";
|
|
case EPROTONOSUPPORT:
|
|
return "EPROTONOSUPPORT";
|
|
#ifdef ESOCKTNOSUPPORT
|
|
case ESOCKTNOSUPPORT:
|
|
return "ESOCKTNOSUPPORT";
|
|
#endif
|
|
#ifdef EOPNOTSUPP
|
|
case EOPNOTSUPP:
|
|
return "EOPNOTSUPP";
|
|
#endif
|
|
case EPFNOSUPPORT:
|
|
return "EPFNOSUPPORT";
|
|
case EAFNOSUPPORT:
|
|
return "EAFNOSUPPORT";
|
|
case EADDRINUSE:
|
|
return "EADDRINUSE";
|
|
case EADDRNOTAVAIL:
|
|
return "EADDRNOTAVAIL";
|
|
case ENETDOWN:
|
|
return "ENETDOWN";
|
|
case ENETUNREACH:
|
|
return "ENETUNREACH";
|
|
case ENETRESET:
|
|
return "ENETRESET";
|
|
case ECONNABORTED:
|
|
return "ECONNABORTED";
|
|
case ECONNRESET:
|
|
return "ECONNRESET";
|
|
case ENOBUFS:
|
|
return "ENOBUFS";
|
|
case EISCONN:
|
|
return "EISCONN";
|
|
case ENOTCONN:
|
|
return "ENOTCONN";
|
|
#ifdef ESHUTDOWN
|
|
case ESHUTDOWN:
|
|
return "ESHUTDOWN";
|
|
#endif
|
|
#ifdef ETOOMANYREFS
|
|
case ETOOMANYREFS:
|
|
return "ETOOMANYREFS";
|
|
#endif
|
|
case ETIMEDOUT:
|
|
return "ETIMEDOUT";
|
|
case ECONNREFUSED:
|
|
return "ECONNREFUSED";
|
|
#ifdef EHOSTDOWN
|
|
case EHOSTDOWN:
|
|
return "EHOSTDOWN";
|
|
#endif
|
|
case EHOSTUNREACH:
|
|
return "EHOSTUNREACH";
|
|
case EALREADY:
|
|
return "EALREADY";
|
|
case EINPROGRESS:
|
|
return "EINPROGRESS";
|
|
case ESTALE:
|
|
return "ESTALE";
|
|
#ifdef EUCLEAN
|
|
case EUCLEAN:
|
|
return "EUCLEAN";
|
|
#endif
|
|
#ifdef ENOTNAM
|
|
case ENOTNAM:
|
|
return "ENOTNAM";
|
|
#endif
|
|
#ifdef ENAVAIL
|
|
case ENAVAIL:
|
|
return "ENAVAIL";
|
|
#endif
|
|
#ifdef EISNAM
|
|
case EISNAM:
|
|
return "EISNAM";
|
|
#endif
|
|
#ifdef EREMOTEIO
|
|
case EREMOTEIO:
|
|
return "EREMOTEIO";
|
|
#endif
|
|
case EDQUOT:
|
|
return "EDQUOT";
|
|
#ifdef ENOMEDIUM
|
|
case ENOMEDIUM:
|
|
return "ENOMEDIUM";
|
|
#endif
|
|
#ifdef EMEDIUMTYPE
|
|
case EMEDIUMTYPE:
|
|
return "EMEDIUMTYPE";
|
|
#endif
|
|
case ECANCELED:
|
|
return "ECANCELED";
|
|
#ifdef ENOKEY
|
|
case ENOKEY:
|
|
return "ENOKEY";
|
|
#endif
|
|
#ifdef EKEYEXPIRED
|
|
case EKEYEXPIRED:
|
|
return "EKEYEXPIRED";
|
|
#endif
|
|
#ifdef EKEYREVOKED
|
|
case EKEYREVOKED:
|
|
return "EKEYREVOKED";
|
|
#endif
|
|
#ifdef EKEYREJECTED
|
|
case EKEYREJECTED:
|
|
return "EKEYREJECTED";
|
|
#endif
|
|
#ifdef EOWNERDEAD
|
|
case EOWNERDEAD:
|
|
return "EOWNERDEAD";
|
|
#endif
|
|
#ifdef ENOTRECOVERABLE
|
|
case ENOTRECOVERABLE:
|
|
return "ENOTRECOVERABLE";
|
|
#endif
|
|
#ifdef ERFKILL
|
|
case ERFKILL:
|
|
return "ERFKILL";
|
|
#endif
|
|
#ifdef EHWPOISON
|
|
case EHWPOISON:
|
|
return "EHWPOISON";
|
|
#endif
|
|
#ifdef EPROCLIM
|
|
case EPROCLIM:
|
|
return "EPROCLIM";
|
|
#endif
|
|
#ifdef EBADRPC
|
|
case EBADRPC:
|
|
return "EBADRPC";
|
|
#endif
|
|
#ifdef ERPCMISMATCH
|
|
case ERPCMISMATCH:
|
|
return "ERPCMISMATCH";
|
|
#endif
|
|
#ifdef EPROGUNAVAIL
|
|
case EPROGUNAVAIL:
|
|
return "EPROGUNAVAIL";
|
|
#endif
|
|
#ifdef EPROGMISMATCH
|
|
case EPROGMISMATCH:
|
|
return "EPROGMISMATCH";
|
|
#endif
|
|
#ifdef EPROCUNAVAIL
|
|
case EPROCUNAVAIL:
|
|
return "EPROCUNAVAIL";
|
|
#endif
|
|
#ifdef EFTYPE
|
|
case EFTYPE:
|
|
return "EFTYPE";
|
|
#endif
|
|
#ifdef EAUTH
|
|
case EAUTH:
|
|
return "EAUTH";
|
|
#endif
|
|
#ifdef ENEEDAUTH
|
|
case ENEEDAUTH:
|
|
return "ENEEDAUTH";
|
|
#endif
|
|
#ifdef EPWROFF
|
|
case EPWROFF:
|
|
return "EPWROFF";
|
|
#endif
|
|
#ifdef EDEVERR
|
|
case EDEVERR:
|
|
return "EDEVERR";
|
|
#endif
|
|
#ifdef EBADEXEC
|
|
case EBADEXEC:
|
|
return "EBADEXEC";
|
|
#endif
|
|
#ifdef EBADARCH
|
|
case EBADARCH:
|
|
return "EBADARCH";
|
|
#endif
|
|
#ifdef ESHLIBVERS
|
|
case ESHLIBVERS:
|
|
return "ESHLIBVERS";
|
|
#endif
|
|
#ifdef EBADMACHO
|
|
case EBADMACHO:
|
|
return "EBADMACHO";
|
|
#endif
|
|
#ifdef ENOATTR
|
|
case ENOATTR:
|
|
return "ENOATTR";
|
|
#endif
|
|
#ifdef EQFULL
|
|
case EQFULL:
|
|
return "EQFULL";
|
|
#endif
|
|
default:
|
|
char* str = strerror(nErrno);
|
|
return std::to_string(nErrno) + " (" + std::string(str) + ")";
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|