Skip to content

Commit 8afdbf0

Browse files
davidbenCQ bot account: commit-bot@chromium.org
authored and
CQ bot account: [email protected]
committed
Abstract fd operations better in tool.
Windows and POSIX implement very similar fd operations, but differ slightly: - ssize_t in POSIX is usually int on Windows. - POSIX needs EINTR retry loops. - Windows wants _open rather than open, etc. - POSIX fds and sockets are the same thing, while Windows sockets are HANDLEs and leaves fd as a C runtime construct. Rather than ad-hoc macros and redefinitions of ssize_t (which reportedly upset MINGW), add some actual abstractions. While I'm here, add a scoped file descriptor type. That still leaves recv/send which are only used in one file, so defined a socket_result_t for them. Change-Id: I17fca2a50c77191f573852bfd27553996e3e9c3f Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/41725 Commit-Queue: David Benjamin <[email protected]> Reviewed-by: Adam Langley <[email protected]>
1 parent 884614c commit 8afdbf0

File tree

6 files changed

+232
-106
lines changed

6 files changed

+232
-106
lines changed

tool/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_executable(
88
client.cc
99
const.cc
1010
digest.cc
11+
fd.cc
1112
file.cc
1213
generate_ed25519.cc
1314
genrsa.cc

tool/digest.cc

+26-50
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,13 @@ OPENSSL_MSVC_PRAGMA(warning(push, 3))
3737
OPENSSL_MSVC_PRAGMA(warning(pop))
3838
#include <io.h>
3939
#define PATH_MAX MAX_PATH
40-
typedef int ssize_t;
4140
#endif
4241

4342
#include <openssl/digest.h>
4443

4544
#include "internal.h"
4645

4746

48-
struct close_delete {
49-
void operator()(int *fd) {
50-
BORINGSSL_CLOSE(*fd);
51-
}
52-
};
53-
54-
template<typename T, typename R, R (*func) (T*)>
55-
struct func_delete {
56-
void operator()(T* obj) {
57-
func(obj);
58-
}
59-
};
60-
6147
// Source is an awkward expression of a union type in C++: Stdin | File filename.
6248
struct Source {
6349
enum Type {
@@ -79,37 +65,31 @@ struct Source {
7965

8066
static const char kStdinName[] = "standard input";
8167

82-
// OpenFile opens the regular file named |filename| and sets |*out_fd| to be a
83-
// file descriptor to it. Returns true on sucess or prints an error to stderr
84-
// and returns false on error.
85-
static bool OpenFile(int *out_fd, const std::string &filename) {
86-
*out_fd = -1;
87-
88-
int fd = BORINGSSL_OPEN(filename.c_str(), O_RDONLY | O_BINARY);
89-
if (fd < 0) {
68+
// OpenFile opens the regular file named |filename| and returns a file
69+
// descriptor to it.
70+
static ScopedFD OpenFile(const std::string &filename) {
71+
ScopedFD fd = OpenFD(filename.c_str(), O_RDONLY | O_BINARY);
72+
if (!fd) {
9073
fprintf(stderr, "Failed to open input file '%s': %s\n", filename.c_str(),
9174
strerror(errno));
92-
return false;
75+
return ScopedFD();
9376
}
94-
std::unique_ptr<int, close_delete> scoped_fd(&fd);
9577

9678
#if !defined(OPENSSL_WINDOWS)
9779
struct stat st;
98-
if (fstat(fd, &st)) {
80+
if (fstat(fd.get(), &st)) {
9981
fprintf(stderr, "Failed to stat input file '%s': %s\n", filename.c_str(),
10082
strerror(errno));
101-
return false;
83+
return ScopedFD();
10284
}
10385

10486
if (!S_ISREG(st.st_mode)) {
10587
fprintf(stderr, "%s: not a regular file\n", filename.c_str());
106-
return false;
88+
return ScopedFD();
10789
}
10890
#endif
10991

110-
*out_fd = fd;
111-
scoped_fd.release();
112-
return true;
92+
return fd;
11393
}
11494

11595
// SumFile hashes the contents of |source| with |md| and sets |*out_hex| to the
@@ -119,16 +99,17 @@ static bool OpenFile(int *out_fd, const std::string &filename) {
11999
// error.
120100
static bool SumFile(std::string *out_hex, const EVP_MD *md,
121101
const Source &source) {
122-
std::unique_ptr<int, close_delete> scoped_fd;
102+
ScopedFD scoped_fd;
123103
int fd;
124104

125105
if (source.is_stdin()) {
126106
fd = 0;
127107
} else {
128-
if (!OpenFile(&fd, source.filename())) {
108+
scoped_fd = OpenFile(source.filename());
109+
if (!scoped_fd) {
129110
return false;
130111
}
131-
scoped_fd.reset(&fd);
112+
fd = scoped_fd.get();
132113
}
133114

134115
static const size_t kBufSize = 8192;
@@ -141,21 +122,18 @@ static bool SumFile(std::string *out_hex, const EVP_MD *md,
141122
}
142123

143124
for (;;) {
144-
ssize_t n;
145-
146-
do {
147-
n = BORINGSSL_READ(fd, buf.get(), kBufSize);
148-
} while (n == -1 && errno == EINTR);
149-
150-
if (n == 0) {
151-
break;
152-
} else if (n < 0) {
125+
size_t n;
126+
if (!ReadFromFD(fd, &n, buf.get(), kBufSize)) {
153127
fprintf(stderr, "Failed to read from %s: %s\n",
154128
source.is_stdin() ? kStdinName : source.filename().c_str(),
155129
strerror(errno));
156130
return false;
157131
}
158132

133+
if (n == 0) {
134+
break;
135+
}
136+
159137
if (!EVP_DigestUpdate(ctx.get(), buf.get(), n)) {
160138
fprintf(stderr, "Failed to update hash.\n");
161139
return false;
@@ -221,25 +199,23 @@ struct CheckModeArguments {
221199
// returns false.
222200
static bool Check(const CheckModeArguments &args, const EVP_MD *md,
223201
const Source &source) {
224-
std::unique_ptr<FILE, func_delete<FILE, int, fclose>> scoped_file;
225202
FILE *file;
203+
ScopedFILE scoped_file;
226204

227205
if (source.is_stdin()) {
228206
file = stdin;
229207
} else {
230-
int fd;
231-
if (!OpenFile(&fd, source.filename())) {
208+
ScopedFD fd = OpenFile(source.filename());
209+
if (!fd) {
232210
return false;
233211
}
234212

235-
file = BORINGSSL_FDOPEN(fd, "rb");
236-
if (!file) {
213+
scoped_file = FDToFILE(std::move(fd), "rb");
214+
if (!scoped_file) {
237215
perror("fdopen");
238-
BORINGSSL_CLOSE(fd);
239216
return false;
240217
}
241-
242-
scoped_file = std::unique_ptr<FILE, func_delete<FILE, int, fclose>>(file);
218+
file = scoped_file.get();
243219
}
244220

245221
const size_t hex_size = EVP_MD_size(md) * 2;

tool/fd.cc

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/* Copyright (c) 2020, Google Inc.
2+
*
3+
* Permission to use, copy, modify, and/or distribute this software for any
4+
* purpose with or without fee is hereby granted, provided that the above
5+
* copyright notice and this permission notice appear in all copies.
6+
*
7+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10+
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12+
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13+
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14+
15+
#include <openssl/base.h>
16+
17+
#include <errno.h>
18+
#include <limits.h>
19+
#include <stdio.h>
20+
21+
#include <algorithm>
22+
23+
#include "internal.h"
24+
25+
#if defined(OPENSSL_WINDOWS)
26+
#include <io.h>
27+
#else
28+
#include <fcntl.h>
29+
#include <unistd.h>
30+
#endif
31+
32+
33+
ScopedFD OpenFD(const char *path, int flags) {
34+
#if defined(OPENSSL_WINDOWS)
35+
return ScopedFD(_open(path, flags));
36+
#else
37+
int fd;
38+
do {
39+
fd = open(path, flags);
40+
} while (fd == -1 && errno == EINTR);
41+
return ScopedFD(fd);
42+
#endif
43+
}
44+
45+
void CloseFD(int fd) {
46+
#if defined(OPENSSL_WINDOWS)
47+
_close(fd);
48+
#else
49+
close(fd);
50+
#endif
51+
}
52+
53+
bool ReadFromFD(int fd, size_t *out_bytes_read, void *out, size_t num) {
54+
#if defined(OPENSSL_WINDOWS)
55+
// On Windows, the buffer must be at most |INT_MAX|. See
56+
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/read?view=vs-2019
57+
int ret = _read(fd, out, std::min(size_t{INT_MAX}, num));
58+
#else
59+
ssize_t ret;
60+
do {
61+
ret = read(fd, out, num);
62+
} while (ret == -1 && errno == EINVAL);
63+
#endif
64+
65+
if (ret < 0) {
66+
*out_bytes_read = 0;
67+
return false;
68+
}
69+
*out_bytes_read = ret;
70+
return true;
71+
}
72+
73+
bool WriteToFD(int fd, size_t *out_bytes_written, const void *in, size_t num) {
74+
#if defined(OPENSSL_WINDOWS)
75+
// The documentation for |_write| does not say the buffer must be at most
76+
// |INT_MAX|, but clamp it to |INT_MAX| instead of |UINT_MAX| in case.
77+
int ret = _write(fd, in, std::min(size_t{INT_MAX}, num));
78+
#else
79+
ssize_t ret;
80+
do {
81+
ret = write(fd, in, num);
82+
} while (ret == -1 && errno == EINVAL);
83+
#endif
84+
85+
if (ret < 0) {
86+
*out_bytes_written = 0;
87+
return false;
88+
}
89+
*out_bytes_written = ret;
90+
return true;
91+
}
92+
93+
ScopedFILE FDToFILE(ScopedFD fd, const char *mode) {
94+
ScopedFILE ret;
95+
#if defined(OPENSSL_WINDOWS)
96+
ret.reset(_fdopen(fd.get(), mode));
97+
#else
98+
ret.reset(fdopen(fd.get(), mode));
99+
#endif
100+
// |fdopen| takes ownership of |fd| on success.
101+
if (ret) {
102+
fd.release();
103+
}
104+
return ret;
105+
}

tool/internal.h

+63-17
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,17 @@
1818
#include <openssl/base.h>
1919

2020
#include <string>
21+
#include <utility>
2122
#include <vector>
2223

23-
OPENSSL_MSVC_PRAGMA(warning(push))
2424
// MSVC issues warning C4702 for unreachable code in its xtree header when
2525
// compiling with -D_HAS_EXCEPTIONS=0. See
2626
// https://connect.microsoft.com/VisualStudio/feedback/details/809962
27+
OPENSSL_MSVC_PRAGMA(warning(push))
2728
OPENSSL_MSVC_PRAGMA(warning(disable: 4702))
28-
2929
#include <map>
30-
3130
OPENSSL_MSVC_PRAGMA(warning(pop))
3231

33-
#if defined(OPENSSL_WINDOWS)
34-
#define BORINGSSL_OPEN _open
35-
#define BORINGSSL_FDOPEN _fdopen
36-
#define BORINGSSL_CLOSE _close
37-
#define BORINGSSL_READ _read
38-
#define BORINGSSL_WRITE _write
39-
#else
40-
#define BORINGSSL_OPEN open
41-
#define BORINGSSL_FDOPEN fdopen
42-
#define BORINGSSL_CLOSE close
43-
#define BORINGSSL_READ read
44-
#define BORINGSSL_WRITE write
45-
#endif
46-
4732
struct FileCloser {
4833
void operator()(FILE *file) {
4934
fclose(file);
@@ -52,6 +37,67 @@ struct FileCloser {
5237

5338
using ScopedFILE = std::unique_ptr<FILE, FileCloser>;
5439

40+
// The following functions abstract between POSIX and Windows differences in
41+
// file descriptor I/O functions.
42+
43+
// CloseFD behaves like |close|.
44+
void CloseFD(int fd);
45+
46+
class ScopedFD {
47+
public:
48+
ScopedFD() {}
49+
explicit ScopedFD(int fd) : fd_(fd) {}
50+
ScopedFD(ScopedFD &&other) { *this = std::move(other); }
51+
ScopedFD(const ScopedFD &) = delete;
52+
~ScopedFD() { reset(); }
53+
54+
ScopedFD &operator=(const ScopedFD &) = delete;
55+
ScopedFD &operator=(ScopedFD &&other) {
56+
reset();
57+
fd_ = other.fd_;
58+
other.fd_ = -1;
59+
return *this;
60+
}
61+
62+
explicit operator bool() const { return fd_ >= 0; }
63+
64+
int get() const { return fd_; }
65+
66+
void reset() {
67+
if (fd_ >= 0) {
68+
CloseFD(fd_);
69+
}
70+
fd_ = -1;
71+
}
72+
73+
int release() {
74+
int fd = fd_;
75+
fd_ = -1;
76+
return fd;
77+
}
78+
79+
private:
80+
int fd_ = -1;
81+
};
82+
83+
// OpenFD behaves like |open| but handles |EINTR| and works on Windows.
84+
ScopedFD OpenFD(const char *path, int flags);
85+
86+
// ReadFromFD reads up to |num| bytes from |fd| and writes the result to |out|.
87+
// On success, it returns true and sets |*out_bytes_read| to the number of bytes
88+
// read. Otherwise, it returns false and leaves an error in |errno|. On POSIX,
89+
// it handles |EINTR| internally.
90+
bool ReadFromFD(int fd, size_t *out_bytes_read, void *out, size_t num);
91+
92+
// WriteToFD writes up to |num| bytes from |in| to |fd|. On success, it returns
93+
// true and sets |*out_bytes_written| to the number of bytes written. Otherwise,
94+
// it returns false and leaves an error in |errno|. On POSIX, it handles |EINTR|
95+
// internally.
96+
bool WriteToFD(int fd, size_t *out_bytes_written, const void *in, size_t num);
97+
98+
// FDToFILE behaves like |fdopen|.
99+
ScopedFILE FDToFILE(ScopedFD fd, const char *mode);
100+
55101
enum ArgumentType {
56102
kRequiredArgument,
57103
kOptionalArgument,

0 commit comments

Comments
 (0)