FileUtils.cc

Go to the documentation of this file.
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;/* and call read() again */
00082       else if (errno == EAGAIN)
00083         break;
00084       else {
00085         return -1;
00086       }
00087     } else if (nread == 0)
00088       break;/* EOF */
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;/* and call read() again */
00109       else if (errno == EAGAIN)
00110         break;
00111       else {
00112         return -1;
00113       }
00114     } else if (nread == 0)
00115       break;/* EOF */
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; /* and call write() again */
00154       else if (errno == EAGAIN)
00155         break;
00156       else {
00157         return -1; /* error */
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; /* and call write() again */
00172     else if (errno == EAGAIN) {
00173       nwritten = 0;
00174       break;
00175     }
00176     else {
00177       return -1; /* error */
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; /* and call sendto() again */
00197       else if (errno == EAGAIN || errno == ENOBUFS)
00198         break;
00199       else {
00200         return -1; /* error */
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; /* and call sendto() again */
00223       else if (errno == EAGAIN || errno == ENOBUFS)
00224         break;
00225       else {
00226         return -1; /* error */
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 /* flags are file status flags to turn on */
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