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