0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
FileUtils.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 3
9  * of the License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
27 #include "Common/Compat.h"
28 
29 #include <iomanip>
30 #include <iostream>
31 #include <sstream>
32 #include <cstdio>
33 
34 extern "C" {
35 #include <unistd.h>
36 #include <errno.h>
37 #include <pwd.h>
38 #include <fcntl.h>
39 #include <string.h>
40 #include <sys/mman.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <sys/uio.h>
44 }
45 
46 #include <boost/shared_array.hpp>
47 #include <boost/shared_ptr.hpp>
48 
49 #include <re2/re2.h>
50 
51 #include "FileUtils.h"
52 #include "Logger.h"
53 
54 using namespace Hypertable;
55 using namespace std;
56 
58 
59 bool FileUtils::read(const String &fname, String &contents) {
60  off_t len {};
61  char *buf = file_to_buffer(fname, &len);
62  if (buf != 0) {
63  contents.append(buf, len);
64  delete [] buf;
65  return true;
66  }
67  return false;
68 }
69 
70 
71 ssize_t FileUtils::read(int fd, void *vptr, size_t n) {
72  size_t nleft;
73  ssize_t nread;
74  char *ptr;
75 
76  ptr = (char *)vptr;
77  nleft = n;
78  while (nleft > 0) {
79  if ((nread = ::read(fd, ptr, nleft)) < 0) {
80  if (errno == EINTR)
81  nread = 0;/* and call read() again */
82  else if (errno == EAGAIN)
83  break;
84  else
85  return -1;
86  }
87  else if (nread == 0)
88  break; /* EOF */
89 
90  nleft -= nread;
91  ptr += nread;
92  }
93  return n - nleft;
94 }
95 
96 
97 ssize_t FileUtils::pread(int fd, void *vptr, size_t n, off_t offset) {
98  size_t nleft;
99  ssize_t nread;
100  char *ptr;
101 
102  ptr = (char *)vptr;
103  nleft = n;
104  while (nleft > 0) {
105  if ((nread = ::pread(fd, ptr, nleft, offset)) < 0) {
106  if (errno == EINTR)
107  nread = 0;/* and call read() again */
108  else if (errno == EAGAIN)
109  break;
110  else
111  return -1;
112  }
113  else if (nread == 0)
114  break; /* EOF */
115 
116  nleft -= nread;
117  ptr += nread;
118  offset += nread;
119  }
120  return n - nleft;
121 }
122 
123 
124 ssize_t FileUtils::write(const String &fname, const std::string &contents) {
125  int fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
126  if (fd < 0) {
127  int saved_errno = errno;
128  HT_ERRORF("Unable to open file \"%s\" for writing - %s", fname.c_str(),
129  strerror(saved_errno));
130  errno = saved_errno;
131  return -1;
132  }
133  ssize_t rval = write(fd, contents);
134  ::close(fd);
135  return rval;
136 }
137 
138 
139 ssize_t FileUtils::write(int fd, const void *vptr, size_t n) {
140  size_t nleft;
141  ssize_t nwritten;
142  const char *ptr;
143 
144  ptr = (const char *)vptr;
145  nleft = n;
146  while (nleft > 0) {
147  if ((nwritten = ::write(fd, ptr, nleft)) <= 0) {
148  if (errno == EINTR)
149  nwritten = 0; /* and call write() again */
150  else if (errno == EAGAIN)
151  break;
152  else
153  return -1; /* error */
154  }
155 
156  nleft -= nwritten;
157  ptr += nwritten;
158  }
159  return n - nleft;
160 }
161 
162 ssize_t FileUtils::writev(int fd, const struct iovec *vector, int count) {
163  ssize_t nwritten;
164  while ((nwritten = ::writev(fd, vector, count)) <= 0) {
165  if (errno == EINTR)
166  nwritten = 0; /* and call write() again */
167  else if (errno == EAGAIN) {
168  nwritten = 0;
169  break;
170  }
171  else
172  return -1; /* error */
173  }
174  return nwritten;
175 }
176 
177 
178 ssize_t FileUtils::sendto(int fd, const void *vptr, size_t n,
179  const sockaddr *to, socklen_t tolen) {
180  size_t nleft;
181  ssize_t nsent;
182  const char *ptr;
183 
184  ptr = (const char *)vptr;
185  nleft = n;
186  while (nleft > 0) {
187  if ((nsent = ::sendto(fd, ptr, nleft, 0, to, tolen)) <= 0) {
188  if (errno == EINTR)
189  nsent = 0; /* and call sendto() again */
190  else if (errno == EAGAIN || errno == ENOBUFS)
191  break;
192  else
193  return -1; /* error */
194  }
195 
196  nleft -= nsent;
197  ptr += nsent;
198  }
199  return n - nleft;
200 }
201 
202 
203 ssize_t FileUtils::send(int fd, const void *vptr, size_t n) {
204  size_t nleft;
205  ssize_t nsent;
206  const char *ptr;
207 
208  ptr = (const char *)vptr;
209  nleft = n;
210  while (nleft > 0) {
211  if ((nsent = ::send(fd, ptr, nleft, 0)) <= 0) {
212  if (errno == EINTR)
213  nsent = 0; /* and call sendto() again */
214  else if (errno == EAGAIN || errno == ENOBUFS)
215  break;
216  else
217  return -1; /* error */
218  }
219 
220  nleft -= nsent;
221  ptr += nsent;
222  }
223  return n - nleft;
224 }
225 
226 
227 ssize_t FileUtils::recvfrom(int fd, void *vptr, size_t n, sockaddr *from,
228  socklen_t *fromlen) {
229  ssize_t nread;
230  while (true) {
231  if ((nread = ::recvfrom(fd, vptr, n, 0, from, fromlen)) < 0) {
232  if (errno != EINTR)
233  break;
234  }
235  else
236  break;
237  }
238  return nread;
239 }
240 
241 
242 ssize_t FileUtils::recv(int fd, void *vptr, size_t n) {
243  ssize_t nread;
244  while (true) {
245  if ((nread = ::recv(fd, vptr, n, 0)) < 0) {
246  if (errno != EINTR)
247  break;
248  }
249  else
250  break;
251  }
252  return nread;
253 }
254 
255 
256 bool FileUtils::set_flags(int fd, int flags) {
257  int val;
258  bool ret = true;
259 
260  if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
261  int saved_errno = errno;
262  HT_ERROR_OUT << "fcnt(F_GETFL) failed : " << ::strerror(saved_errno)
263  << HT_END;
264  errno = saved_errno;
265  ret = false;
266  }
267 
268  val |= flags;
269 
270  if (fcntl(fd, F_SETFL, val) < 0) {
271  int saved_errno = errno;
272  HT_ERROR_OUT << "fcnt(F_SETFL) failed : " << ::strerror(saved_errno)
273  << HT_END;
274  errno = saved_errno;
275  ret = false;
276  }
277 
278  return ret;
279 }
280 
281 
282 char *FileUtils::file_to_buffer(const String &fname, off_t *lenp) {
283  struct stat statbuf;
284  int fd;
285 
286  *lenp = 0;
287 
288  if ((fd = open(fname.c_str(), O_RDONLY)) < 0) {
289  int saved_errno = errno;
290  HT_ERRORF("open(\"%s\") failure - %s", fname.c_str(),
291  strerror(saved_errno));
292  errno = saved_errno;
293  return 0;
294  }
295 
296  if (fstat(fd, &statbuf) < 0) {
297  int saved_errno = errno;
298  HT_ERRORF("fstat(\"%s\") failure - %s", fname.c_str(),
299  strerror(saved_errno));
300  errno = saved_errno;
301  return 0;
302  }
303 
304  *lenp = statbuf.st_size;
305 
306  char *rbuf = new char [*lenp + 1];
307 
308  ssize_t nread = FileUtils::read(fd, rbuf, *lenp);
309 
310  ::close(fd);
311 
312  if (nread == (ssize_t)-1) {
313  int saved_errno = errno;
314  HT_ERRORF("read(\"%s\") failure - %s", fname.c_str(),
315  strerror(saved_errno));
316  errno = saved_errno;
317  delete [] rbuf;
318  *lenp = 0;
319  return 0;
320  }
321 
322  if (nread < *lenp) {
323  HT_WARNF("short read (%d of %d bytes)", (int)nread, (int)*lenp);
324  *lenp = nread;
325  }
326 
327  rbuf[nread] = 0;
328 
329  return rbuf;
330 }
331 
332 
334  String str;
335  off_t len;
336  char *contents = file_to_buffer(fname, &len);
337  str = (contents == 0) ? "" : contents;
338  delete [] contents;
339  return str;
340 }
341 
342 
343 void *FileUtils::mmap(const String &fname, off_t *lenp) {
344  int fd;
345  struct stat statbuf;
346  void *map;
347 
348  if (::stat(fname.c_str(), &statbuf) != 0)
349  HT_FATALF("Unable determine length of '%s' for memory mapping - %s",
350  fname.c_str(), strerror(errno));
351  *lenp = (off_t)statbuf.st_size;
352 
353  if ((fd = ::open(fname.c_str(), O_RDONLY)) == -1)
354  HT_FATALF("Unable to open '%s' for memory mapping - %s", fname.c_str(),
355  strerror(errno));
356 
357  if ((map = ::mmap(0, *lenp, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
358  HT_FATALF("Unable to memory map file '%s' - %s", fname.c_str(),
359  strerror(errno));
360 
361  close(fd);
362  return map;
363 }
364 
365 
366 bool FileUtils::mkdirs(const String &dirname) {
367  struct stat statbuf;
368  boost::shared_array<char> tmp_dir(new char [dirname.length() + 1]);
369  char *tmpdir = tmp_dir.get();
370  char *ptr = tmpdir + 1;
371 
372  strcpy(tmpdir, dirname.c_str());
373 
374  while ((ptr = strchr(ptr, '/')) != 0) {
375  *ptr = 0;
376  if (stat(tmpdir, &statbuf) != 0) {
377  if (errno == ENOENT) {
378  if (mkdir(tmpdir, 0755) != 0) {
379  int saved_errno = errno;
380  HT_ERRORF("Problem creating directory '%s' - %s", tmpdir,
381  strerror(saved_errno));
382  errno = saved_errno;
383  return false;
384  }
385  }
386  else {
387  int saved_errno = errno;
388  HT_ERRORF("Problem stat'ing directory '%s' - %s", tmpdir,
389  strerror(saved_errno));
390  errno = saved_errno;
391  return false;
392  }
393  }
394  *ptr++ = '/';
395  }
396 
397  if (stat(tmpdir, &statbuf) != 0) {
398  if (errno == ENOENT) {
399  if (mkdir(tmpdir, 0755) != 0) {
400  int saved_errno = errno;
401  HT_ERRORF("Problem creating directory '%s' - %s", tmpdir,
402  strerror(saved_errno));
403  errno = saved_errno;
404  return false;
405  }
406  }
407  else {
408  int saved_errno = errno;
409  HT_ERRORF("Problem stat'ing directory '%s' - %s", tmpdir,
410  strerror(saved_errno));
411  errno = saved_errno;
412  return false;
413  }
414  }
415 
416  return true;
417 }
418 
419 
420 bool FileUtils::exists(const String &fname) {
421  struct stat statbuf;
422  if (stat(fname.c_str(), &statbuf) != 0)
423  return false;
424  return true;
425 }
426 
427 bool FileUtils::unlink(const String &fname) {
428  if (::unlink(fname.c_str()) == -1) {
429  int saved_errno = errno;
430  HT_ERRORF("unlink(\"%s\") failed - %s", fname.c_str(),
431  strerror(saved_errno));
432  errno = saved_errno;
433  return false;
434  }
435  return true;
436 }
437 
438 bool FileUtils::rename(const String &oldpath, const String &newpath) {
439  if (::rename(oldpath.c_str(), newpath.c_str()) == -1) {
440  int saved_errno = errno;
441  HT_ERRORF("rename(\"%s\", \"%s\") failed - %s",
442  oldpath.c_str(), newpath.c_str(), strerror(saved_errno));
443  errno = saved_errno;
444  return false;
445  }
446  return true;
447 }
448 
449 
450 uint64_t FileUtils::size(const String &fname) {
451  struct stat statbuf;
452  if (stat(fname.c_str(), &statbuf) != 0)
453  return 0;
454  return statbuf.st_size;
455 }
456 
457 
458 off_t FileUtils::length(const String &fname) {
459  struct stat statbuf;
460  if (stat(fname.c_str(), &statbuf) != 0)
461  return (off_t)-1;
462  return statbuf.st_size;
463 }
464 
465 
467  if (path.find('/', path.length() - 1) == string::npos)
468  path += "/";
469 }
470 
471 
473 
474  if (fname[0] != '~')
475  return false;
476 
477  lock_guard<mutex> lock(ms_mutex);
478 
479  struct passwd pbuf;
480  struct passwd *prbuf;
481  char buf[256];
482 
483  if (fname.length() == 1 || fname[1] == '/') {
484  if (getpwuid_r(getuid() , &pbuf, buf, 256, &prbuf) != 0 || prbuf == 0)
485  return false;
486  fname = (String)pbuf.pw_dir + fname.substr(1);
487  }
488  else {
489  String name;
490  size_t first_slash = fname.find_first_of('/');
491 
492  if (first_slash == string::npos)
493  name = fname.substr(1);
494  else
495  name = fname.substr(1, first_slash-1);
496 
497  if (getpwnam_r(name.c_str() , &pbuf, buf, 256, &prbuf) != 0 || prbuf == 0)
498  return false;
499 
500  if (first_slash == string::npos)
501  fname = pbuf.pw_dir;
502  else
503  fname = (String)pbuf.pw_dir + fname.substr(first_slash);
504  }
505 
506  return true;
507 }
508 
509 using namespace re2;
510 
511 void FileUtils::readdir(const String &dirname, const String &fname_regex,
512  std::vector<struct dirent> &listing) {
513  int ret;
514  DIR *dirp = opendir(dirname.c_str());
515  struct dirent de, *dep;
516  boost::shared_ptr<RE2> regex(fname_regex.length()
517  ? new RE2(fname_regex)
518  : 0);
519 
520  do {
521  if ((ret = readdir_r(dirp, &de, &dep)) != 0)
522  HT_FATALF("Problem reading directory '%s' - %s", dirname.c_str(),
523  strerror(errno));
524 
525  if (dep != 0 && (!regex || RE2::FullMatch(de.d_name, *regex)))
526  listing.push_back(de);
527  } while (dep != 0);
528 
529  (void)closedir(dirp);
530 }
531 
532 
static std::mutex mutex
Definition: Logger.cc:43
static char * file_to_buffer(const String &fname, off_t *lenp)
Reads a full file into a new buffer; the buffer is allocated with operator new[], and the caller has ...
Definition: FileUtils.cc:282
#define HT_WARNF(msg,...)
Definition: Logger.h:290
static std::mutex ms_mutex
Mutex for protecting thread-unsafe glibc library function calls.
Definition: FileUtils.h:269
static bool read(const String &fname, String &contents)
Reads a whole file into a String.
Definition: FileUtils.cc:59
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
static bool unlink(const String &fname)
Unlinks (deletes) a file or directory.
Definition: FileUtils.cc:427
static off_t length(const String &fname)
Returns the size of a file (-1 on error)
Definition: FileUtils.cc:458
Po::typed_value< String > * str(String *v=0)
Definition: Properties.h:166
static ssize_t write(const String &fname, const std::string &contents)
Writes a String buffer to a file; the file is overwritten if it already exists.
Definition: FileUtils.cc:124
static void add_trailing_slash(String &path)
Adds a trailing slash to a path.
Definition: FileUtils.cc:466
static bool exists(const String &fname)
Checks if a file or directory exists.
Definition: FileUtils.cc:420
STL namespace.
static bool mkdirs(const String &dirname)
Creates a directory (with all parent directories, if required)
Definition: FileUtils.cc:366
static ssize_t recvfrom(int fd, void *vptr, size_t n, struct sockaddr *from, socklen_t *fromlen)
Receives data from a network connection and returns the sender's address.
Definition: FileUtils.cc:227
static ssize_t pread(int fd, void *vptr, size_t n, off_t offset)
Reads positional data from a file descriptor into a buffer.
Definition: FileUtils.cc:97
static ssize_t sendto(int fd, const void *vptr, size_t n, const sockaddr *to, socklen_t tolen)
Sends data through a network connection; if the socket is TCP then the address is ignored...
Definition: FileUtils.cc:178
static ssize_t send(int fd, const void *vptr, size_t n)
Sends data through a network connection.
Definition: FileUtils.cc:203
static uint64_t size(const String &fname)
Returns the size of a file (0 on error)
Definition: FileUtils.cc:450
File system utility functions.
Logging routines and macros.
Compatibility Macros for C/C++.
#define HT_END
Definition: Logger.h:220
#define HT_ERROR_OUT
Definition: Logger.h:301
static bool expand_tilde(String &fname)
Expands a leading tilde character in a filename.
Definition: FileUtils.cc:472
static bool set_flags(int fd, int flags)
Sets fcntl flags of a socket.
Definition: FileUtils.cc:256
Hypertable definitions
static void readdir(const String &dirname, const String &fname_regex, std::vector< struct dirent > &listing)
Reads all directory entries, applies a regular expression and returns those which match...
Definition: FileUtils.cc:511
#define HT_FATALF(msg,...)
Definition: Logger.h:343
static void * mmap(const String &fname, off_t *lenp)
Maps a full file into memory using mmap; the mapping will be released when the application terminates...
Definition: FileUtils.cc:343
static ssize_t writev(int fd, const struct iovec *vector, int count)
Atomically writes data from multiple buffers to a file descriptor.
Definition: FileUtils.cc:162
#define HT_ERRORF(msg,...)
Definition: Logger.h:300
static bool rename(const String &oldpath, const String &newpath)
Renames a file or directory.
Definition: FileUtils.cc:438
static ssize_t recv(int fd, void *vptr, size_t n)
Receives data from a network connection.
Definition: FileUtils.cc:242
static String file_to_string(const String &fname)
Reads a full file into a String.
Definition: FileUtils.cc:333