Include <strings.h> in portability/String.h
[folly.git] / folly / portability / Unistd.cpp
index 27fc7c7723b4b58b65d2cac09668b62ba5dc5b79..a587ba6aae4292ad5b10c286cf839f634fadd32c 100755 (executable)
@@ -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.
  * 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 <folly/portability/Unistd.h>
 
 #ifdef _WIN32
 #include <folly/portability/Sockets.h>
 #include <folly/portability/Windows.h>
 
+// 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 <bcrypt.h>
+#include <ntstatus.h>
+
 // Generic wrapper for the p* family of functions.
 template <class F, class... Args>
 static int wrapPositional(F f, int fd, off_t offset, Args... args) {
@@ -54,8 +64,6 @@ int access(char const* fn, int am) { return _access(fn, am); }
 
 int chdir(const char* path) { return _chdir(path); }
 
-// We aren't hooking into the internals of the CRT, nope, not at all.
-extern "C" int __cdecl _free_osfhnd(int const fh);
 int close(int fh) {
   if (folly::portability::sockets::is_fh_socket(fh)) {
     SOCKET h = (SOCKET)_get_osfhandle(fh);
@@ -66,12 +74,39 @@ int close(int fh) {
     // calling closesocket, because closesocket has already closed
     // the HANDLE, and _close would attempt to close the HANDLE
     // again, resulting in a double free.
-    // Luckily though, there is a function in the internals of the
-    // CRT that is used to free only the file descriptor, so we
-    // can call that to avoid leaking the file descriptor itself.
-    auto c = closesocket(h);
-    _free_osfhnd(fh);
-    return c;
+    // 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);
 }
@@ -92,7 +127,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;
   }
 
@@ -112,7 +147,7 @@ int getdtablesize() { return _getmaxstdio(); }
 
 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.
@@ -124,7 +159,9 @@ int isatty(int fh) { return _isatty(fh); }
 
 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); }
 
@@ -134,26 +171,26 @@ int pipe(int pth[2]) {
   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) {
+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, (size_t)mcc, 0);
+      auto r = folly::portability::sockets::recv(fh, buf, count, 0);
       if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
         errno = EAGAIN;
       }
       return r;
     }
   }
-  auto r = _read(fh, buf, mcc);
+  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
@@ -168,18 +205,20 @@ ssize_t readlink(const char* path, char* buf, size_t 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;
@@ -190,34 +229,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) {
@@ -235,7 +272,7 @@ int usleep(unsigned int ms) {
   return 0;
 }
 
-int write(int fh, void const* buf, unsigned int count) {
+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) {
@@ -246,8 +283,8 @@ int write(int fh, void const* buf, unsigned int count) {
       return r;
     }
   }
-  auto r = _write(fh, buf, count);
-  if ((r > 0 && r != count) || (r == -1 && errno == ENOSPC)) {
+  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