1 /* Copyright 2014-present Facebook, Inc.
2  * Licensed under the Apache License, Version 2.0 */
3 
4 #include "watchman.h"
5 #include "make_unique.h"
6 
7 using watchman::FileDescriptor;
8 
9 // Things are more complicated here than on unix.
10 // We maintain an overlapped context for reads and
11 // another for writes.  Actual write data is queued
12 // and dispatched to the underlying handle as prior
13 // writes complete.
14 
15 struct win_handle;
16 
17 namespace {
18 class WindowsEvent : public watchman_event {
19  public:
20   HANDLE hEvent;
21 
WindowsEvent(bool initialState=false)22   explicit WindowsEvent(bool initialState = false)
23       : hEvent(CreateEvent(nullptr, TRUE, initialState, nullptr)) {}
24 
~WindowsEvent()25   ~WindowsEvent() {
26     CloseHandle(hEvent);
27   }
28 
notify()29   void notify() override {
30     SetEvent(hEvent);
31   }
32 
testAndClear()33   bool testAndClear() override {
34     bool was_set = WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0;
35     ResetEvent(hEvent);
36     return was_set;
37   }
38 
reset()39   void reset() {
40     ResetEvent(hEvent);
41   }
42 };
43 }
44 
45 struct overlapped_op {
46   OVERLAPPED olap;
47   struct win_handle *h;
48   struct write_buf *wbuf;
49 };
50 
51 struct write_buf {
52   struct write_buf *next;
53   int len;
54   char *cursor;
55   char data[1];
56 };
57 
58 class win_handle : public watchman_stream {
59  public:
60   struct overlapped_op *read_pending{nullptr}, *write_pending{nullptr};
61   FileDescriptor h;
62   WindowsEvent waitable;
63   CRITICAL_SECTION mtx;
64   bool error_pending{false};
65   DWORD errcode{0};
66   DWORD file_type;
67   struct write_buf *write_head{nullptr}, *write_tail{nullptr};
68   char read_buf[8192];
69   char* read_cursor{read_buf};
70   int read_avail{0};
71   bool blocking{true};
72 
73   explicit win_handle(FileDescriptor&& handle);
74   ~win_handle();
75   int read(void* buf, int size) override;
76   int write(const void* buf, int size) override;
77   w_evt_t getEvents() override;
78   void setNonBlock(bool nonb) override;
79   bool rewind() override;
80   bool shutdown() override;
81   bool peerIsOwner() override;
getFileDescriptor() const82   const FileDescriptor& getFileDescriptor() const override {
83     return h;
84   }
85 
86   // Helper to avoid sprinkling casts all over this file
handle() const87   inline HANDLE handle() const {
88     return (HANDLE)h.handle();
89   }
90 
getPeerProcessID() const91   pid_t getPeerProcessID() const override {
92     return 0;
93   }
94 };
95 
96 #if 1
97 #define stream_debug(x, ...) 0
98 #else
99 #define stream_debug(x, ...)                                                   \
100   do {                                                                         \
101     time_t now;                                                                \
102     char timebuf[64];                                                          \
103     struct tm tm;                                                              \
104     time(&now);                                                                \
105     localtime_s(&tm, &now);                                                    \
106     strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);              \
107     fprintf(stderr, "%s    : ", timebuf);                                      \
108     fprintf(stderr, x, __VA_ARGS__);                                           \
109     fflush(stderr);                                                            \
110   } while (0)
111 #endif
112 
113 typedef BOOL (WINAPI *get_overlapped_result_ex_func)(
114     HANDLE file,
115     LPOVERLAPPED olap,
116     LPDWORD bytes,
117     DWORD millis,
118     BOOL alertable);
119 static BOOL WINAPI probe_get_overlapped_result_ex(
120     HANDLE file,
121     LPOVERLAPPED olap,
122     LPDWORD bytes,
123     DWORD millis,
124     BOOL alertable);
125 static get_overlapped_result_ex_func get_overlapped_result_ex =
126     probe_get_overlapped_result_ex;
127 
get_overlapped_result_ex_impl(HANDLE file,LPOVERLAPPED olap,LPDWORD bytes,DWORD millis,BOOL alertable)128 static BOOL WINAPI get_overlapped_result_ex_impl(
129     HANDLE file,
130     LPOVERLAPPED olap,
131     LPDWORD bytes,
132     DWORD millis,
133     BOOL alertable) {
134 
135   DWORD waitReturnCode, err;
136 
137   stream_debug( "Preparing to wait for maximum %ums\n", millis );
138   if ( millis != 0 ) {
139 
140     waitReturnCode = WaitForSingleObjectEx(olap->hEvent, millis, alertable);
141     switch (waitReturnCode)
142     {
143     case WAIT_OBJECT_0:
144       // Event is signaled, overlapped IO operation result should be available.
145       break;
146     case WAIT_IO_COMPLETION:
147       // WaitForSingleObjectEx returnes because the system added an I/O
148       // completion routine or an asynchronous procedure call (APC) to the
149       // thread queue.
150       SetLastError(WAIT_IO_COMPLETION);
151       break;
152     case WAIT_TIMEOUT:
153       // We reached the maximum allowed wait time, the IO operation failed
154       // to complete in timely fashion.
155       SetLastError(WAIT_TIMEOUT);
156       return FALSE;
157 
158     case WAIT_FAILED:
159       // something went wrong calling WaitForSingleObjectEx
160       err = GetLastError();
161       stream_debug("WaitForSingleObjectEx failed: %s\n", win32_strerror(err));
162       return FALSE;
163 
164     default:
165       // unexpected situation deserving investigation.
166       err = GetLastError();
167       stream_debug("Unexpected error: %s\n", win32_strerror(err));
168       return FALSE;
169     }
170   }
171 
172   return GetOverlappedResult(file, olap, bytes, FALSE);
173 }
174 
175 
probe_get_overlapped_result_ex(HANDLE file,LPOVERLAPPED olap,LPDWORD bytes,DWORD millis,BOOL alertable)176 static BOOL WINAPI probe_get_overlapped_result_ex(
177     HANDLE file,
178     LPOVERLAPPED olap,
179     LPDWORD bytes,
180     DWORD millis,
181     BOOL alertable ) {
182   get_overlapped_result_ex_func func;
183 
184   func = (get_overlapped_result_ex_func)GetProcAddress(
185       GetModuleHandle("kernel32.dll"),
186       "GetOverlappedResultEx");
187 
188   if ((getenv("WATCHMAN_WIN7_COMPAT") &&
189        getenv("WATCHMAN_WIN7_COMPAT")[0] == '1') || !func) {
190     func = get_overlapped_result_ex_impl;
191   }
192 
193   get_overlapped_result_ex = func;
194 
195   return func(file, olap, bytes, millis, alertable);
196 }
197 
~win_handle()198 win_handle::~win_handle() {
199   EnterCriticalSection(&mtx);
200 
201   if (read_pending) {
202     if (CancelIoEx(handle(), &read_pending->olap)) {
203       free(read_pending);
204       read_pending = nullptr;
205     }
206   }
207   if (write_pending) {
208     if (CancelIoEx(handle(), &write_pending->olap)) {
209       free(write_pending);
210       write_pending = nullptr;
211     }
212 
213     while (write_head) {
214       struct write_buf* b = write_head;
215       write_head = b->next;
216 
217       free(b);
218     }
219   }
220 
221   DeleteCriticalSection(&mtx);
222 }
223 
move_from_read_buffer(struct win_handle * h,int * total_read_ptr,char ** target_buf_ptr,int * size_ptr)224 static void move_from_read_buffer(struct win_handle *h,
225     int *total_read_ptr,
226     char **target_buf_ptr,
227     int *size_ptr) {
228   int nread = std::min(*size_ptr, h->read_avail);
229   size_t wasted;
230 
231   if (!nread) {
232     return;
233   }
234 
235   memcpy(*target_buf_ptr, h->read_cursor, nread);
236   *total_read_ptr += nread;
237   *target_buf_ptr += nread;
238   *size_ptr -= nread;
239   h->read_cursor += nread;
240   h->read_avail -= nread;
241 
242   stream_debug("moved %d bytes from buffer\n", nread);
243 
244   // Pack the buffer to free up space at the rear for reads
245   wasted = h->read_cursor - h->read_buf;
246   if (wasted) {
247     memmove(h->read_buf, h->read_cursor, h->read_avail);
248     h->read_cursor = h->read_buf;
249   }
250 }
251 
win_read_handle_completion(struct win_handle * h)252 static bool win_read_handle_completion(struct win_handle *h) {
253   BOOL olap_res;
254   DWORD bytes, err;
255 
256 again:
257 
258   EnterCriticalSection(&h->mtx);
259   if (!h->read_pending) {
260     LeaveCriticalSection(&h->mtx);
261     return false;
262   }
263 
264   stream_debug("have read_pending, checking status\n");
265   h->waitable.reset();
266 
267   // Don't hold the mutex while we're blocked
268   LeaveCriticalSection(&h->mtx);
269   olap_res = get_overlapped_result_ex(
270       h->handle(),
271       &h->read_pending->olap,
272       &bytes,
273       h->blocking ? INFINITE : 0,
274       true);
275   err = GetLastError();
276   EnterCriticalSection(&h->mtx);
277 
278   if (olap_res) {
279     stream_debug("pending read completed, read %d bytes, %s\n",
280         (int)bytes, win32_strerror(err));
281     h->read_avail += bytes;
282     free(h->read_pending);
283     h->read_pending = nullptr;
284   } else {
285     if (err == WAIT_IO_COMPLETION) {
286       // Some other async thing completed and our wait was interrupted.
287       // This is similar to EINTR
288       LeaveCriticalSection(&h->mtx);
289       goto again;
290     }
291     stream_debug("pending read failed: %s\n", win32_strerror(err));
292     if (err != ERROR_IO_INCOMPLETE) {
293       // Failed
294       free(h->read_pending);
295       h->read_pending = nullptr;
296 
297       h->errcode = err;
298       h->error_pending = true;
299       stream_debug("marking read as failed\n");
300       h->waitable.notify();
301     }
302   }
303   LeaveCriticalSection(&h->mtx);
304 
305   return h->read_pending != nullptr;
306 }
307 
win_read_blocking(struct win_handle * h,void * buf,int size)308 static int win_read_blocking(struct win_handle* h, void* buf, int size) {
309   int total_read = 0;
310   DWORD bytes, err;
311 
312   move_from_read_buffer(h, &total_read, (char**)&buf, &size);
313 
314   if (size == 0) {
315     return total_read;
316   }
317 
318   stream_debug("blocking read of %d bytes\n", (int)size);
319   if (ReadFile(h->handle(), buf, size, &bytes, nullptr)) {
320     total_read += bytes;
321     stream_debug("blocking read provided %d bytes, total=%d\n",
322         (int)bytes, total_read);
323     return total_read;
324   }
325 
326   err = GetLastError();
327 
328   stream_debug("blocking read failed: %s\n", win32_strerror(err));
329 
330   if (total_read) {
331     stream_debug("but already got %d bytes from buffer\n", total_read);
332     return total_read;
333   }
334 
335   errno = map_win32_err(err);
336   return -1;
337 }
338 
win_read_non_blocking(struct win_handle * h,void * buf,int size)339 static int win_read_non_blocking(struct win_handle* h, void* buf, int size) {
340   int total_read = 0;
341   char *target;
342   DWORD target_space;
343   DWORD bytes;
344 
345   stream_debug("non_blocking read for %d bytes\n", size);
346 
347   move_from_read_buffer(h, &total_read, (char**)&buf, &size);
348 
349   target = h->read_cursor + h->read_avail;
350   target_space = (DWORD)((h->read_buf + sizeof(h->read_buf)) - target);
351 
352   stream_debug("initiate read for %d\n", target_space);
353 
354   // Create a unique olap for each request
355   h->read_pending = (overlapped_op*)calloc(1, sizeof(*h->read_pending));
356   if (h->read_avail == 0) {
357     stream_debug("ResetEvent because there is no read_avail right now\n");
358     h->waitable.reset();
359   }
360   h->read_pending->olap.hEvent = h->waitable.hEvent;
361   h->read_pending->h = h;
362 
363   if (!ReadFile(
364           h->handle(), target, target_space, nullptr, &h->read_pending->olap)) {
365     DWORD err = GetLastError();
366 
367     if (err != ERROR_IO_PENDING) {
368       free(h->read_pending);
369       h->read_pending = nullptr;
370 
371       stream_debug("olap read failed immediately: %s\n",
372           win32_strerror(err));
373       h->waitable.notify();
374     } else {
375       stream_debug("olap read queued ok\n");
376     }
377 
378     errno = map_win32_err(err);
379     return total_read == 0 ? -1 : total_read;
380   }
381 
382   // Note: we obtain the bytes via GetOverlappedResult because the docs for
383   // ReadFile warn against passing the pointer to the ReadFile parameter for
384   // asynchronouse reads
385   GetOverlappedResult(h->handle(), &h->read_pending->olap, &bytes, FALSE);
386   stream_debug("olap read succeeded immediately bytes=%d\n", (int)bytes);
387 
388   h->read_avail += bytes;
389   free(h->read_pending);
390   h->read_pending = nullptr;
391 
392   move_from_read_buffer(h, &total_read, (char**)&buf, &size);
393 
394   stream_debug("read returning %d\n", total_read);
395   h->waitable.notify();
396   return total_read;
397 }
398 
read(void * buf,int size)399 int win_handle::read(void* buf, int size) {
400   if (win_read_handle_completion(this)) {
401     errno = EAGAIN;
402     return -1;
403   }
404 
405   // Report a prior failure
406   if (error_pending) {
407     stream_debug(
408         "win_read: reporting prior failure err=%d errno=%d %s\n",
409         errcode,
410         map_win32_err(errcode),
411         win32_strerror(errcode));
412     errno = map_win32_err(errcode);
413     error_pending = false;
414     return -1;
415   }
416 
417   if (blocking) {
418     return win_read_blocking(this, buf, size);
419   }
420 
421   return win_read_non_blocking(this, buf, size);
422 }
423 
424 static void initiate_write(struct win_handle *h);
425 
write_completed(DWORD err,DWORD bytes,LPOVERLAPPED olap)426 static void CALLBACK write_completed(DWORD err, DWORD bytes,
427     LPOVERLAPPED olap) {
428   // Reverse engineer our handle from the olap pointer
429   struct overlapped_op *op = (overlapped_op*)olap;
430   struct win_handle *h = op->h;
431   struct write_buf *wbuf = op->wbuf;
432 
433   stream_debug("WriteFileEx: completion callback invoked: bytes=%d %s\n",
434       (int)bytes, win32_strerror(err));
435 
436   EnterCriticalSection(&h->mtx);
437   if (h->write_pending == op) {
438     h->write_pending = nullptr;
439   }
440 
441   if (err == 0) {
442     wbuf->cursor += bytes;
443     wbuf->len -= bytes;
444 
445     if (wbuf->len == 0) {
446       // Consumed this buffer
447       free(wbuf);
448     } else {
449       stream_debug("WriteFileEx: short write: %d written, %d remain\n",
450               bytes, wbuf->len);
451       // the initiate_write call will send the remainder
452       // but we need to re-insert this wbuf in the write queue
453       wbuf->next = h->write_head;
454       h->write_head = wbuf;
455       if (!h->write_tail) {
456         h->write_tail = wbuf;
457       }
458     }
459   } else {
460     stream_debug("WriteFilex: completion: failed: %s\n",
461         win32_strerror(err));
462     h->errcode = err;
463     h->error_pending = true;
464   }
465 
466   stream_debug("SetEvent because WriteFileEx completed\n");
467   h->waitable.notify();
468 
469   // Send whatever else we have waiting to go
470   initiate_write(h);
471 
472   LeaveCriticalSection(&h->mtx);
473 
474   // Free the prior struct after possibly initiating another write
475   // to minimize the chance of the same address being reused and
476   // confusing the completion status
477   free(op);
478 }
479 
480 // Must be called with the mutex held
initiate_write(struct win_handle * h)481 static void initiate_write(struct win_handle *h) {
482   struct write_buf *wbuf = h->write_head;
483   if (h->write_pending || !wbuf) {
484     return;
485   }
486 
487   h->write_head = wbuf->next;
488   if (!h->write_head) {
489     h->write_tail = nullptr;
490   }
491 
492   h->write_pending = (overlapped_op*)calloc(1, sizeof(*h->write_pending));
493   h->write_pending->h = h;
494   h->write_pending->wbuf = wbuf;
495 
496   stream_debug(
497       "Calling WriteFileEx with wbuf=%p wbuf->cursor=%p len=%d olap=%p\n", wbuf,
498       wbuf->cursor, wbuf->len, &h->write_pending->olap);
499   if (!WriteFileEx(
500           h->handle(),
501           wbuf->cursor,
502           wbuf->len,
503           &h->write_pending->olap,
504           write_completed)) {
505     stream_debug("WriteFileEx: failed %s\n",
506         win32_strerror(GetLastError()));
507     free(h->write_pending);
508     h->write_pending = nullptr;
509   } else {
510     stream_debug("WriteFileEx: queued %d bytes for later\n", wbuf->len);
511   }
512 }
513 
write(const void * buf,int size)514 int win_handle::write(const void* buf, int size) {
515   struct write_buf *wbuf;
516 
517   EnterCriticalSection(&mtx);
518   if (file_type != FILE_TYPE_PIPE && blocking && !write_head) {
519     DWORD bytes;
520     stream_debug("blocking write of %d\n", size);
521     if (WriteFile(handle(), buf, size, &bytes, nullptr)) {
522       LeaveCriticalSection(&mtx);
523       stream_debug("blocking write wrote %d bytes of %d\n", bytes, size);
524       return bytes;
525     }
526     errcode = GetLastError();
527     error_pending = true;
528     errno = map_win32_err(errcode);
529     stream_debug("SetEvent because blocking write completed (failed)\n");
530     waitable.notify();
531     stream_debug("write failed: %s\n", win32_strerror(errcode));
532     LeaveCriticalSection(&mtx);
533     return -1;
534   }
535 
536   wbuf = (write_buf*)malloc(sizeof(*wbuf) + size - 1);
537   if (!wbuf) {
538     return -1;
539   }
540   wbuf->next = nullptr;
541   wbuf->cursor = wbuf->data;
542   wbuf->len = size;
543   memcpy(wbuf->data, buf, size);
544 
545   if (write_tail) {
546     write_tail->next = wbuf;
547   } else {
548     write_head = wbuf;
549   }
550   write_tail = wbuf;
551 
552   stream_debug("queue write of %d bytes to write_tail\n", size);
553 
554   if (!write_pending) {
555     initiate_write(this);
556   }
557 
558   LeaveCriticalSection(&mtx);
559 
560   return size;
561 }
562 
getEvents()563 w_evt_t win_handle::getEvents() {
564   return &waitable;
565 }
566 
setNonBlock(bool nonb)567 void win_handle::setNonBlock(bool nonb) {
568   blocking = !nonb;
569 }
570 
rewind()571 bool win_handle::rewind() {
572   bool res;
573   LARGE_INTEGER new_pos;
574 
575   new_pos.QuadPart = 0;
576   res = SetFilePointerEx(handle(), new_pos, &new_pos, FILE_BEGIN);
577   errno = map_win32_err(GetLastError());
578   return res;
579 }
580 
581 // Ensure that any data buffered for write are sent prior to setting
582 // ourselves up to close
shutdown()583 bool win_handle::shutdown() {
584   BOOL olap_res;
585   DWORD bytes;
586 
587   blocking = true;
588   while (write_pending) {
589     olap_res = get_overlapped_result_ex(
590         handle(), &write_pending->olap, &bytes, INFINITE, true);
591   }
592 
593   return true;
594 }
595 
peerIsOwner()596 bool win_handle::peerIsOwner() {
597   // TODO: implement this for Windows
598   return true;
599 }
600 
w_event_make(void)601 std::unique_ptr<watchman_event> w_event_make(void) {
602   return watchman::make_unique<WindowsEvent>();
603 }
604 
win_handle(FileDescriptor && handle)605 win_handle::win_handle(FileDescriptor&& handle)
606     : h(std::move(handle)),
607       // Initially signalled, meaning that they can try reading
608       waitable(true),
609       file_type(GetFileType((HANDLE)h.handle())) {
610   InitializeCriticalSection(&mtx);
611 }
612 
w_stm_fdopen(FileDescriptor && handle)613 std::unique_ptr<watchman_stream> w_stm_fdopen(FileDescriptor&& handle) {
614   if (!handle) {
615     return nullptr;
616   }
617 
618   return watchman::make_unique<win_handle>(std::move(handle));
619 }
620 
w_stm_connect_named_pipe(const char * path,int timeoutms)621 std::unique_ptr<watchman_stream> w_stm_connect_named_pipe(
622     const char* path,
623     int timeoutms) {
624   DWORD err;
625   DWORD64 deadline = GetTickCount64() + timeoutms;
626 
627   if (strlen(path) > 255) {
628     w_log(W_LOG_ERR, "w_stm_connect_named_pipe(%s) path is too long\n", path);
629     errno = E2BIG;
630     return nullptr;
631   }
632 
633   while (true) {
634     FileDescriptor handle(intptr_t(CreateFile(
635         path,
636         GENERIC_READ | GENERIC_WRITE,
637         0,
638         nullptr,
639         OPEN_EXISTING,
640         FILE_FLAG_OVERLAPPED,
641         nullptr)));
642 
643     if (handle) {
644       return w_stm_fdopen(std::move(handle));
645     }
646 
647     err = GetLastError();
648     if (timeoutms > 0) {
649       timeoutms -= (DWORD)(GetTickCount64() - deadline);
650     }
651     if (timeoutms <= 0 ||
652         (err != ERROR_PIPE_BUSY && err != ERROR_FILE_NOT_FOUND)) {
653       // either we're out of time, or retrying won't help with this error
654       errno = map_win32_err(err);
655       return nullptr;
656     }
657 
658     // We can retry
659     if (!WaitNamedPipe(path, timeoutms)) {
660       err = GetLastError();
661       if (err == ERROR_SEM_TIMEOUT) {
662         errno = map_win32_err(err);
663         return nullptr;
664       }
665       if (err == ERROR_FILE_NOT_FOUND) {
666         // Grace to allow it to be created
667         SleepEx(10, true);
668       }
669     }
670   }
671 }
672 
w_poll_events(struct watchman_event_poll * p,int n,int timeoutms)673 int w_poll_events(struct watchman_event_poll *p, int n, int timeoutms) {
674   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
675   int i;
676   DWORD res;
677 
678   if (n > MAXIMUM_WAIT_OBJECTS - 1) {
679     // Programmer error :-/
680     w_log(W_LOG_FATAL, "%d > MAXIMUM_WAIT_OBJECTS-1 (%d)\n", n,
681         MAXIMUM_WAIT_OBJECTS - 1);
682   }
683 
684   for (i = 0; i < n; i++) {
685     auto evt = dynamic_cast<WindowsEvent*>(p[i].evt);
686     w_check(evt != nullptr, "!WindowsEvent");
687     handles[i] = evt->hEvent;
688     p[i].ready = false;
689   }
690 
691   res = WaitForMultipleObjectsEx(n, handles, false,
692           timeoutms == -1 ? INFINITE : timeoutms, true);
693 
694   if (res == WAIT_FAILED) {
695     errno = map_win32_err(GetLastError());
696     return -1;
697   }
698   if (res == WAIT_IO_COMPLETION) {
699     errno = EINTR;
700     return -1;
701   }
702   // Note: WAIT_OBJECT_0 == 0
703   if (/* res >= WAIT_OBJECT_0 && */ res < WAIT_OBJECT_0 + n) {
704     p[res - WAIT_OBJECT_0].ready = true;
705     return 1;
706   }
707   if (res >= WAIT_ABANDONED_0 && res < WAIT_ABANDONED_0 + n) {
708     p[res - WAIT_ABANDONED_0].ready = true;
709     return 1;
710   }
711   return 0;
712 }
713 
714 // similar to open(2), but returns a handle
w_handle_open(const char * path,int flags)715 FileDescriptor w_handle_open(const char* path, int flags) {
716   DWORD access = 0, share = 0, create = 0, attrs = 0;
717   DWORD err;
718   SECURITY_ATTRIBUTES sec;
719 
720   if (!strcmp(path, "/dev/null")) {
721     path = "NUL:";
722   }
723 
724   auto wpath = w_string_piece(path).asWideUNC();
725 
726   if (flags & (O_WRONLY|O_RDWR)) {
727     access |= GENERIC_WRITE;
728   }
729   if ((flags & O_WRONLY) == 0) {
730     access |= GENERIC_READ;
731   }
732 
733   // We want more posix-y behavior by default
734   share = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
735 
736   memset(&sec, 0, sizeof(sec));
737   sec.nLength = sizeof(sec);
738   sec.bInheritHandle = TRUE;
739   if (flags & O_CLOEXEC) {
740     sec.bInheritHandle = FALSE;
741   }
742 
743   if ((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) {
744     create = CREATE_NEW;
745   } else if ((flags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC)) {
746     create = CREATE_ALWAYS;
747   } else if (flags & O_CREAT) {
748     create = OPEN_ALWAYS;
749   } else if (flags & O_TRUNC) {
750     create = TRUNCATE_EXISTING;
751   } else {
752     create = OPEN_EXISTING;
753   }
754 
755   attrs = FILE_ATTRIBUTE_NORMAL;
756   if (flags & O_DIRECTORY) {
757     attrs |= FILE_FLAG_BACKUP_SEMANTICS;
758   }
759 
760   FileDescriptor h(intptr_t(
761       CreateFileW(wpath.c_str(), access, share, &sec, create, attrs, nullptr)));
762   err = GetLastError();
763 
764   errno = map_win32_err(err);
765   return h;
766 }
767 
w_stm_open(const char * path,int flags,...)768 std::unique_ptr<watchman_stream> w_stm_open(const char* path, int flags, ...) {
769   return w_stm_fdopen(w_handle_open(path, flags));
770 }
771