00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <dirent.h>
00036 #include <unistd.h>
00037 #include <utime.h>
00038 #include <errno.h>
00039 #include <iostream>
00040 #include <sstream>
00041 #include <cstdio>
00042 #include <cstdlib>
00043 #include <fcntl.h>
00044 #include <algorithm>
00045 #include "maceConfig.h"
00046 #include "mace-macros.h"
00047 #include "Accumulator.h"
00048 #include "Log.h"
00049 #include "FileUtil.h"
00050 #include "Util.h"
00051 #include "StrUtil.h"
00052 #include "Replay.h"
00053
00054 #ifdef WINDOWS_FILES
00055 #define lstat stat
00056 #define ELOOP ENOENT
00057 #endif
00058
00059 using namespace std;
00060
00061 const int FileUtil::STDIN;
00062 const int FileUtil::STDOUT;
00063 const int FileUtil::STDERR;
00064 const int FileUtil::READ_INDEX;
00065 const int FileUtil::WRITE_INDEX;
00066
00067
00068 int FileUtil::open(const std::string& path, int flags, mode_t mode)
00069 throw(FileException) {
00070 ADD_SELECTORS("FileUtil::open");
00071
00072 int fd = ::open(path.c_str(), flags, mode);
00073 if (fd < 0) {
00074 Log::perror("open " + path);
00075 throwFileException("open", errno, path);
00076 }
00077
00078 traceout << fd << Log::end;
00079
00080 return fd;
00081 }
00082
00083 int FileUtil::open(const std::string& path, int flags) throw(FileException) {
00084 ADD_SELECTORS("FileUtil::open");
00085 int fd = ::open(path.c_str(), flags);
00086 if (fd < 0) {
00087 Log::perror("open " + path);
00088 throwFileException("open", errno, path);
00089 }
00090
00091 traceout << fd << Log::end;
00092
00093 return fd;
00094 }
00095
00096 void FileUtil::ftruncate(int fd, off_t length) throw(FileException) {
00097
00098 int r = ::ftruncate(fd, length);
00099 if (r < 0) {
00100 Log::perror("ftruncate " + boost::lexical_cast<std::string>(fd));
00101 throwFileException("ftruncate", errno, boost::lexical_cast<std::string>(fd));
00102 }
00103 }
00104
00105 void FileUtil::mkdir(const std::string& path, mode_t mode, bool createParents)
00106 throw(FileException) {
00107
00108 ADD_SELECTORS("FileUtil::mkdir");
00109
00110
00111 if (createParents) {
00112 struct stat sbuf;
00113 bool found = true;
00114 try {
00115 statWithErr(path, sbuf);
00116 }
00117 catch (const FileNotFoundException& e) {
00118 found = false;
00119 }
00120
00121 if (found) {
00122 if (S_ISDIR(sbuf.st_mode) && ((sbuf.st_mode & mode) == mode)) {
00123
00124 return;
00125 }
00126 }
00127
00128 mace::string p;
00129 StringList l = StrUtil::split("/", path, true);
00130 while (!l.empty() && l.back().empty()) {
00131
00132 l.pop_back();
00133 }
00134 if (!l.empty()) {
00135 l.pop_back();
00136 }
00137
00138 while (!l.empty()) {
00139
00140 if (l.front().empty() && p[p.size() - 1] != '/') {
00141 p.append("/");
00142 }
00143 else {
00144 p.append(l.front());
00145 }
00146 l.pop_front();
00147 try {
00148
00149 statWithErr(p, sbuf);
00150
00151 }
00152 catch (const FileNotFoundException& e) {
00153
00154 mkdir(p, mode, false);
00155 }
00156 if (p != "/") {
00157 p.append("/");
00158 }
00159
00160 }
00161 }
00162
00163
00164 #ifdef WINDOWS_FILES
00165 int r = ::mkdir(path.c_str());
00166 if (r >= 0) {
00167 chmod(path, mode);
00168 }
00169 #else
00170 int r = ::mkdir(path.c_str(), mode);
00171 #endif
00172 if (r < 0) {
00173 Log::perror("mkdir " + path);
00174 throwFileException("mkdir", errno, path);
00175 }
00176
00177 }
00178
00179 void FileUtil::chdir(const std::string& path) throw(FileException) {
00180 if (::chdir(path.c_str()) != 0) {
00181 throwFileException("chdir", errno, path);
00182 }
00183 }
00184
00185 int FileUtil::mktemp(std::string& name) throw(FileException) {
00186
00187 size_t s = name.size();
00188 char* buf = new char[s + 1];
00189 memcpy(buf, name.data(), s);
00190 buf[s] = 0;
00191 #ifdef WINDOWS_FILES
00192 int r = -1;
00193 if (::mktemp(buf) == NULL) {
00194 r = open(buf, O_RDWR);
00195 }
00196 #else
00197 int r = mkstemp(buf);
00198 #endif
00199 if (r == -1) {
00200 delete buf;
00201 throwFileException("mkstemp", errno, name);
00202 }
00203 name.clear();
00204 name.append(buf, s);
00205 delete buf;
00206 return r;
00207 }
00208
00209 void FileUtil::rename(const std::string& oldpath, const std::string& newpath) throw(FileException) {
00210 if (::rename(oldpath.c_str(), newpath.c_str()) != 0) {
00211 throwFileException("rename", errno, oldpath + " -> " + newpath);
00212 }
00213 }
00214
00215 void FileUtil::symlink(const std::string& oldpath, const std::string& newpath) throw(FileException) {
00216 #ifdef WINDOWS_FILES
00217 ABORT("Windows builds don't support symlinking yet.");
00218 #else
00219 if (::symlink(oldpath.c_str(), newpath.c_str()) != 0) {
00220 throwFileException("symlink", errno, oldpath + " -> " + newpath);
00221 }
00222 #endif
00223 }
00224
00225 void FileUtil::unlink(const std::string& path) throw(FileException) {
00226
00227 if (::unlink(path.c_str()) != 0) {
00228 throwFileException("unlink", errno, path);
00229 }
00230 }
00231
00232 void FileUtil::rmdir(const std::string& path) throw(FileException) {
00233 if (::rmdir(path.c_str()) != 0) {
00234 throwFileException("rmdir", errno, path);
00235 }
00236 }
00237
00238 void FileUtil::chmod(const std::string& path, mode_t mode) throw(FileException) {
00239 if (::chmod(path.c_str(), mode) != 0) {
00240 throwFileException("chmod", errno, path);
00241 }
00242 }
00243
00244 void FileUtil::fchmod(int fd, mode_t mode) throw(FileException) {
00245 #ifdef WINDOWS_FILES
00246 ABORT("Windows builds do not support fchmod!\n");
00247 #else
00248 if (::fchmod(fd, mode) != 0) {
00249 throwFileException("chmod", errno, boost::lexical_cast<std::string>(fd));
00250 }
00251 #endif
00252 }
00253
00254 void FileUtil::utime(const std::string& path, time_t mtime) throw(FileException) {
00255 utime(path, mtime, TimeUtil::time());
00256 }
00257
00258 void FileUtil::utime(const std::string& path, time_t mtime, time_t atime) throw(FileException) {
00259 struct utimbuf tbuf = { atime, mtime };
00260 if (::utime(path.c_str(), &tbuf) != 0) {
00261 throwFileException("utime", errno, path);
00262 }
00263 }
00264
00265 int FileUtil::close(int fd) {
00266 ADD_SELECTORS("FileUtil::close");
00267 int r = ::close(fd);
00268 traceout << r << Log::end;
00269 return r;
00270 }
00271
00272 void FileUtil::readDir(const std::string& path, StringList& dirlist, bool sort)
00273 throw (FileException) {
00274 ADD_SELECTORS("FileUtil::readDir");
00275 DIR* d = opendir(path.c_str());
00276 if (d == 0) {
00277 Log::perror("opendir " + path);
00278 throw FileException(getErrorMessage(errno, "opendir", path));
00279 }
00280
00281 struct dirent* ent;
00282 while ((ent = ::readdir(d))) {
00283 if ((strcmp(ent->d_name, ".") == 0) ||
00284 (strcmp(ent->d_name, "..") == 0)) {
00285 continue;
00286 }
00287
00288 dirlist.push_back(ent->d_name);
00289 }
00290
00291 if (sort) {
00292 stable_sort(dirlist.begin(), dirlist.end());
00293 }
00294
00295 closedir(d);
00296
00297 traceout << dirlist << Log::end;
00298 }
00299
00300 std::string FileUtil::loadFile(const std::string& path) throw(FileException) {
00301 ADD_SELECTORS("FileUtil::loadFile");
00302
00303 struct stat sbuf;
00304 statWithErr(path, sbuf);
00305
00306 int fd = ::open(path.c_str(), O_RDONLY);
00307 if (fd < 0) {
00308 throw FileException(getErrorMessage(errno, "open", path));
00309 }
00310
00311 mace::string r = bufferedRead(fd, sbuf.st_size);
00312 close(fd);
00313
00314 traceout << r << Log::end;
00315
00316 return r;
00317 }
00318
00319 void FileUtil::saveFile(const std::string& path, const std::string& data,
00320 const std::string& bak, bool removeBak) throw(FileException) {
00321
00322 if (fileIsReg(path) && !bak.empty()) {
00323 rename(path, bak);
00324 }
00325
00326 int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
00327 if (fd < 0) {
00328 throw FileException(getErrorMessage(errno, "open", path));
00329 }
00330
00331 write(fd, data);
00332
00333 close(fd);
00334
00335 if (!bak.empty() && removeBak && fileIsReg(bak)) {
00336 unlink(bak);
00337 }
00338 }
00339
00340 bool FileUtil::fileIsReg(const std::string& path, bool doLstat) {
00341 ADD_SELECTORS("FileUtil::fileIsReg");
00342 struct stat buf;
00343 if (doLstat) {
00344 if (::lstat(path.c_str(), &buf) < 0) {
00345 traceout << false << Log::end;
00346 return false;
00347 }
00348 }
00349 else {
00350 if (::stat(path.c_str(), &buf) < 0) {
00351 traceout << false << Log::end;
00352 return false;
00353 }
00354 }
00355
00356 traceout << S_ISREG(buf.st_mode) << Log::end;
00357
00358 return S_ISREG(buf.st_mode);
00359 }
00360
00361 bool FileUtil::fileIsDir(const std::string& path, bool doLstat) {
00362 ADD_SELECTORS("FileUtil::fileIsDir");
00363 struct stat buf;
00364 if (doLstat) {
00365 if (::lstat(path.c_str(), &buf) < 0) {
00366 traceout << false << Log::end;
00367 return false;
00368 }
00369 }
00370 else {
00371 if (::stat(path.c_str(), &buf) < 0) {
00372 traceout << false << Log::end;
00373 return false;
00374 }
00375 }
00376 traceout << S_ISDIR(buf.st_mode) << Log::end;
00377 return S_ISDIR(buf.st_mode);
00378 }
00379
00380 bool FileUtil::fileIsLink(const std::string& path) {
00381 #ifdef WINDOWS_FILES
00382 return false;
00383 #else
00384 ADD_SELECTORS("FileUtil::fileIsLink");
00385 struct stat buf;
00386 if (::lstat(path.c_str(), &buf) < 0) {
00387 traceout << false << Log::end;
00388 return false;
00389 }
00390 traceout << S_ISLNK(buf.st_mode) << Log::end;
00391 return S_ISLNK(buf.st_mode);
00392 #endif
00393 }
00394
00395 bool FileUtil::fileExists(const std::string& path, bool doLstat) {
00396 ADD_SELECTORS("FileUtil::fileExists");
00397 struct stat buf;
00398 if (doLstat) {
00399 if (::lstat(path.c_str(), &buf) < 0) {
00400 traceout << false << Log::end;
00401 return false;
00402 }
00403 }
00404 else {
00405 if (::stat(path.c_str(), &buf) < 0) {
00406 traceout << false << Log::end;
00407 return false;
00408 }
00409 }
00410 traceout << true << Log::end;
00411 return true;
00412 }
00413
00414 FileUtil::AccessResult FileUtil::canAccess(const std::string& path, int mode)
00415 throw (FileException) {
00416 ADD_SELECTORS("FileUtil::canAccess");
00417
00418 int r = access(path.c_str(), mode);
00419 if (r < 0) {
00420 int err = errno;
00421 if ((err == ELOOP) ||
00422 (err == ENOTDIR) ||
00423 (err == ENAMETOOLONG) ||
00424 (err == ENOENT) ||
00425 (err == EROFS)) {
00426 traceout << false << false << mace::string(Util::getErrorString(err)) << Log::end;
00427 return AccessResult(false, false, Util::getErrorString(err));
00428 }
00429 else if (err == EACCES) {
00430 traceout << false << true << mace::string(Util::getErrorString(err)) << Log::end;
00431 return AccessResult(false, true, Util::getErrorString(err));
00432 }
00433
00434 throwFileException("access", err, path);
00435 }
00436
00437 traceout << true << true << Log::end;
00438 return AccessResult(true, true, "");
00439 }
00440
00441 string FileUtil::realpath(const string& path) throw (FileException) {
00442 #ifndef MAX_PATH
00443 static const int MAX_PATH = 1028;
00444 #endif
00445
00446 ADD_SELECTORS("FileUtil::realpath");
00447 char buf[MAX_PATH + 1];
00448 #ifdef WINDOWS_FILES
00449 if ((GetFullPathName(path.c_str(), MAX_PATH, buf, NULL) == 0)) {
00450 throwFileException("GetFullPathName", errno, path);
00451 }
00452 #else
00453 if ((::realpath(path.c_str(), buf) == 0)) {
00454 throwFileException("realpath", errno, path);
00455 }
00456 #endif
00457 return buf;
00458 }
00459
00460 string FileUtil::getErrorMessage(int err, const string& syscall, const string& path) {
00461 string errstr = syscall + " " + path + ": " + Util::getErrorString(err);
00462 return errstr;
00463 }
00464
00465 string FileUtil::getErrorString(int err, const string& n, int fd) {
00466 ostringstream errstr;
00467 errstr << n << ": " << Util::getErrorString(err) << " on " << fd;
00468 return errstr.str();
00469 }
00470
00471 void FileUtil::throwFileException(const string& prefix,
00472 int err, const string& path)
00473 throw (FileException) {
00474 string errstr = getErrorMessage(err, prefix, path);
00475
00476 if (err == ENOENT) {
00477
00478 throw FileNotFoundException(errstr);
00479 }
00480 else if (err == ENOTDIR) {
00481
00482 throw InvalidPathException(errstr);
00483 }
00484 else if (err == EACCES) {
00485
00486 throw PermissionAccessException(errstr);
00487 }
00488 else if (err == ELOOP) {
00489
00490 throw LinkLoopException(errstr);
00491 }
00492 else{
00493
00494 throw FileException(errstr);
00495 }
00496 }
00497
00498 void FileUtil::lstatWithErr(const mace::string& path, struct stat& buf)
00499 throw (FileException) {
00500 ADD_SELECTORS("FileUtil::lstatWithErr");
00501 if (::lstat(path.c_str(), &buf) < 0) {
00502 traceout << false << errno << path << Log::end;
00503 throwFileException("lstat", errno, path);
00504 }
00505
00506 }
00507
00508 void FileUtil::statWithErr(const mace::string& path, struct stat& buf)
00509 throw (FileException) {
00510 ADD_SELECTORS("FileUtil::statWithErr");
00511 if (::stat(path.c_str(), &buf) < 0) {
00512 traceout << false << errno << path << Log::end;
00513 throwFileException("stat", errno, path);
00514 }
00515
00516 }
00517
00518 void FileUtil::fstatWithErr(int fd, struct stat& buf)
00519 throw (FileException) {
00520 ADD_SELECTORS("FileUtil::fstatWithErr");
00521 if (::fstat(fd, &buf) < 0) {
00522
00523 throwFileException("fstat", errno, boost::lexical_cast<std::string>(fd));
00524 }
00525
00526 }
00527
00528 off_t FileUtil::seek(int fd, off_t offset, int whence) throw (FileException) {
00529 ADD_SELECTORS("FileUtil::seek");
00530 off_t r = ::lseek(fd, offset, whence);
00531 if (r == (off_t)-1) {
00532
00533 throwFileException("lseek", errno, boost::lexical_cast<std::string>(fd));
00534 }
00535
00536 return r;
00537 }
00538
00539 void FileUtil::write(int fd, const string& buf, bool log) throw (WriteException) {
00540 fullWrite(fd, buf.data(), buf.size(), log);
00541 }
00542
00543 void FileUtil::fullWrite(int desc, const char *ptr, size_t len, bool log)
00544 throw (WriteException) {
00545 while (len > 0) {
00546 int written = ::write(desc, ptr, len);
00547 if (written < 0) {
00548 int err = errno;
00549 if (err == EINTR) {
00550 continue;
00551 }
00552 else if (err == EPIPE) {
00553 ostringstream os;
00554 os << "EPIPE error writing to " << desc;
00555 throw PipeClosedException(os.str());
00556 }
00557 Log::perror("write");
00558 throw WriteException(getErrorString(err, "write", desc));
00559 }
00560 ptr += written;
00561 len -= written;
00562 if (log) {
00563 Accumulator::Instance(Accumulator::FILE_WRITE)->accumulate(written);
00564 }
00565 }
00566 }
00567
00568 string FileUtil::read(int s) throw (ReadException) {
00569 mace::string sr;
00570 read(s, sr);
00571 return sr;
00572 }
00573
00574 size_t FileUtil::read(int s, mace::string& sr) throw (ReadException) {
00575 ADD_SELECTORS("FileUtil::read");
00576 const size_t BUF_SIZE = 8192;
00577 char buf[BUF_SIZE];
00578 int rc = 0;
00579 do {
00580 rc = ::read(s, buf, BUF_SIZE);
00581 } while (rc < 0 && errno == EINTR);
00582
00583 if (rc < 0) {
00584 traceout << false << errno << s << sr << Log::end;
00585 throw ReadException(getErrorString(errno, "read", s));
00586 }
00587 sr.append(buf, rc);
00588 traceout << true << rc << sr << Log::end;
00589 return rc;
00590 }
00591
00592 size_t FileUtil::bufferedRead(int32_t s, mace::string& sr, size_t len, bool clear) throw (ReadException) {
00593 ADD_SELECTORS("FileUtil::bufferedRead");
00594 if (clear) {
00595 sr.clear();
00596 }
00597 if (len == 0) {
00598 return 0;
00599 }
00600 size_t r = 0;
00601 const size_t BUF_SIZE = 8192;
00602 char buf[BUF_SIZE];
00603 while (r < len) {
00604 size_t rlen = BUF_SIZE;
00605 if ((len - r) < BUF_SIZE) {
00606 rlen = len - r;
00607 }
00608 ssize_t rc = ::read(s, buf, rlen);
00609 if (rc < 0 && errno == EINTR) {
00610 continue;
00611 }
00612 if (rc < 0) {
00613 traceout << false << errno << s << sr << Log::end;
00614 throw ReadException(getErrorString(errno, "read", s));
00615 }
00616 if (rc == 0) {
00617 traceout << true << ((uint32_t)r) << sr << Log::end;
00618 return r;
00619 }
00620 r += rc;
00621 sr.append(buf, rc);
00622 }
00623 ASSERT(r == len);
00624 traceout << true << ((uint32_t)r) << sr << Log::end;
00625 return r;
00626 }
00627
00628 string FileUtil::bufferedRead(int s, size_t len) throw (ReadException) {
00629 mace::string sr;
00630 bufferedRead(s, sr, len);
00631 return sr;
00632 }
00633
00634 int FileUtil::read(int fd, char* buf, size_t count) {
00635 ADD_SELECTORS("FileUtil::read");
00636 int r = ::read(fd, buf, count);
00637 if (Replay::trace()) {
00638 traceout << r;
00639 if (r > 0) {
00640 mace::string s(buf, r);
00641 traceout << s;
00642 }
00643 traceout << Log::end;
00644 }
00645 return r;
00646 }
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669 void FileUtil::remapPipeStdinStdout(pipefdpair_t p2c, pipefdpair_t c2p)
00670 throw (IOException) {
00671
00672 close(p2c[WRITE_INDEX]);
00673 close(c2p[READ_INDEX]);
00674
00675 close(STDIN);
00676 close(STDOUT);
00677
00678 remapPipeStdinStdout(p2c[READ_INDEX], c2p[WRITE_INDEX]);
00679 }
00680
00681
00682
00683
00684 void FileUtil::remapPipeStdinStdout(int rpipe, int wpipe) throw (IOException) {
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 if ((rpipe == STDIN) && (wpipe == STDOUT)) {
00755 return;
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 if ((rpipe >= 1) && (wpipe > 1)) {
00768 dup2close(rpipe, STDIN);
00769 dup2close(wpipe, STDOUT);
00770 return;
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781 if ((rpipe == STDIN) && (wpipe >= 1)) {
00782 dup2close(wpipe, STDOUT);
00783 return;
00784 }
00785
00786 if ((rpipe >= 1) && (wpipe == STDOUT)) {
00787 dup2close(rpipe, STDIN);
00788 return;
00789 }
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 if ((rpipe >= 1) && (wpipe == STDIN)) {
00801 dup2close(wpipe, STDOUT);
00802 dup2close(rpipe, STDIN);
00803 return;
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813 if ((rpipe == STDOUT) && (wpipe == STDIN)) {
00814 const int tmp = dup(wpipe);
00815
00816 if (tmp <= 1) {
00817 throw IOException(getErrorString(errno, "dup", tmp));
00818 }
00819
00820 if (close(wpipe) < 0) {
00821 throw IOException(getErrorString(errno, "close", wpipe));
00822 }
00823
00824 dup2close(rpipe, STDIN);
00825 dup2close(tmp, STDOUT);
00826
00827 return;
00828 }
00829
00830
00831
00832 ASSERT(false);
00833 }
00834
00835 void FileUtil::dup2close(int oldfd, int newfd) throw (IOException) {
00836 if (dup2(oldfd, newfd) < 0) {
00837 throw IOException(getErrorString(errno, "dup2", oldfd));
00838 }
00839
00840 if (close(oldfd) < 0) {
00841 throw IOException(getErrorString(errno, "close", oldfd));
00842 }
00843 }
00844
00845 std::string FileUtil::basename(const std::string& buf) {
00846 size_t i = buf.rfind("/");
00847 if (i != string::npos) {
00848 return buf.substr(i+1);
00849 }
00850 return buf;
00851 }
00852
00853 std::string FileUtil::dirname(const std::string& buf) {
00854 size_t i = buf.rfind("/");
00855 if (i != string::npos) {
00856 while (i >= 0 && buf[i] == '/') {
00857 i--;
00858 }
00859 if (i >= 0) {
00860 return buf.substr(0,i+1);
00861 } else {
00862 return "/";
00863 }
00864 }
00865 return ".";
00866 }
00867
00868 std::string FileUtil::readlink(const std::string& path) throw (FileException) {
00869 ADD_SELECTORS("FileUtil::readlink");
00870 int lbufSize = PATH_MAX;
00871 char lbuf[lbufSize];
00872 #ifdef WINDOWS_FILES
00873 int r = EINVAL;
00874 #else
00875 int r = ::readlink(path.c_str(), lbuf, lbufSize);
00876 #endif
00877 if (r < 0) {
00878 throwFileException("readlink", errno, path);
00879 }
00880 mace::string s(lbuf, r);
00881
00882 return s;
00883 }