blocxx
FileBuf.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Quest Software, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Quest Software, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
38 #include "blocxx/BLOCXX_config.h"
39 #include "blocxx/FileBuf.hpp"
40 #include "blocxx/IOException.hpp"
41 
42 #ifdef BLOCXX_HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 
46 #include <fcntl.h>
47 #include <ios>
48 
49 #ifdef BLOCXX_WIN32
50 #include <io.h>
51 #endif
52 
53 namespace BLOCXX_NAMESPACE
54 {
55 
57 : BaseStreamBuffer(E_IN_OUT)
58 , m_file(0)
59 {
60 }
61 
63 {
64  close();
65 }
66 
67 bool
69 {
70  return m_file != 0;
71 }
72 
73 FileBuf*
74 FileBuf::open(FILE* fp)
75 {
76  if (isOpen())
77  {
78  return 0;
79  }
80 
81  m_file = fp;
82  return this;
83 }
84 
85 FileBuf*
87 {
88  if (isOpen())
89  {
90  return 0;
91  }
92 
93 int d = -1;
94 
95 #ifdef BLOCXX_WIN32
96 #pragma message(Reminder "TODO: implement it for Win!")
97  //maybe it's enough just to set flags = O_RDWR
98  //but it's unclear what to do with O_APPEND
99  int flags = O_RDWR;
100 
101  d = _open_osfhandle(reinterpret_cast<long>(fd.get()), flags);
102 #else
103  d = fd.get();
104  int flags = ::fcntl(d, F_GETFL);
105  if (flags == -1)
106  {
107  return 0;
108  }
109 #endif
110 
111  m_file = ::fdopen(d, cppModeToCMode(posixModeToCppMode(flags)));
112  if (m_file == 0)
113  {
114  return 0;
115  }
116  ::setbuf(m_file, 0);
117  fd.release();
118  return this;
119 }
120 
121 #if 0
122 FileBuf*
123 FileBuf::open(const File& f)
124 {
125  if (isOpen())
126  {
127  return 0;
128  }
129  int flags = ::fcntl(f.???, F_GETFL);
130  if (flags == -1)
131  {
132  return 0;
133  }
134 
135  m_file = ::fdopen(???, cppModeToCMode(posixModeToCppMode(flags)));
136  if (m_file == 0)
137  {
138  return 0;
139  }
140  ::setbuf(m_file, 0);
141  return this;
142 }
143 #endif
144 
145 FileBuf*
146 FileBuf::open(const char* path, std::ios_base::openmode mode, mode_t permissions)
147 {
148  if (isOpen())
149  {
150  return 0;
151  }
152 
153  int d = ::open(path, cppModeToPOSIXMode(mode), permissions);
154 
155 #ifdef BLOCXX_WIN32
156  Descriptor h = reinterpret_cast<Descriptor>(_get_osfhandle(d));
157  AutoDescriptor fd(h);
158 #else
159  AutoDescriptor fd(d);
160 #endif
161 
162  if (fd.get() == BLOCXX_INVALID_HANDLE)
163  {
164  return 0;
165  }
166 
167  m_file = ::fdopen(d, cppModeToCMode(mode));
168 
169  if (m_file == 0)
170  {
171  return 0;
172  }
173 
174  ::setbuf(m_file, 0);
175  fd.release();
176 
177  return this;
178 }
179 
180 FileBuf*
182 {
183  if (isOpen())
184  {
185  ::fclose(m_file);
186  }
187  m_file = 0;
188  return this;
189 }
190 
191 int
192 FileBuf::buffer_to_device(const char* c, int n)
193 {
194  size_t written = ::fwrite(c, 1, n, m_file);
195  if (written == static_cast<size_t>(n))
196  {
197  return 0;
198  }
199  else
200  {
201  return -1;
202  }
203 }
204 
205 int
207 {
208  if (!isOpen())
209  {
210  return -1;
211  }
212  size_t numRead = ::fread(c, 1, n, m_file);
213  if (numRead != static_cast<size_t>(n))
214  {
215  if (ferror(m_file))
216  {
217  BLOCXX_THROW_ERRNO_MSG(IOException, "FileBuf::buffer_from_device: ::fread()");
218  }
219  else if (feof(m_file) && numRead == 0)
220  {
221  return -1;
222  }
223  else
224  {
225  return numRead;
226  }
227  }
228  else
229  {
230  return n;
231  }
232 }
233 
234 std::ios_base::openmode
236 {
237  std::ios_base::openmode mode = posixMode & O_APPEND ? std::ios::app : std::ios_base::openmode(0);
238 
239 #ifdef BLOCXX_WIN32
240  #define O_ACCMODE 3
241 #endif
242  switch (posixMode & O_ACCMODE)
243  {
244  case O_RDONLY: mode |= (std::ios::in | std::ios::binary); break;
245  case O_WRONLY: mode |= (std::ios::out | std::ios::binary); break;
246  case O_RDWR: mode |= (std::ios::in | std::ios::out | std::ios::binary); break;
247  }
248  return mode;
249 }
250 
251 int
252 FileBuf::cppModeToPOSIXMode(std::ios_base::openmode cppMode)
253 {
254  int mode = 0;
255  if (cppMode & std::ios::app)
256  {
257  mode |= O_APPEND;
258  }
259 
260  if (cppMode & std::ios::trunc)
261  {
262  mode |= O_TRUNC;
263  }
264 
265  if (cppMode & (std::ios::in | std::ios::out))
266  {
267  mode |= O_RDWR;
268  }
269  else if (cppMode & std::ios::in)
270  {
271  mode |= O_RDONLY;
272  }
273  else if (cppMode & std::ios::out)
274  {
275  mode |= O_WRONLY;
276  }
277  return mode;
278 }
279 
280 const char* FileBuf::cppModeToCMode(std::ios_base::openmode cppMode)
281 {
282  // mask out irrelevant bits
283  cppMode = cppMode & ~std::ios::ate;
284 
285  using std::ios;
286  // can't use a switch here because the ios flags aren't native types.
287  if( cppMode == ios::app ||
288  cppMode == (ios::in|ios::app) ||
289  cppMode == (ios::out|ios::app) )
290  {
291  return "a";
292  }
293 
294  else if( cppMode == (ios::binary|ios::app) ||
295  cppMode == (ios::in|ios::binary|ios::app) ||
296  cppMode == (ios::out|ios::binary|ios::app) )
297  {
298  return "ab";
299  }
300 
301  else if (cppMode == ios::in)
302  {
303  return "r";
304  }
305 
306  else if (cppMode == (ios::in|ios::binary))
307  {
308  return "rb";
309  }
310 
311  else if (cppMode == (ios::out|ios::in))
312  {
313  return "r+";
314  }
315 
316  else if (cppMode == (ios::out|ios::in|ios::app))
317  {
318  return "a+";
319  }
320 
321  else if (cppMode == (ios::out|ios::in|ios::binary))
322  {
323  return "r+b";
324  }
325 
326  else if (cppMode == (ios::out|ios::in|ios::binary|ios::app))
327  {
328  return "a+b";
329  }
330 
331  else if( (cppMode == ios::out) ||
332  cppMode == (ios::trunc) ||
333  cppMode == (ios::trunc|ios::app) ||
334  cppMode == (ios::trunc|ios::out) ||
335  cppMode == (ios::trunc|ios::out|ios::app) )
336  {
337  return "w";
338  }
339 
340  else if( (cppMode == (ios::trunc|ios::binary)) ||
341  (cppMode == (ios::trunc|ios::binary|ios::app)) ||
342  (cppMode == (ios::out|ios::binary)) ||
343  (cppMode == (ios::trunc|ios::out|ios::binary)) ||
344  (cppMode == (ios::trunc|ios::out|ios::binary|ios::app) ))
345  {
346  return "wb";
347  }
348 
349  else if( (cppMode == (ios::trunc|ios::out|ios::in)) ||
350  (cppMode == (ios::trunc|ios::out|ios::in|ios::app)) )
351  {
352  return "w+";
353  }
354 
355  else if( (cppMode == (ios::trunc|ios::out|ios::in|ios::binary)) ||
356  (cppMode == (ios::trunc|ios::out|ios::in|ios::binary|ios::app)) )
357  {
358  return "w+b";
359  }
360  else
361  {
362  return ""; // bad mode
363  }
364 
365 }
366 
367 
368 } // end namespace BLOCXX_NAMESPACE
369 
370