00001
00022 #include "Common/Compat.h"
00023
00024 #include <iomanip>
00025 #include <iostream>
00026 #include <sstream>
00027
00028 extern "C" {
00029 #include <unistd.h>
00030 #include <errno.h>
00031 #include <pwd.h>
00032 #include <fcntl.h>
00033 #include <sys/stat.h>
00034 #include <sys/types.h>
00035 #include <sys/uio.h>
00036 #ifdef HT_XATTR_ENABLED
00037 # if defined(__FreeBSD__)
00038 # include <sys/extattr.h>
00039 # else
00040 # include <sys/xattr.h>
00041 # endif
00042 # if defined(__linux__)
00043 # include <attr/xattr.h>
00044 # endif
00045 #endif
00046 }
00047
00048 #include <boost/shared_array.hpp>
00049
00050 #include "FileUtils.h"
00051 #include "Logger.h"
00052
00053 using namespace Hypertable;
00054 using namespace std;
00055
00056 ssize_t FileUtils::read(const String &fname, String &contents) {
00057 off_t len = 0;
00058 String str;
00059 char *buf = file_to_buffer(fname, &len);
00060 if (buf != 0) {
00061 contents.append(buf, len);
00062 delete [] buf;
00063 }
00064 return (ssize_t)len;
00065 }
00066
00067
00068
00071 ssize_t FileUtils::read(int fd, void *vptr, size_t n) {
00072 size_t nleft;
00073 ssize_t nread;
00074 char *ptr;
00075
00076 ptr = (char *)vptr;
00077 nleft = n;
00078 while (nleft > 0) {
00079 if ((nread = ::read(fd, ptr, nleft)) < 0) {
00080 if (errno == EINTR)
00081 nread = 0;
00082 else if (errno == EAGAIN)
00083 break;
00084 else {
00085 return -1;
00086 }
00087 } else if (nread == 0)
00088 break;
00089
00090 nleft -= nread;
00091 ptr += nread;
00092 }
00093 return n - nleft;
00094 }
00095
00098 ssize_t FileUtils::pread(int fd, void *vptr, size_t n, off_t offset) {
00099 size_t nleft;
00100 ssize_t nread;
00101 char *ptr;
00102
00103 ptr = (char *)vptr;
00104 nleft = n;
00105 while (nleft > 0) {
00106 if ((nread = ::pread(fd, ptr, nleft, offset)) < 0) {
00107 if (errno == EINTR)
00108 nread = 0;
00109 else if (errno == EAGAIN)
00110 break;
00111 else {
00112 return -1;
00113 }
00114 } else if (nread == 0)
00115 break;
00116
00117 nleft -= nread;
00118 ptr += nread;
00119 offset += nread;
00120 }
00121 return n - nleft;
00122 }
00123
00124
00125 ssize_t FileUtils::write(const String &fname, String &contents) {
00126 int fd = open(fname.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
00127 if (fd < 0) {
00128 int saved_errno = errno;
00129 HT_ERRORF("Unable to open file \"%s\" for writing - %s", fname.c_str(),
00130 strerror(saved_errno));
00131 errno = saved_errno;
00132 return -1;
00133 }
00134 ssize_t rval = write(fd, contents.c_str(), contents.length());
00135 ::close(fd);
00136 return rval;
00137 }
00138
00139
00140
00143 ssize_t FileUtils::write(int fd, const void *vptr, size_t n) {
00144 size_t nleft;
00145 ssize_t nwritten;
00146 const char *ptr;
00147
00148 ptr = (const char *)vptr;
00149 nleft = n;
00150 while (nleft > 0) {
00151 if ((nwritten = ::write(fd, ptr, nleft)) <= 0) {
00152 if (errno == EINTR)
00153 nwritten = 0;
00154 else if (errno == EAGAIN)
00155 break;
00156 else {
00157 return -1;
00158 }
00159 }
00160
00161 nleft -= nwritten;
00162 ptr += nwritten;
00163 }
00164 return n - nleft;
00165 }
00166
00167 ssize_t FileUtils::writev(int fd, const struct iovec *vector, int count) {
00168 ssize_t nwritten;
00169 while ((nwritten = ::writev(fd, vector, count)) <= 0) {
00170 if (errno == EINTR)
00171 nwritten = 0;
00172 else if (errno == EAGAIN) {
00173 nwritten = 0;
00174 break;
00175 }
00176 else {
00177 return -1;
00178 }
00179 }
00180 return nwritten;
00181 }
00182
00183
00184 ssize_t
00185 FileUtils::sendto(int fd, const void *vptr, size_t n, const sockaddr *to,
00186 socklen_t tolen) {
00187 size_t nleft;
00188 ssize_t nsent;
00189 const char *ptr;
00190
00191 ptr = (const char *)vptr;
00192 nleft = n;
00193 while (nleft > 0) {
00194 if ((nsent = ::sendto(fd, ptr, nleft, 0, to, tolen)) <= 0) {
00195 if (errno == EINTR)
00196 nsent = 0;
00197 else if (errno == EAGAIN || errno == ENOBUFS)
00198 break;
00199 else {
00200 return -1;
00201 }
00202 }
00203
00204 nleft -= nsent;
00205 ptr += nsent;
00206 }
00207 return n - nleft;
00208 }
00209
00210
00211
00212 ssize_t FileUtils::send(int fd, const void *vptr, size_t n) {
00213 size_t nleft;
00214 ssize_t nsent;
00215 const char *ptr;
00216
00217 ptr = (const char *)vptr;
00218 nleft = n;
00219 while (nleft > 0) {
00220 if ((nsent = ::send(fd, ptr, nleft, 0)) <= 0) {
00221 if (errno == EINTR)
00222 nsent = 0;
00223 else if (errno == EAGAIN || errno == ENOBUFS)
00224 break;
00225 else {
00226 return -1;
00227 }
00228 }
00229
00230 nleft -= nsent;
00231 ptr += nsent;
00232 }
00233 return n - nleft;
00234 }
00235
00236
00237
00238 ssize_t
00239 FileUtils::recvfrom(int fd, void *vptr, size_t n, sockaddr *from,
00240 socklen_t *fromlen) {
00241 ssize_t nread;
00242 while (true) {
00243 if ((nread = ::recvfrom(fd, vptr, n, 0, from, fromlen)) < 0) {
00244 if (errno != EINTR)
00245 break;
00246 }
00247 else
00248 break;
00249 }
00250 return nread;
00251 }
00252
00253
00254 ssize_t FileUtils::recv(int fd, void *vptr, size_t n) {
00255 ssize_t nread;
00256 while (true) {
00257 if ((nread = ::recv(fd, vptr, n, 0)) < 0) {
00258 if (errno != EINTR)
00259 break;
00260 }
00261 else
00262 break;
00263 }
00264 return nread;
00265 }
00266
00267
00268
00269 void FileUtils::set_flags(int fd, int flags) {
00270 int val;
00271
00272 if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
00273 int saved_errno = errno;
00274 cerr << "fcnt(F_GETFL) failed : " << strerror(saved_errno) << endl;
00275 errno = saved_errno;
00276 }
00277
00278 val |= flags;
00279
00280 if (fcntl(fd, F_SETFL, val) < 0) {
00281 int saved_errno = errno;
00282 cerr << "fcnt(F_SETFL) failed : " << strerror(saved_errno) << endl;
00283 errno = saved_errno;
00284 }
00285 }
00286
00287
00288
00291 char *FileUtils::file_to_buffer(const String &fname, off_t *lenp) {
00292 struct stat statbuf;
00293 int fd;
00294
00295 *lenp = 0;
00296
00297 if ((fd = open(fname.c_str(), O_RDONLY)) < 0) {
00298 int saved_errno = errno;
00299 HT_ERRORF("open(\"%s\") failure - %s", fname.c_str(), strerror(saved_errno));
00300 errno = saved_errno;
00301 return 0;
00302 }
00303
00304 if (fstat(fd, &statbuf) < 0) {
00305 int saved_errno = errno;
00306 HT_ERRORF("fstat(\"%s\") failure - %s", fname.c_str(), strerror(saved_errno));
00307 errno = saved_errno;
00308 return 0;
00309 }
00310
00311 *lenp = statbuf.st_size;
00312
00313 char *rbuf = new char [*lenp + 1];
00314
00315 ssize_t nread = FileUtils::read(fd, rbuf, *lenp);
00316
00317 ::close(fd);
00318
00319 if (nread == (ssize_t)-1) {
00320 int saved_errno = errno;
00321 HT_ERRORF("read(\"%s\") failure - %s", fname.c_str(), strerror(saved_errno));
00322 errno = saved_errno;
00323 delete [] rbuf;
00324 *lenp = 0;
00325 return 0;
00326 }
00327
00328 if (nread < *lenp) {
00329 HT_WARNF("short read (%d of %d bytes)", (int)nread, (int)*lenp);
00330 *lenp = nread;
00331 }
00332
00333 rbuf[nread] = 0;
00334
00335 return rbuf;
00336 }
00337
00338 String FileUtils::file_to_string(const String &fname) {
00339 String str;
00340 off_t len;
00341 char *contents = file_to_buffer(fname, &len);
00342 str = (contents == 0) ? "" : contents;
00343 delete [] contents;
00344 return str;
00345 }
00346
00347
00348
00349 bool FileUtils::mkdirs(const String &dirname) {
00350 struct stat statbuf;
00351 boost::shared_array<char> tmp_dir(new char [dirname.length() + 1]);
00352 char *tmpdir = tmp_dir.get();
00353 char *ptr = tmpdir+1;
00354
00355 strcpy(tmpdir, dirname.c_str());
00356
00357 while ((ptr = strchr(ptr, '/')) != 0) {
00358 *ptr = 0;
00359 if (stat(tmpdir, &statbuf) != 0) {
00360 if (errno == ENOENT) {
00361 if (mkdir(tmpdir, 0755) != 0) {
00362 int saved_errno = errno;
00363 HT_ERRORF("Problem creating directory '%s' - %s",
00364 tmpdir, strerror(saved_errno));
00365 errno = saved_errno;
00366 return false;
00367 }
00368 }
00369 else {
00370 int saved_errno = errno;
00371 HT_ERRORF("Problem stat'ing directory '%s' - %s",
00372 tmpdir, strerror(saved_errno));
00373 errno = saved_errno;
00374 return false;
00375 }
00376 }
00377 *ptr++ = '/';
00378 }
00379
00380 if (stat(tmpdir, &statbuf) != 0) {
00381 if (errno == ENOENT) {
00382 if (mkdir(tmpdir, 0755) != 0) {
00383 int saved_errno = errno;
00384 HT_ERRORF("Problem creating directory '%s' - %s",
00385 tmpdir, strerror(saved_errno));
00386 errno = saved_errno;
00387 return false;
00388 }
00389 }
00390 else {
00391 int saved_errno = errno;
00392 HT_ERRORF("Problem stat'ing directory '%s' - %s",
00393 tmpdir, strerror(saved_errno));
00394 errno = saved_errno;
00395 return false;
00396 }
00397 }
00398
00399 return true;
00400 }
00401
00402
00403 bool FileUtils::exists(const String &fname) {
00404 struct stat statbuf;
00405 if (stat(fname.c_str(), &statbuf) != 0)
00406 return false;
00407 return true;
00408 }
00409
00410 bool FileUtils::unlink(const String &fname) {
00411 if (::unlink(fname.c_str()) == -1) {
00412 int saved_errno = errno;
00413 HT_ERRORF("unlink(\"%s\") failed - %s", fname.c_str(), strerror(saved_errno));
00414 errno = saved_errno;
00415 return false;
00416 }
00417 return true;
00418 }
00419
00420 bool FileUtils::rename(const String &oldpath, const String &newpath) {
00421 if (::rename(oldpath.c_str(), newpath.c_str()) == -1) {
00422 int saved_errno = errno;
00423 HT_ERRORF("rename(\"%s\", \"%s\") failed - %s",
00424 oldpath.c_str(), newpath.c_str(), strerror(saved_errno));
00425 errno = saved_errno;
00426 return false;
00427 }
00428 return true;
00429 }
00430
00431 uint64_t FileUtils::size(const String &fname) {
00432 struct stat statbuf;
00433 if (stat(fname.c_str(), &statbuf) != 0)
00434 return 0;
00435 return statbuf.st_size;
00436
00437 }
00438
00439
00440 off_t FileUtils::length(const String &fname) {
00441 struct stat statbuf;
00442 if (stat(fname.c_str(), &statbuf) != 0)
00443 return (off_t)-1;
00444 return statbuf.st_size;
00445 }
00446
00447
00448 void FileUtils::add_trailing_slash(String &path) {
00449 if (path.find('/', path.length()-1) == string::npos)
00450 path += "/";
00451 }
00452
00453
00454 bool FileUtils::expand_tilde(String &fname) {
00455 struct passwd pbuf;
00456 struct passwd *prbuf;
00457 char buf[256];
00458
00459 if (fname[0] != '~')
00460 return false;
00461
00462 if (fname[1] == '/') {
00463 if (getpwuid_r(getuid() , &pbuf, buf, 256, &prbuf) != 0 || prbuf == 0)
00464 return false;
00465 fname = (String)pbuf.pw_dir + fname.substr(1);
00466 }
00467 else {
00468 String name;
00469 size_t first_slash = fname.find_first_of('/');
00470
00471 if (first_slash == string::npos)
00472 name = fname.substr(1);
00473 else
00474 name = fname.substr(1, first_slash-1);
00475
00476 if (getpwnam_r(name.c_str() , &pbuf, buf, 256, &prbuf) != 0 || prbuf == 0)
00477 return false;
00478
00479 if (first_slash == string::npos)
00480 fname = pbuf.pw_dir;
00481 else
00482 fname = (String)pbuf.pw_dir + fname.substr(first_slash);
00483 }
00484
00485 return true;
00486 }
00487
00488
00489 #ifdef HT_XATTR_ENABLED
00490
00491 int
00492 FileUtils::getxattr(const String &path, const String &name, void *value,
00493 size_t size) {
00494 String canonic = (String)"user." + name;
00495 #if defined(__linux__)
00496 return ::getxattr(path.c_str(), canonic.c_str(), value, size);
00497 #elif defined(__APPLE__)
00498 return ::getxattr(path.c_str(), canonic.c_str(), value, size, 0, 0);
00499 #elif defined(__FreeBSD__)
00500 return ::extattr_get_file(path.c_str(), EXTATTR_NAMESPACE_USER, canonic.c_str(), value, size);
00501 #else
00502 ImplementMe;
00503 #endif
00504 }
00505
00506
00507 int
00508 FileUtils::setxattr(const String &path, const String &name, const void *value,
00509 size_t size, int flags) {
00510 String canonic = (String)"user." + name;
00511 #if defined(__linux__)
00512 return ::setxattr(path.c_str(), canonic.c_str(), value, size, flags);
00513 #elif defined(__APPLE__)
00514 return ::setxattr(path.c_str(), canonic.c_str(), value, size, 0, flags);
00515 #elif defined(__FreeBSD__)
00516 return ::extattr_set_file(path.c_str(), EXTATTR_NAMESPACE_USER, canonic.c_str(), value, size);
00517 #else
00518 ImplementMe;
00519 #endif
00520 }
00521
00522
00523 int FileUtils::fgetxattr(int fd, const String &name, void *value, size_t size) {
00524 String canonic = (String)"user." + name;
00525 #if defined(__linux__)
00526 return ::fgetxattr(fd, canonic.c_str(), value, size);
00527 #elif defined(__APPLE__)
00528 return ::fgetxattr(fd, canonic.c_str(), value, size, 0, 0);
00529 #elif defined(__FreeBSD__)
00530 return ::extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, canonic.c_str(), value, size);
00531 #else
00532 ImplementMe;
00533 #endif
00534 }
00535
00536
00537 int
00538 FileUtils::fsetxattr(int fd, const String &name, const void *value,
00539 size_t size, int flags) {
00540 String canonic = (String)"user." + name;
00541 #if defined(__linux__)
00542 return ::fsetxattr(fd, canonic.c_str(), value, size, flags);
00543 #elif defined(__APPLE__)
00544 return ::fsetxattr(fd, canonic.c_str(), value, size, 0, flags);
00545 #elif defined(__FreeBSD__)
00546 return ::extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, canonic.c_str(), value, size);
00547 #else
00548 ImplementMe;
00549 #endif
00550 }
00551
00552
00553 int FileUtils::removexattr(const String &path, const String &name) {
00554 String canonic = (String)"user." + name;
00555 #if defined(__linux__)
00556 return ::removexattr(path.c_str(), canonic.c_str());
00557 #elif defined(__APPLE__)
00558 return ::removexattr(path.c_str(), canonic.c_str(), 0);
00559 #elif defined(__FreeBSD__)
00560 return ::extattr_delete_file(path.c_str(), EXTATTR_NAMESPACE_USER, canonic.c_str());
00561 #else
00562 ImplementMe;
00563 #endif
00564 }
00565
00566 int FileUtils::fremovexattr(int fd, const String &name) {
00567 String canonic = (String)"user." + name;
00568 #if defined(__linux__)
00569 return ::fremovexattr(fd, canonic.c_str());
00570 #elif defined(__APPLE__)
00571 return ::fremovexattr(fd, canonic.c_str(), 0);
00572 #elif defined(__FreeBSD__)
00573 return ::extattr_delete_fd(fd, EXTATTR_NAMESPACE_USER, canonic.c_str());
00574 #else
00575 ImplementMe;
00576 #endif
00577
00578 }
00579
00580 #endif // HT_XATTR_ENABLED