X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Fportability%2FUnistd.cpp;h=24652914270caa7c5d12215608c04b636c234a6a;hb=55af3d190b31e6b09943bb6456dc1085688fc007;hp=33a8f7a4ec9db165427e960c106a3e72bbcaf461;hpb=af77aab7ea371176605245b4056d0a46efbfcaba;p=folly.git diff --git a/folly/portability/Unistd.cpp b/folly/portability/Unistd.cpp old mode 100755 new mode 100644 index 33a8f7a4..24652914 --- a/folly/portability/Unistd.cpp +++ b/folly/portability/Unistd.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,27 @@ * limitations under the License. */ +// We need to prevent winnt.h from defining the core STATUS codes, +// otherwise they will conflict with what we're getting from ntstatus.h +#define UMDF_USING_NTSTATUS + #include #ifdef _WIN32 + #include + #include + #include #include +// Including ntdef.h requires building as a driver, but all we want +// is a status code, but we need NTSTATUS defined for that. Luckily +// bcrypt.h also defines NTSTATUS, so we'll use that one instead. +#include +#include + // Generic wrapper for the p* family of functions. template static int wrapPositional(F f, int fd, off_t offset, Args... args) { @@ -50,21 +63,68 @@ static int wrapPositional(F f, int fd, off_t offset, Args... args) { namespace folly { namespace portability { namespace unistd { -int access(char const* fn, int am) { return _access(fn, am); } +int access(char const* fn, int am) { + return _access(fn, am); +} -int chdir(const char* path) { return _chdir(path); } +int chdir(const char* path) { + return _chdir(path); +} int close(int fh) { if (folly::portability::sockets::is_fh_socket(fh)) { SOCKET h = (SOCKET)_get_osfhandle(fh); + + // If we were to just call _close on the descriptor, it would + // close the HANDLE, but it wouldn't free any of the resources + // associated to the SOCKET, and we can't call _close after + // calling closesocket, because closesocket has already closed + // the HANDLE, and _close would attempt to close the HANDLE + // again, resulting in a double free. + // We can however protect the HANDLE from actually being closed + // long enough to close the file descriptor, then close the + // socket itself. + constexpr DWORD protectFlag = HANDLE_FLAG_PROTECT_FROM_CLOSE; + DWORD handleFlags = 0; + if (!GetHandleInformation((HANDLE)h, &handleFlags)) { + return -1; + } + if (!SetHandleInformation((HANDLE)h, protectFlag, protectFlag)) { + return -1; + } + int c = 0; + __try { + // We expect this to fail. It still closes the file descriptor though. + c = _close(fh); + // We just have to catch the SEH exception that gets thrown when we do + // this with a debugger attached -_-.... + } __except ( + GetExceptionCode() == STATUS_HANDLE_NOT_CLOSABLE + ? EXCEPTION_CONTINUE_EXECUTION + : EXCEPTION_CONTINUE_SEARCH) { + // We told it to continue execution, so there's nothing here would + // be run anyways. + } + // We're at the core, we don't get the luxery of SCOPE_EXIT because + // of circular dependencies. + if (!SetHandleInformation((HANDLE)h, protectFlag, handleFlags)) { + return -1; + } + if (c != -1) { + return -1; + } return closesocket(h); } return _close(fh); } -int dup(int fh) { return _dup(fh); } +int dup(int fh) { + return _dup(fh); +} -int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); } +int dup2(int fhs, int fhd) { + return _dup2(fhs, fhd); +} int fsync(int fd) { HANDLE h = (HANDLE)_get_osfhandle(fd); @@ -78,7 +138,7 @@ int fsync(int fd) { } int ftruncate(int fd, off_t len) { - if (_lseek(fd, len, SEEK_SET)) { + if (_lseek(fd, len, SEEK_SET) == -1) { return -1; } @@ -92,57 +152,102 @@ int ftruncate(int fd, off_t len) { return 0; } -char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); } +char* getcwd(char* buf, int sz) { + return _getcwd(buf, sz); +} -int getdtablesize() { return _getmaxstdio(); } +int getdtablesize() { + return _getmaxstdio(); +} -int getgid() { return 1; } +int getgid() { + return 1; +} -pid_t getpid() { return pid_t(GetCurrentProcessId()); } +pid_t getpid() { + return (pid_t)uint64_t(GetCurrentProcessId()); +} // No major need to implement this, and getting a non-potentially // stale ID on windows is a bit involved. -pid_t getppid() { return (pid_t)1; } +pid_t getppid() { + return (pid_t)1; +} -int getuid() { return 1; } +int getuid() { + return 1; +} -int isatty(int fh) { return _isatty(fh); } +int isatty(int fh) { + return _isatty(fh); +} -int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); } +int lockf(int fd, int cmd, off_t len) { + return _locking(fd, cmd, len); +} -long lseek(int fh, long off, int orig) { return _lseek(fh, off, orig); } +off_t lseek(int fh, off_t off, int orig) { + return _lseek(fh, off, orig); +} -int rmdir(const char* path) { return _rmdir(path); } +int rmdir(const char* path) { + return _rmdir(path); +} -int pipe(int* pth) { return _pipe(pth, 0, _O_BINARY); } +int pipe(int pth[2]) { + // We need to be able to listen to pipes with + // libevent, so they need to be actual sockets. + return socketpair(PF_UNIX, SOCK_STREAM, 0, pth); +} -int pread(int fd, void* buf, size_t count, off_t offset) { +ssize_t pread(int fd, void* buf, size_t count, off_t offset) { return wrapPositional(_read, fd, offset, buf, (unsigned int)count); } -int pwrite(int fd, const void* buf, size_t count, off_t offset) { +ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) { return wrapPositional(_write, fd, offset, buf, (unsigned int)count); } -int read(int fh, void* buf, unsigned int mcc) { return _read(fh, buf, mcc); } +ssize_t read(int fh, void* buf, size_t count) { + if (folly::portability::sockets::is_fh_socket(fh)) { + SOCKET s = (SOCKET)_get_osfhandle(fh); + if (s != INVALID_SOCKET) { + auto r = folly::portability::sockets::recv(fh, buf, count, 0); + if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { + errno = EAGAIN; + } + return r; + } + } + auto r = _read(fh, buf, unsigned int(count)); + if (r == -1 && GetLastError() == ERROR_NO_DATA) { + // This only happens if the file was non-blocking and + // no data was present. We have to translate the error + // to a form that the rest of the world is expecting. + errno = EAGAIN; + } + return r; +} ssize_t readlink(const char* path, char* buf, size_t buflen) { if (!buflen) { return -1; } - HANDLE h = CreateFile(path, - GENERIC_READ, - FILE_SHARE_READ, - nullptr, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - nullptr); + HANDLE h = CreateFileA( + path, + GENERIC_READ, + FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + nullptr); if (h == INVALID_HANDLE_VALUE) { return -1; } - DWORD ret = GetFinalPathNameByHandleA(h, buf, buflen - 1, VOLUME_NAME_DOS); + DWORD ret = + GetFinalPathNameByHandleA(h, buf, DWORD(buflen - 1), VOLUME_NAME_DOS); if (ret >= buflen || ret >= MAX_PATH || !ret) { CloseHandle(h); return -1; @@ -153,34 +258,32 @@ ssize_t readlink(const char* path, char* buf, size_t buflen) { return ret; } -void* sbrk(intptr_t i) { return (void*)-1; } - -int setmode(int fh, int md) { return _setmode(fh, md); } +void* sbrk(intptr_t /* i */) { + return (void*)-1; +} unsigned int sleep(unsigned int seconds) { Sleep((DWORD)(seconds * 1000)); return 0; } -size_t sysconf(int tp) { +long sysconf(int tp) { switch (tp) { case _SC_PAGESIZE: { SYSTEM_INFO inf; GetSystemInfo(&inf); - return (size_t)inf.dwPageSize; + return (long)inf.dwPageSize; } case _SC_NPROCESSORS_ONLN: { SYSTEM_INFO inf; GetSystemInfo(&inf); - return (size_t)inf.dwNumberOfProcessors; + return (long)inf.dwNumberOfProcessors; } default: - return (size_t)-1; + return -1L; } } -long tell(int fh) { return _tell(fh); } - int truncate(const char* path, off_t len) { int fd = _open(path, O_WRONLY); if (!fd) { @@ -198,10 +301,39 @@ int usleep(unsigned int ms) { return 0; } -int write(int fh, void const* buf, unsigned int mcc) { - return _write(fh, buf, mcc); +ssize_t write(int fh, void const* buf, size_t count) { + if (folly::portability::sockets::is_fh_socket(fh)) { + SOCKET s = (SOCKET)_get_osfhandle(fh); + if (s != INVALID_SOCKET) { + auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0); + if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { + errno = EAGAIN; + } + return r; + } + } + auto r = _write(fh, buf, unsigned int(count)); + if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) { + // Writing to a pipe with a full buffer doesn't generate + // any error type, unless it caused us to write exactly 0 + // bytes, so we have to see if we have a pipe first. We + // don't touch the errno for anything else. + HANDLE h = (HANDLE)_get_osfhandle(fh); + if (GetFileType(h) == FILE_TYPE_PIPE) { + DWORD state = 0; + if (GetNamedPipeHandleState( + h, &state, nullptr, nullptr, nullptr, nullptr, 0)) { + if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) { + errno = EAGAIN; + return -1; + } + } + } + } + return r; } } } } + #endif