libzypp  17.34.1
zerocopystreams.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \----------------------------------------------------------------------/
9 *
10 * Some versions of protobuf lite do not export the simple zero copy streams,
11 * so for those we copied them from upstream.
12 */
13 
14 #include "zerocopystreams.h"
15 
16 #ifdef PROTOBUFLITE_HAS_NO_ZEROCOPYSTREAM
17 
18 // Protocol Buffers - Google's data interchange format
19 // Copyright 2008 Google Inc. All rights reserved.
20 // https://developers.google.com/protocol-buffers/
21 //
22 // Redistribution and use in source and binary forms, with or without
23 // modification, are permitted provided that the following conditions are
24 // met:
25 //
26 // * Redistributions of source code must retain the above copyright
27 // notice, this list of conditions and the following disclaimer.
28 // * Redistributions in binary form must reproduce the above
29 // copyright notice, this list of conditions and the following disclaimer
30 // in the documentation and/or other materials provided with the
31 // distribution.
32 // * Neither the name of Google Inc. nor the names of its
33 // contributors may be used to endorse or promote products derived from
34 // this software without specific prior written permission.
35 //
36 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
37 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
38 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
39 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
40 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
43 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
46 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 
48 // Author: kenton@google.com (Kenton Varda)
49 // Based on original Protocol Buffers design by
50 // Sanjay Ghemawat, Jeff Dean, and others.
51 
52 #include <unistd.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <fcntl.h>
56 #include <errno.h>
57 #include <iostream>
58 #include <algorithm>
59 #include <google/protobuf/io/zero_copy_stream_impl.h>
60 #include <google/protobuf/stubs/common.h>
61 #include <google/protobuf/stubs/logging.h>
62 #include <google/protobuf/stubs/stl_util.h>
63 
64 namespace zyppng {
65 
66 namespace {
67 
68 // EINTR sucks.
69 int close_no_eintr(int fd) {
70  int result;
71  do {
72  result = close(fd);
73  } while (result < 0 && errno == EINTR);
74  return result;
75 }
76 
77 } // namespace
78 
79 
80 // ===================================================================
81 
82 FileInputStream::FileInputStream(int file_descriptor, int block_size)
83  : copying_input_(file_descriptor),
84  impl_(&copying_input_, block_size) {
85 }
86 
87 bool FileInputStream::Close() {
88  return copying_input_.Close();
89 }
90 
91 bool FileInputStream::Next(const void** data, int* size) {
92  return impl_.Next(data, size);
93 }
94 
95 void FileInputStream::BackUp(int count) {
96  impl_.BackUp(count);
97 }
98 
99 bool FileInputStream::Skip(int count) {
100  return impl_.Skip(count);
101 }
102 
103 google::protobuf::int64 FileInputStream::ByteCount() const {
104  return impl_.ByteCount();
105 }
106 
107 FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
108  int file_descriptor)
109  : file_(file_descriptor),
110  close_on_delete_(false),
111  is_closed_(false),
112  errno_(0),
113  previous_seek_failed_(false) {
114 }
115 
116 FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
117  if (close_on_delete_) {
118  if (!Close()) {
119  GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
120  }
121  }
122 }
123 
124 bool FileInputStream::CopyingFileInputStream::Close() {
125  GOOGLE_CHECK(!is_closed_);
126 
127  is_closed_ = true;
128  if (close_no_eintr(file_) != 0) {
129  // The docs on close() do not specify whether a file descriptor is still
130  // open after close() fails with EIO. However, the glibc source code
131  // seems to indicate that it is not.
132  errno_ = errno;
133  return false;
134  }
135 
136  return true;
137 }
138 
139 int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
140  GOOGLE_CHECK(!is_closed_);
141 
142  int result;
143  do {
144  result = read(file_, buffer, size);
145  } while (result < 0 && errno == EINTR);
146 
147  if (result < 0) {
148  // Read error (not EOF).
149  errno_ = errno;
150  }
151 
152  return result;
153 }
154 
155 int FileInputStream::CopyingFileInputStream::Skip(int count) {
156  GOOGLE_CHECK(!is_closed_);
157 
158  if (!previous_seek_failed_ &&
159  lseek(file_, count, SEEK_CUR) != (off_t)-1) {
160  // Seek succeeded.
161  return count;
162  } else {
163  // Failed to seek.
164 
165  // Note to self: Don't seek again. This file descriptor doesn't
166  // support it.
167  previous_seek_failed_ = true;
168 
169  // Use the default implementation.
170  return google::protobuf::io::CopyingInputStream::Skip(count);
171  }
172 }
173 
174 // ===================================================================
175 
176 FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
177  : copying_output_(file_descriptor),
178  impl_(&copying_output_, block_size) {
179 }
180 
181 FileOutputStream::~FileOutputStream() {
182  impl_.Flush();
183 }
184 
185 bool FileOutputStream::Close() {
186  bool flush_succeeded = impl_.Flush();
187  return copying_output_.Close() && flush_succeeded;
188 }
189 
190 bool FileOutputStream::Flush() {
191  return impl_.Flush();
192 }
193 
194 bool FileOutputStream::Next(void** data, int* size) {
195  return impl_.Next(data, size);
196 }
197 
198 void FileOutputStream::BackUp(int count) {
199  impl_.BackUp(count);
200 }
201 
202 google::protobuf::int64 FileOutputStream::ByteCount() const {
203  return impl_.ByteCount();
204 }
205 
206 FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
207  int file_descriptor)
208  : file_(file_descriptor),
209  close_on_delete_(false),
210  is_closed_(false),
211  errno_(0) {
212 }
213 
214 FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
215  if (close_on_delete_) {
216  if (!Close()) {
217  GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
218  }
219  }
220 }
221 
222 bool FileOutputStream::CopyingFileOutputStream::Close() {
223  GOOGLE_CHECK(!is_closed_);
224 
225  is_closed_ = true;
226  if (close_no_eintr(file_) != 0) {
227  // The docs on close() do not specify whether a file descriptor is still
228  // open after close() fails with EIO. However, the glibc source code
229  // seems to indicate that it is not.
230  errno_ = errno;
231  return false;
232  }
233 
234  return true;
235 }
236 
237 bool FileOutputStream::CopyingFileOutputStream::Write(
238  const void* buffer, int size) {
239  GOOGLE_CHECK(!is_closed_);
240  int total_written = 0;
241 
242  const google::protobuf::uint8* buffer_base = reinterpret_cast<const google::protobuf::uint8*>(buffer);
243 
244  while (total_written < size) {
245  int bytes;
246  do {
247  bytes = write(file_, buffer_base + total_written, size - total_written);
248  } while (bytes < 0 && errno == EINTR);
249 
250  if (bytes <= 0) {
251  // Write error.
252 
253  // FIXME(kenton): According to the man page, if write() returns zero,
254  // there was no error; write() simply did not write anything. It's
255  // unclear under what circumstances this might happen, but presumably
256  // errno won't be set in this case. I am confused as to how such an
257  // event should be handled. For now I'm treating it as an error, since
258  // retrying seems like it could lead to an infinite loop. I suspect
259  // this never actually happens anyway.
260 
261  if (bytes < 0) {
262  errno_ = errno;
263  }
264  return false;
265  }
266  total_written += bytes;
267  }
268 
269  return true;
270 }
271 
272 // ===================================================================
273 
274 } // namespace
275 
276 #endif
google::protobuf::io::FileInputStream FileInputStream
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:54
google::protobuf::io::FileOutputStream FileOutputStream
std::map< std::string, std::string > read(const Pathname &_path)
Read sysconfig file path_r and return (key,valye) pairs.
Definition: sysconfig.cc:34
bool write(const Pathname &path_r, const std::string &key_r, const std::string &val_r, const std::string &newcomment_r)
Add or change a value in sysconfig file path_r.
Definition: sysconfig.cc:80