00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <errno.h>
00020 #include <fcntl.h>
00021 #include <string.h>
00022 #include <sys/stat.h>
00023 #include <unistd.h>
00024 #include <limits.h>
00025 #include <Basics.H>
00026 #include "FS.H"
00027
00028 using std::ios;
00029
00030 static void PrintBanner(std::ostream &os, char c, int num) throw ()
00031 {
00032 os << '\n';
00033 for (int i = 0; i < num; i++) os << c;
00034 os << '\n';
00035 }
00036
00037 std::ostream& operator<<(std::ostream &os, const FS::Failure &f) throw ()
00038 {
00039 PrintBanner(os, '*', 60);
00040 os << "FS::Failure:\n";
00041 os << " opName = " << f.get_op() << "\n";
00042 os << " arg(s) = " << f.get_arg() << "\n";
00043 os << " errno = " << f.get_errno();
00044 Text errmsg = Basics::errno_Text(f.get_errno());
00045 if (!errmsg.Empty()) os << " (" << errmsg << ")";
00046 PrintBanner(os, '*', 60);
00047 os.flush();
00048 return os;
00049 }
00050
00051 void FS::OpenReadOnly(const Text &fname, std::ifstream &ifs)
00052 throw (FS::DoesNotExist, FS::Failure)
00053
00054 {
00055 int errno_save;
00056 while(1)
00057 {
00058 ifs.open(fname.chars(), ios::in);
00059 errno_save = errno;
00060
00061
00062
00063 if(ifs.good() || (errno_save != EINTR))
00064 break;
00065
00066
00067
00068 ifs.clear(ios::goodbit);
00069 }
00070
00071 if(!ifs.good())
00072 {
00073
00074
00075 if(errno_save == ENOENT)
00076 throw FS::DoesNotExist();
00077 else
00078 throw FS::Failure(Text("FS::OpenReadOnly"), fname, errno_save);
00079 }
00080 assert(ifs.good());
00081 }
00082
00083 void FS::OpenForWriting(const Text &fname, std::ofstream &ofs)
00084 throw (FS::Failure)
00085
00086 {
00087 int errno_save;
00088
00089 while(1)
00090 {
00091 ofs.open(fname.chars(), ios::out|ios::trunc);
00092 errno_save = errno;
00093
00094
00095
00096 if(ofs.good() || (errno_save != EINTR))
00097 break;
00098
00099
00100
00101 ofs.clear(ios::goodbit);
00102 }
00103
00104 if(!ofs.good())
00105 {
00106 throw FS::Failure(Text("FS::OpenForWriting [ofstream::open]"),
00107 fname, errno_save);
00108 }
00109 }
00110
00111 void FS::Seek(std::istream &ifs, std::streamoff offset, ios::seekdir orig)
00112 throw (FS::Failure)
00113 {
00114 if(!(ifs.seekg(offset, orig)))
00115 {
00116 int errno_save = errno;
00117 std::ostringstream buff;
00118 buff << "offset = " << offset << ", orig = " << orig;
00119 throw FS::Failure(Text("FS::Seek(std::istream) [istream::seekg]"), Text(buff.str()),
00120 errno_save);
00121 }
00122
00123
00124
00125
00126
00127 if(ifs.sync() == EOF)
00128 {
00129 int errno_save = errno;
00130 std::ostringstream buff;
00131 buff << "offset = " << offset << ", orig = " << orig;
00132 throw FS::Failure(Text("FS::Seek(std::istream) [istream::sync]"), Text(buff.str()),
00133 errno_save);
00134 }
00135 }
00136
00137 void FS::Seek(std::ostream &ofs, std::streamoff offset, ios::seekdir orig)
00138 throw (FS::Failure)
00139 {
00140 if (!(ofs.seekp(offset, orig))) {
00141 int errno_save = errno;
00142 std::ostringstream buff;
00143 buff << "offset = " << offset << ", orig = " << orig;
00144 throw FS::Failure(Text("FS::Seek(std::ostream)"), Text(buff.str()),
00145 errno_save);
00146 }
00147 }
00148
00149 std::streampos FS::Posn(std::istream &ifs) throw (FS::Failure)
00150 {
00151 std::streampos res = ifs.tellg();
00152 if (!ifs) throw FS::Failure(Text("FS::Posn(std::istream)"));
00153 return res;
00154 }
00155
00156 std::streampos FS::Posn(std::ostream &ofs) throw (FS::Failure)
00157 {
00158 std::streampos res = ofs.tellp();
00159 if (!ofs) throw FS::Failure(Text("FS::Posn(std::ostream)"));
00160 return res;
00161 }
00162
00163 void FS::Read(std::istream &ifs, char *buff, int n)
00164 throw (FS::EndOfFile, FS::Failure)
00165 {
00166 if (!(ifs.read(buff, n))) {
00167 int errno_save = errno;
00168 if (ifs.gcount() < n) throw FS::EndOfFile();
00169 else {
00170 std::ostringstream buff;
00171 buff << "count = " << n;
00172 throw FS::Failure(Text("FS::Read"), Text(buff.str()),
00173 errno_save);
00174 }
00175 }
00176 }
00177
00178 void FS::Write(std::ostream &ofs, char *buff, int n) throw (FS::Failure)
00179 {
00180 if (!(ofs.write(buff, n))) {
00181 int errno_save = errno;
00182 std::ostringstream buff;
00183 buff << "count = " << n;
00184 throw FS::Failure(Text("FS::Write"), Text(buff.str()),
00185 errno_save);
00186 }
00187 }
00188
00189 void FS::Copy(std::istream &ifs, std::ostream &ofs, int len)
00190 throw (FS::EndOfFile, FS::Failure)
00191 {
00192 const int BuffSz = 1024;
00193 char buff[BuffSz];
00194 while (len > 0) {
00195 int toCopy = min(len, BuffSz);
00196 FS::Read(ifs, buff, toCopy);
00197 FS::Write(ofs, buff, toCopy);
00198 len -= toCopy;
00199 }
00200 }
00201
00202 bool FS::AtEOF(std::istream &is) throw ()
00203 {
00204 if (is.eof()) return true;
00205 if (is.rdstate() != 0) assert(false);
00206 return (is.peek() == EOF);
00207 }
00208
00209 void FS::Flush(std::ostream &ofs) throw (FS::Failure)
00210 {
00211
00212
00213
00214
00215 if(!ofs.good())
00216 throw (FS::Failure(Text("FS::Flush(std::ostream) [on entry]")));
00217 ofs.flush();
00218 if(!ofs.good())
00219 throw (FS::Failure(Text("FS::Flush(std::ostream) [after flush]")));
00220 }
00221
00222 void FS::Close(std::ifstream &ifs) throw (FS::Failure)
00223 {
00224
00225
00226
00227
00228
00229 if(ifs.bad())
00230 throw (FS::Failure(Text("FS::Close(std::ifstream) [on entry]")));
00231 ifs.close();
00232 if (ifs.bad())
00233 throw (FS::Failure(Text("FS::Close(std::ifstream) [after close]")));
00234 }
00235
00236 void FS::Close(std::ofstream &ofs) throw (FS::Failure)
00237 {
00238
00239
00240
00241
00242
00243
00244
00245 if(!ofs.good())
00246 throw (FS::Failure(Text("FS::Close(std::ofstream) [on entry]")));
00247 ofs.flush();
00248 if(!ofs.good())
00249 throw (FS::Failure(Text("FS::Close(std::ofstream) [after flush]")));
00250 ofs.close();
00251 if(!ofs.good())
00252 throw (FS::Failure(Text("FS::Close(std::ofstream) [after close]")));
00253 }
00254
00255 void FS::Close(std::fstream &fs) throw (FS::Failure)
00256 {
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 if(fs.bad())
00270 throw (FS::Failure(Text("FS::Close(std::fstream) [on entry]")));
00271
00272
00273 fs.flush();
00274 if(fs.bad())
00275 throw (FS::Failure(Text("FS::Close(std::fstream) [after flush]")));
00276 fs.close();
00277 if (fs.bad())
00278 throw (FS::Failure(Text("FS::Close(std::fstream) [after close]")));
00279 }
00280
00281 void FS::Delete(const Text &fname) throw (FS::Failure)
00282 {
00283 bool fail;
00284 do
00285 {
00286 fail = (unlink(fname.cchars()) != 0);
00287 }
00288 while(fail && (errno == EINTR));
00289
00290 if(fail)
00291 {
00292 throw (FS::Failure(Text("FS::Delete"), fname));
00293 }
00294 }
00295
00296 bool FS::DeleteDir(const Text &dirname) throw (FS::Failure)
00297 {
00298 bool fail;
00299
00300
00301
00302 do
00303 {
00304 fail = (rmdir(dirname.cchars()) < 0);
00305 }
00306 while(fail && (errno == EINTR));
00307
00308
00309
00310 if (fail && (errno != EEXIST) && (errno != ENOTEMPTY))
00311 {
00312 throw (FS::Failure(Text("FS::DeleteDir"), dirname));
00313 }
00314
00315 return !fail;
00316 }
00317
00318 bool FS::Exists(const Text &fname) throw ()
00319 {
00320 struct stat l_stat_buf;
00321
00322 bool fail = (stat(fname.cchars(), &l_stat_buf) != 0);
00323 return !fail;
00324 }
00325
00326 bool FS::IsFile(const Text &fname) throw ()
00327 {
00328 struct stat l_stat_buf;
00329
00330 bool fail = (stat(fname.cchars(), &l_stat_buf) != 0);
00331 return (!fail && S_ISREG(l_stat_buf.st_mode));
00332 }
00333
00334 bool FS::IsDirectory(const Text &fname) throw ()
00335 {
00336 struct stat l_stat_buf;
00337
00338 bool fail = (stat(fname.cchars(), &l_stat_buf) != 0);
00339 return (!fail && S_ISDIR(l_stat_buf.st_mode));
00340 }
00341
00342 void FS::Touch(const Text &fname, mode_t mode, bool allowOverwrite)
00343 throw (FS::AlreadyExists, FS::Failure)
00344 {
00345 int oflag = O_CREAT|O_WRONLY;
00346 oflag |= allowOverwrite ? O_TRUNC : O_EXCL;
00347 int fd;
00348 int errno_save;
00349 do
00350 {
00351 fd = ::open(fname.cchars(), oflag, mode);
00352 errno_save = errno;
00353 }
00354
00355
00356 while((fd < 0) && (errno == EINTR));
00357 if (fd < 0) {
00358 if (errno_save == EEXIST) {
00359 assert(!allowOverwrite);
00360 throw FS::AlreadyExists();
00361 } else {
00362 throw FS::Failure(Text("FS::Touch [open(2)]"), fname, errno_save);
00363 }
00364 }
00365 int close_res;
00366 do
00367 close_res = ::close(fd);
00368 while((close_res != 0) && (errno == EINTR));
00369 if(close_res != 0)
00370 throw FS::Failure(Text("FS::Touch [close(2)]"), fname);
00371 }
00372
00373
00374 Text FS::ParentDir(const Text &fname) throw (FS::Failure)
00375 {
00376 Text name, parent;
00377 SplitPath(fname, name, parent);
00378 return parent;
00379 }
00380
00381
00382 Text FS::GetAbsolutePath(const Text &name) throw(FS::Failure)
00383 {
00384 Text apath = name;
00385 if(name.Empty() || name[0] != '/') {
00386 char cwdbuf[PATH_MAX+1];
00387 char *cwd = getcwd(cwdbuf, sizeof(cwdbuf));
00388 if (cwd == NULL) {
00389 throw FS::Failure(Text("FS::GetAbsolutePath [getcwd]"), name, errno);
00390 }
00391 if (name.Empty()) {
00392 apath = Text(cwd);
00393 }
00394 else {
00395 apath = Text(cwd) + "/" + name;
00396 }
00397 }
00398 return apath;
00399 }
00400
00401 Text FS::RemoveSpecialArcs(const Text &name) throw()
00402 {
00403 int len = name.Length();
00404 int start = 1;
00405 Text cname = "";
00406 while (start < len) {
00407 int slash = name.FindChar('/', start);
00408 if (slash == -1)
00409 slash = len;
00410 Text comp = name.Sub(start, slash - start);
00411 if (comp == "." || comp == "") {
00412
00413 }
00414 else if (comp == "..") {
00415
00416 int prev = cname.FindCharR('/');
00417 if(prev > -1)
00418 cname = cname.Sub(0, prev);
00419 else
00420 cname = "";
00421 }
00422 else {
00423
00424 cname = cname + "/" + comp;
00425 }
00426 start = slash + 1;
00427 }
00428 if(cname == "")
00429 cname = "/";
00430 return cname;
00431 }
00432
00433 void FS::SplitPath(const Text &fname,
00434 Text &name, Text &parent) throw(FS::Failure)
00435 {
00436 Text apath = GetAbsolutePath(fname);
00437 name = RemoveSpecialArcs(apath);
00438
00439 int last_slash_pos = name.FindCharR(PathnameSep);
00440
00441 while(last_slash_pos != -1) {
00442 if(last_slash_pos + 1 < name.Length()) {
00443
00444
00445 if(last_slash_pos == 0)
00446 parent = "/";
00447 else
00448 parent = name.Sub(0, last_slash_pos);
00449 name = name.Sub(last_slash_pos + 1);
00450 break;
00451 }
00452 else {
00453
00454 if(last_slash_pos) {
00455
00456 name = name.Sub(0, last_slash_pos);
00457 last_slash_pos = name.FindCharR(PathnameSep);
00458 }
00459 else {
00460 name = "/";
00461 parent = "/";
00462 break;
00463 }
00464 }
00465 }
00466 }
00467
00468 Text FS::TempFname(Text prefix, Text (*suffix_func)(), mode_t mode)
00469 throw (FS::Failure)
00470 {
00471 int oflag = O_CREAT|O_WRONLY|O_EXCL;
00472 Text fname;
00473 int fd;
00474 int errno_save;
00475 while(1)
00476 {
00477
00478 fname = prefix+suffix_func();
00479 fd = ::open(fname.cchars(), oflag, mode);
00480 errno_save = errno;
00481
00482
00483 if((fd == -1) && (errno_save == EEXIST))
00484 continue;
00485
00486
00487 else if((fd != -1) || (errno_save != EINTR))
00488 break;
00489 }
00490
00491
00492 if (fd < 0)
00493 {
00494 assert(errno_save != EEXIST);
00495 throw FS::Failure(Text("FS::TempFname [open(2)]"), fname, errno_save);
00496 }
00497
00498 int close_res;
00499 do
00500 close_res = ::close(fd);
00501 while((close_res != 0) && (errno == EINTR));
00502 if(close_res != 0)
00503 throw FS::Failure(Text("FS::TempFname [close(2)]"), fname);
00504
00505 return fname;
00506 }