1 /* Copyright 2012-present Facebook, Inc.
2  * Licensed under the Apache License, Version 2.0 */
3 #pragma once
4 #include "watchman_system.h"
5 #include <system_error>
6 #include "Result.h"
7 
8 class w_string;
9 
10 namespace watchman {
11 
12 struct FileInformation;
13 
14 // Manages the lifetime of a system independent file descriptor.
15 // On POSIX systems this is a posix file descriptor.
16 // On Win32 systems this is a Win32 HANDLE object.
17 // It will close() the descriptor when it is destroyed.
18 class FileDescriptor {
19  public:
20   using system_handle_type =
21 #ifdef _WIN32
22       // We track the HANDLE value as intptr_t to avoid needing
23       // to pull in the windows header files all over the place;
24       // this is consistent with the _get_osfhandle function in
25       // the msvcrt library.
26       intptr_t
27 #else
28       int
29 #endif
30       ;
31 
32   // A value representing the canonical invalid handle
33   // value for the system.
34   static constexpr system_handle_type kInvalid = -1;
35 
36   // Normalizes invalid handle values to our canonical invalid handle value.
37   // Otherwise, just returns the handle as-is.
38   static system_handle_type normalizeHandleValue(system_handle_type h);
39 
40   ~FileDescriptor();
41 
42   // Default construct to an empty instance
43   FileDescriptor() = default;
44 
45   // Construct a file descriptor object from an fd.
46   // Will happily accept an invalid handle value without
47   // raising an error; the FileDescriptor will simply evaluate as
48   // false in a boolean context.
49   explicit FileDescriptor(system_handle_type fd);
50 
51   // Construct a file descriptor object from an fd.
52   // If fd is invalid will throw a generic error with a message
53   // constructed from the provided operation name and the current
54   // errno value.
55   FileDescriptor(system_handle_type fd, const char* operation);
56 
57   // No copying
58   FileDescriptor(const FileDescriptor&) = delete;
59   FileDescriptor& operator=(const FileDescriptor&) = delete;
60 
61   FileDescriptor(FileDescriptor&& other) noexcept;
62   FileDescriptor& operator=(FileDescriptor&& other) noexcept;
63 
64   // Closes the associated descriptor
65   void close();
66 
67   // Stops tracking the descriptor, returning it to the caller.
68   // The caller is then responsible for closing it.
69   system_handle_type release();
70 
71   // In a boolean context, returns true if this object owns
72   // a valid descriptor.
73   explicit operator bool() const {
74     return fd_ != kInvalid;
75   }
76 
77   // Returns the underlying descriptor value
system_handle()78   inline system_handle_type system_handle() const {
79     return fd_;
80   }
81 
82 #ifndef _WIN32
83   // Returns the descriptor value as a file descriptor.
84   // This method is only present on posix systems to aid in
85   // detecting non-portable use at compile time.
fd()86   inline int fd() const {
87     return fd_;
88   }
89 #else
90   // Returns the descriptor value as a file handle.
91   // This method is only present on win32 systems to aid in
92   // detecting non-portable use at compile time.
handle()93   inline intptr_t handle() const {
94     return fd_;
95   }
96 #endif
97 
98   // Set the close-on-exec bit
99   void setCloExec();
100 
101   // Enable non-blocking IO
102   void setNonBlock();
103 
104   // Disable non-blocking IO
105   void clearNonBlock();
106 
107   // Returns true if the FD is in non-blocking mode
108   bool isNonBlock() const;
109 
110   /** equivalent to fstat(2) */
111   FileInformation getInfo() const;
112 
113   /** Returns the filename associated with the file handle */
114   w_string getOpenedPath() const;
115 
116   /** Returns the symbolic link target */
117   w_string readSymbolicLink() const;
118 
119   /** read(2), but yielding a Result for system independent error reporting */
120   Result<int, std::error_code> read(void* buf, int size) const;
121 
122   /** write(2), but yielding a Result for system independent error reporting */
123   Result<int, std::error_code> write(const void* buf, int size) const;
124 
125   // Return a global handle to one of the standard IO stream descriptors
126   static const FileDescriptor& stdIn();
127   static const FileDescriptor& stdOut();
128   static const FileDescriptor& stdErr();
129 
130  private:
131   system_handle_type fd_{kInvalid};
132 };
133 }
134