Support using fcntl to mark pipes as non-blocking
[folly.git] / folly / portability / Fcntl.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/portability/Fcntl.h>
18
19 #ifdef _WIN32
20 #include <folly/portability/Sockets.h>
21 #include <folly/portability/SysStat.h>
22 #include <folly/portability/Windows.h>
23
24 namespace folly {
25 namespace portability {
26 namespace fcntl {
27 int creat(char const* fn, int pm) { return _creat(fn, pm); }
28
29 int fcntl(int fd, int cmd, ...) {
30   va_list args;
31   int res = -1;
32   va_start(args, cmd);
33   switch (cmd) {
34     case F_GETFD: {
35       HANDLE h = (HANDLE)_get_osfhandle(fd);
36       if (h != INVALID_HANDLE_VALUE) {
37         DWORD flags;
38         if (GetHandleInformation(h, &flags)) {
39           res = flags & HANDLE_FLAG_INHERIT;
40         }
41       }
42       break;
43     }
44     case F_SETFD: {
45       int flags = va_arg(args, int);
46       HANDLE h = (HANDLE)_get_osfhandle(fd);
47       if (h != INVALID_HANDLE_VALUE) {
48         if (SetHandleInformation(
49                 h, HANDLE_FLAG_INHERIT, (DWORD)(flags & FD_CLOEXEC))) {
50           res = 0;
51         }
52       }
53       break;
54     }
55     case F_GETFL: {
56       // No idea how to get the IO blocking mode, so return 0.
57       res = 0;
58       break;
59     }
60     case F_SETFL: {
61       int flags = va_arg(args, int);
62       if (flags & O_NONBLOCK) {
63         // If it's not a socket, it's probably a pipe.
64         if (folly::portability::sockets::is_fh_socket(fd)) {
65           SOCKET s = (SOCKET)_get_osfhandle(fd);
66           if (s != INVALID_SOCKET) {
67             u_long nonBlockingEnabled = 1;
68             res = ioctlsocket(s, FIONBIO, &nonBlockingEnabled);
69           }
70         } else {
71           HANDLE p = (HANDLE)_get_osfhandle(fd);
72           if (GetFileType(p) == FILE_TYPE_PIPE) {
73             DWORD newMode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
74             if (SetNamedPipeHandleState(p, &newMode, nullptr, nullptr)) {
75               res = 0;
76             }
77           }
78         }
79       }
80       break;
81     }
82   }
83   va_end(args);
84   return res;
85 }
86
87 int open(char const* fn, int of, int pm) {
88   int fh;
89   int realMode = _S_IREAD;
90   if ((of & _O_RDWR) == _O_RDWR) {
91     realMode = _S_IREAD | _S_IWRITE;
92   } else if ((of & _O_WRONLY) == _O_WRONLY) {
93     realMode = _S_IWRITE;
94   } else if ((of & _O_RDONLY) != _O_RDONLY) {
95     // One of these needs to be present, just fail if
96     // none are.
97     return -1;
98   }
99   errno_t res = _sopen_s(&fh, fn, of, _SH_DENYNO, realMode);
100   return res ? -1 : fh;
101 }
102
103 int posix_fallocate(int fd, off_t offset, off_t len) {
104   // We'll pretend we always have enough space. We
105   // can't exactly pre-allocate on windows anyways.
106   return 0;
107 }
108 }
109 }
110 }
111 #endif