libcsdbg  1.28
C++ exception (and generic) stack trace debug library
filebuf.cpp
Go to the documentation of this file.
1 #include "../include/filebuf.hpp"
2 #include "../include/util.hpp"
3 #if !defined CSDBG_WITH_PLUGIN && !defined CSDBG_WITH_HIGHLIGHT
4 #include "../include/exception.hpp"
5 #endif
6 
13 namespace csdbg {
14 
23 filebuf::filebuf(const i8 *path)
24 try:
25 streambuf(),
26 m_path(NULL)
27 {
28  if ( unlikely(path == NULL) )
29  throw exception("invalid argument: path (=%p)", path);
30 
31  m_path = new i8[strlen(path) + 1];
32  strcpy(m_path, path);
33 }
34 
35 catch (...) {
36  delete[] m_data;
37  m_data = NULL;
38  m_path = NULL;
39 }
40 
41 
51 try:
52 streambuf(src),
53 m_path(NULL)
54 {
55  m_path = new i8[strlen(src.m_path) + 1];
56  strcpy(m_path, src.m_path);
57 }
58 
59 catch (...) {
60  delete[] m_data;
61  m_data = NULL;
62  m_path = NULL;
63  close();
64 }
65 
66 
71 {
72  delete[] m_path;
73  m_path = NULL;
74 }
75 
76 
85 inline filebuf* filebuf::clone() const
86 {
87  return new filebuf(*this);
88 }
89 
90 
96 inline const i8* filebuf::path() const
97 {
98  return m_path;
99 }
100 
101 
113 {
114  if ( unlikely(this == &rval) )
115  return *this;
116 
117  /* Copy the buffer and duplicate the stream descriptor */
118  streambuf::operator=(rval);
119 
120  u32 len = strlen(rval.m_path);
121  if (len > strlen(m_path)) {
122  delete[] m_path;
123  m_path = NULL;
124  m_path = new i8[len + 1];
125  }
126 
127  strcpy(m_path, rval.m_path);
128  return *this;
129 }
130 
131 
144 {
145  return open(O_WRONLY | O_CREAT | O_APPEND, 0644);
146 }
147 
148 
162 filebuf& filebuf::open(u32 flags, u32 umask)
163 {
164  if ( unlikely(m_handle >= 0) )
165  close();
166 
167  do {
168  m_handle = ::open(m_path, flags, umask);
169  }
170  while ( unlikely(m_handle < 0 && errno == EINTR) );
171 
172  if ( unlikely(m_handle < 0) )
173  throw exception(
174  "failed to open file '%s' (errno %d - %s)",
175  m_path,
176  errno,
177  strerror(errno)
178  );
179 
180  /* Sanity checks, if a test fails an appropriate exception is thrown */
181  try {
182  fileinfo_t inf;
183  i32 retval = fstat(m_handle, &inf);
184  if ( unlikely(retval < 0) )
185  throw exception(
186  "failed to stat path '%s' (errno %d - %s)",
187  m_path,
188  errno,
189  strerror(errno)
190  );
191 
192  else if ( unlikely(!util::is_regular(inf)) )
193  throw exception("'%s' is not a regular file", m_path);
194 
195  else if ( unlikely(!util::is_writable(inf)) )
196  throw exception("file '%s' is not writable", m_path);
197 
198  return *this;
199  }
200 
201  catch (...) {
202  /* If any of the checks failed, the descriptor is unusable */
203  close();
204  throw;
205  }
206 }
207 
208 
217 {
218  try {
220  return *this;
221  }
222 
223  catch (i32 err) {
224  throw exception(
225  "failed to write data to file '%s' (errno %d - %s)",
226  m_path,
227  err,
228  strerror(err)
229  );
230  }
231 }
232 
233 
241 inline filebuf& filebuf::sync() const
242 {
243  return sync(false);
244 }
245 
246 
256 filebuf& filebuf::sync(bool full) const
257 {
258  i32 retval;
259  if ( likely(full) )
260  retval = fsync(m_handle);
261  else
262  retval = fdatasync(m_handle);
263 
264  if ( unlikely(retval < 0) )
265  throw exception("failed to sync file '%s'", m_path);
266 
267  return const_cast<filebuf&> (*this);
268 }
269 
270 
282 filebuf& filebuf::seek_to(i32 offset, bool rel)
283 {
284  i32 whence = (rel) ? SEEK_CUR : SEEK_SET;
285  i32 retval = lseek(m_handle, offset, whence);
286  if ( unlikely(retval < 0) )
287  throw exception(
288  "failed to seek file '%s' to offset %d (errno %d - %s)",
289  m_path,
290  offset,
291  errno,
292  strerror(errno)
293  );
294 
295  return *this;
296 }
297 
298 
314 {
315  i32 retval;
316  do {
317  retval = ftruncate(m_handle, sz);
318  }
319  while ( unlikely(retval < 0 && errno == EINTR) );
320 
321  if ( unlikely(retval < 0) )
322  throw errno;
323 
324  return *this;
325 }
326 
327 
355 string* filebuf::unique_id(const i8 *fmt)
356 {
357  __D_ASSERT(fmt != NULL);
358  if ( unlikely(fmt == NULL || strlen(fmt) == 0) )
359  fmt = "%e_%p_%t_%s";
360 
361  struct timeval now;
362  gettimeofday(&now, NULL);
363  u64 tstamp = static_cast<u64> (now.tv_sec) * 10e+5 + now.tv_usec;
364 
365  const i8 *path = util::exec_path();
366  string *retval = NULL;
367 
368  /* If an exception occurs, release resources and rethrow it */
369  try {
370  retval = new string();
371 
372  for (u32 i = 0, len = strlen(fmt); likely(i < len); i++) {
373  i8 ch = fmt[i];
374  if ( likely(ch != '%') ) {
375  retval->append(ch);
376  continue;
377  }
378 
379  if ( unlikely(i == len - 1) )
380  throw exception("invalid format '%s' (at %d: no specifier)", fmt, ++i);
381 
382  ch = fmt[++i];
383  switch (ch) {
384  case '%':
385  retval->append(ch);
386  break;
387 
388  case 'a':
389  retval->append(path);
390  break;
391 
392  case 'e':
393  retval->append(basename(path));
394  break;
395 
396  case 'p':
397  retval->append("%x", getpid());
398  break;
399 
400  case 't':
401  retval->append("%lx", pthread_self());
402  break;
403 
404  case 's':
405  retval->append("%lx", tstamp);
406  break;
407 
408  default: {
409  const i8 err[] = "invalid format '%s' (at %d: unknown specifier '%c')";
410  throw exception(err, fmt, i, ch);
411  }}
412  }
413 
414  delete[] path;
415  return retval;
416  }
417 
418  catch (...) {
419  delete[] path;
420  delete retval;
421  throw;
422  }
423 }
424 
425 }
426 
virtual string & append(const string &)
Append a string.
Definition: string.cpp:404
virtual ~filebuf()
Object destructor.
Definition: filebuf.cpp:70
virtual streambuf & flush()=0
To be implemented.
Definition: streambuf.cpp:156
static const i8 * exec_path()
Get the absolute path of the executable.
Definition: util.cpp:87
static bool is_writable(const fileinfo_t &)
Check if the process has write access to a file.
Definition: util.cpp:464
This abstract class is the base for all buffered output stream types (for files, sockets, serial interfaces e.t.c)
Definition: streambuf.hpp:37
virtual filebuf & flush()
Flush the buffered data to the file.
Definition: filebuf.cpp:216
char i8
8-bit signed integer
Definition: config.hpp:72
virtual filebuf & seek_to(i32, bool=false)
Seek the file pointer to a new position.
Definition: filebuf.cpp:282
struct stat fileinfo_t
File metadata.
Definition: config.hpp:112
virtual filebuf & operator=(const filebuf &)
Assignment operator.
Definition: filebuf.cpp:112
unsigned long long u64
64-bit unsigned integer
Definition: config.hpp:107
i32 m_handle
Stream handle (descriptor)
Definition: streambuf.hpp:43
virtual filebuf * clone() const
Object virtual copy constructor.
Definition: filebuf.cpp:85
virtual filebuf & open()
Open the file for output.
Definition: filebuf.cpp:143
string(u32=0)
Object constructor.
Definition: string.cpp:127
#define likely(expr)
Offer a hint (positive) to the pipeline branch predictor.
Definition: config.hpp:344
virtual streambuf & operator=(const streambuf &)
Assignment operator.
Definition: streambuf.cpp:96
virtual filebuf & resize(u32)
Resize the file.
Definition: filebuf.cpp:313
virtual filebuf & sync() const
Commit cached data to the file.
Definition: filebuf.cpp:241
virtual const i8 * path() const
Get the output file path.
Definition: filebuf.cpp:96
unsigned int u32
32-bit unsigned integer
Definition: config.hpp:102
int i32
32-bit signed integer
Definition: config.hpp:82
static bool is_regular(const fileinfo_t &)
Check if a file is a regular one.
Definition: util.cpp:419
A buffered file output stream.
Definition: filebuf.hpp:31
i8 * m_path
Output file path.
Definition: filebuf.hpp:37
filebuf(const i8 *)
Object constructor.
Definition: filebuf.cpp:23
This class is a throwable with a textual description of an error.
Definition: exception.hpp:26
#define unlikely(expr)
Offer a hint (negative) to the pipeline branch predictor.
Definition: config.hpp:349
virtual streambuf & close()
Close the stream.
Definition: streambuf.cpp:130
static string * unique_id(const i8 *)
Create a unique ID based on process identifiers arranged as indicated by a printf-style format string...
Definition: filebuf.cpp:355
#define __D_ASSERT(x)
Assertion macro.
Definition: config.hpp:268