summaryrefslogtreecommitdiff
path: root/src/io/FileDescriptor.hxx
blob: 186c5870cc706e4422efe80f6a80ce99336cec3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
 * Copyright 2012-2019 Max Kellermann <max.kellermann@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef FILE_DESCRIPTOR_HXX
#define FILE_DESCRIPTOR_HXX

#include "util/Compiler.h"

#include <utility>

#include <unistd.h>
#include <sys/types.h>

#ifdef __linux__
#include <csignal>
#endif

#ifdef _WIN32
#include <wchar.h>
#endif

/**
 * An OO wrapper for a UNIX file descriptor.
 *
 * This class is unmanaged and trivial; for a managed version, see
 * #UniqueFileDescriptor.
 */
class FileDescriptor {
protected:
	int fd;

public:
	FileDescriptor() = default;
	explicit constexpr FileDescriptor(int _fd) noexcept:fd(_fd) {}

	constexpr bool operator==(FileDescriptor other) const noexcept {
		return fd == other.fd;
	}

	constexpr bool operator!=(FileDescriptor other) const noexcept {
		return !(*this == other);
	}

	constexpr bool IsDefined() const noexcept {
		return fd >= 0;
	}

#ifndef _WIN32
	/**
	 * Ask the kernel whether this is a valid file descriptor.
	 */
	gcc_pure
	bool IsValid() const noexcept;

	/**
	 * Ask the kernel whether this is a regular file.
	 */
	gcc_pure
	bool IsRegularFile() const noexcept;

	/**
	 * Ask the kernel whether this is a pipe.
	 */
	gcc_pure
	bool IsPipe() const noexcept;

	/**
	 * Ask the kernel whether this is a socket descriptor.
	 */
	gcc_pure
	bool IsSocket() const noexcept;
#endif

	/**
	 * Returns the file descriptor.  This may only be called if
	 * IsDefined() returns true.
	 */
	constexpr int Get() const noexcept {
		return fd;
	}

	void Set(int _fd) noexcept {
		fd = _fd;
	}

	int Steal() noexcept {
		return std::exchange(fd, -1);
	}

	void SetUndefined() noexcept {
		fd = -1;
	}

	static constexpr FileDescriptor Undefined() noexcept {
		return FileDescriptor(-1);
	}

#ifdef __linux__
	bool Open(FileDescriptor dir, const char *pathname,
		  int flags, mode_t mode=0666) noexcept;
#endif

	bool Open(const char *pathname, int flags, mode_t mode=0666) noexcept;

#ifdef _WIN32
	bool Open(const wchar_t *pathname, int flags, mode_t mode=0666) noexcept;
#endif

	bool OpenReadOnly(const char *pathname) noexcept;

#ifndef _WIN32
	bool OpenNonBlocking(const char *pathname) noexcept;
#endif

#ifdef __linux__
	static bool CreatePipe(FileDescriptor &r, FileDescriptor &w,
			       int flags) noexcept;
#endif

	static bool CreatePipe(FileDescriptor &r, FileDescriptor &w) noexcept;

#ifdef _WIN32
	void EnableCloseOnExec() noexcept {}
	void DisableCloseOnExec() noexcept {}
#else
	static bool CreatePipeNonBlock(FileDescriptor &r,
				       FileDescriptor &w) noexcept;

	/**
	 * Enable non-blocking mode on this file descriptor.
	 */
	void SetNonBlocking() noexcept;

	/**
	 * Enable blocking mode on this file descriptor.
	 */
	void SetBlocking() noexcept;

	/**
	 * Auto-close this file descriptor when a new program is
	 * executed.
	 */
	void EnableCloseOnExec() noexcept;

	/**
	 * Do not auto-close this file descriptor when a new program
	 * is executed.
	 */
	void DisableCloseOnExec() noexcept;

	/**
	 * Duplicate the file descriptor onto the given file descriptor.
	 */
	bool Duplicate(FileDescriptor new_fd) const noexcept {
		return ::dup2(Get(), new_fd.Get()) == 0;
	}

	/**
	 * Similar to Duplicate(), but if destination and source file
	 * descriptor are equal, clear the close-on-exec flag.  Use
	 * this method to inject file descriptors into a new child
	 * process, to be used by a newly executed program.
	 */
	bool CheckDuplicate(FileDescriptor new_fd) noexcept;
#endif

#ifdef __linux__
	bool CreateEventFD(unsigned initval=0) noexcept;
	bool CreateSignalFD(const sigset_t *mask) noexcept;
	bool CreateInotify() noexcept;
#endif

	/**
	 * Close the file descriptor.  It should not be called on an
	 * "undefined" object.  After this call, IsDefined() is guaranteed
	 * to return false, and this object may be reused.
	 */
	bool Close() noexcept {
		return ::close(Steal()) == 0;
	}

	/**
	 * Rewind the pointer to the beginning of the file.
	 */
	bool Rewind() noexcept;

	off_t Seek(off_t offset) noexcept {
		return lseek(Get(), offset, SEEK_SET);
	}

	off_t Skip(off_t offset) noexcept {
		return lseek(Get(), offset, SEEK_CUR);
	}

	gcc_pure
	off_t Tell() const noexcept {
		return lseek(Get(), 0, SEEK_CUR);
	}

	/**
	 * Returns the size of the file in bytes, or -1 on error.
	 */
	gcc_pure
	off_t GetSize() const noexcept;

	ssize_t Read(void *buffer, size_t length) noexcept {
		return ::read(fd, buffer, length);
	}

	/**
	 * Read until all of the given buffer has been filled.  Throws
	 * on error.
	 */
	void FullRead(void *buffer, size_t length);

	ssize_t Write(const void *buffer, size_t length) noexcept {
		return ::write(fd, buffer, length);
	}

	/**
	 * Write until all of the given buffer has been written.
	 * Throws on error.
	 */
	void FullWrite(const void *buffer, size_t length);

#ifndef _WIN32
	int Poll(short events, int timeout) const noexcept;

	int WaitReadable(int timeout) const noexcept;
	int WaitWritable(int timeout) const noexcept;

	gcc_pure
	bool IsReadyForWriting() const noexcept;
#endif
};

#endif