-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathproto_file.cpp
More file actions
153 lines (139 loc) · 5.42 KB
/
proto_file.cpp
File metadata and controls
153 lines (139 loc) · 5.42 KB
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
/**
* Copyright (c) 2023 Boston Dynamics, Inc. All rights reserved.
*
* Downloading, reproducing, distributing or otherwise using the SDK Software
* is subject to the terms and conditions of the Boston Dynamics Software
* Development Kit License (20191101-BDSDK-SL).
*/
#include "proto_file.h"
#include <fcntl.h>
#include <sys/stat.h>
#ifdef WIN32
# include <io.h>
# define open _open
# define close(a) _close(a)
# define fsync(a) _commit(a)
#else
# include <unistd.h>
#endif
namespace {
// RAII for file descriptor
class unique_fd {
public:
unique_fd(int fd) : m_fd(fd) {}
unique_fd(const unique_fd& other) = delete; // non-copyable.
unique_fd(unique_fd&& other) { std::swap(m_fd, other.m_fd); }
~unique_fd() {
if (*this) close();
}
inline int fd() { return m_fd; }
operator bool() { return m_fd >= 0; }
unique_fd& operator=(const unique_fd& other) = delete;
unique_fd& operator=(unique_fd&& other) {
std::swap(m_fd, other.m_fd);
return *this;
}
bool close() {
bool result = (::close(m_fd) == 0);
m_fd = -1;
return result;
}
private:
int m_fd = -1;
};
struct ReadErrorCategory : public std::error_category {
const char* name() const noexcept override { return "bosdyn::common::ReadError"; }
std::string message(int ev) const override {
switch (static_cast<bosdyn::common::ReadError>(ev)) {
case bosdyn::common::ReadError::kSuccess:
return "Success";
case bosdyn::common::ReadError::kParseError:
return "Failed to parse the message.";
case bosdyn::common::ReadError::kEmptyFile:
return "File was empty.";
}
return "Unknown error";
}
// bool equivalent(int valcode, const std::error_condition& cond) const noexcept override {
// return false;}
};
struct WriteErrorCategory : public std::error_category {
const char* name() const noexcept override { return "bosdyn::common::WriteError"; }
std::string message(int ev) const override {
switch (static_cast<bosdyn::common::WriteError>(ev)) {
case bosdyn::common::WriteError::kSuccess:
return "Success";
case bosdyn::common::WriteError::kSerializationError:
return "Failed to serialize the message.";
}
return "Unknown error";
}
// bool equivalent(int valcode, const std::error_condition& cond) const noexcept override {
// return false;}
};
const ReadErrorCategory ReadErrorCategory_category{};
const WriteErrorCategory WriteErrorCategory_category{};
} // namespace
namespace bosdyn::common {
bool ParseMessageFromFile(const std::string& filename, google::protobuf::Message* message,
ParseOptions options) {
// error_code is true if there is an error.
return !ParseMessageFromFileWithError(filename, message, options);
}
bool WriteMessageToFile(const std::string& filename, const google::protobuf::Message& message,
WriteOptions options) {
// error_code is true if there is an error.
return !WriteMessageToFileWithError(filename, message, options);
}
std::error_code make_error_code(ReadError value) {
return {static_cast<int>(value), ReadErrorCategory_category};
}
std::error_code make_error_code(WriteError value) {
return {static_cast<int>(value), WriteErrorCategory_category};
}
std::error_code ParseMessageFromFileWithError(const std::string& filename,
google::protobuf::Message* message,
ParseOptions options) {
int mode = options.update_access_time ? O_RDWR : O_RDONLY;
unique_fd fd(open(filename.c_str(), mode));
if (!fd) {
if (!((mode | O_RDWR) && (errno == EACCES || errno == EROFS)))
return std::make_error_code(std::errc(errno));
// Try again, falling back to not updating access time.
fd = unique_fd(open(filename.c_str(), O_RDONLY));
if (!fd) return std::make_error_code(std::errc(errno));
;
options.update_access_time = false;
}
#ifdef IS_LINUX
if (options.update_access_time) {
// Update access time but not modification time.
timespec times[2] = {UTIME_NOW, UTIME_OMIT};
futimens(fd.fd(), times); // Don't bother with error checking on this one.
}
#endif
if (options.ensure_non_empty) {
struct stat stat_buf;
fstat(fd.fd(), &stat_buf);
if (stat_buf.st_size == 0) return ReadError::kEmptyFile;
}
if (message->ParseFromFileDescriptor(fd.fd())) {
return ReadError::kSuccess;
} else {
return ReadError::kParseError;
}
}
std::error_code WriteMessageToFileWithError(const std::string& filename,
const google::protobuf::Message& message,
WriteOptions options) {
unique_fd fd(open(filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0666));
if (!fd) return std::make_error_code(std::errc(errno));
if (!message.SerializeToFileDescriptor(fd.fd())) return WriteError::kSerializationError;
if (options.fsync_file && fsync(fd.fd()) != 0) return std::make_error_code(std::errc(errno));
if (fd.close()) { // Will return false if closing fails.
return WriteError::kSuccess;
} else {
return std::make_error_code(std::errc(errno));
}
}
} // namespace bosdyn::common