00001
00002
00003
00004
00005
00006
00007
00008 #include "ibrcommon/config.h"
00009 #include "ibrcommon/data/File.h"
00010 #include <sstream>
00011 #include <errno.h>
00012 #include <sys/stat.h>
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include <stdlib.h>
00016 #include <fcntl.h>
00017
00018 namespace ibrcommon
00019 {
00020 File::File()
00021 : _path(), _type(DT_UNKNOWN)
00022 {
00023 }
00024
00025 File::File(const string path, const unsigned char t)
00026 : _path(path), _type(t)
00027 {
00028 resolveAbsolutePath();
00029 removeSlash();
00030 }
00031
00032 File::File(const string path)
00033 : _path(path), _type(DT_UNKNOWN)
00034 {
00035 resolveAbsolutePath();
00036 removeSlash();
00037 update();
00038 }
00039
00040 void File::removeSlash()
00041 {
00042 std::string::iterator iter = _path.end(); iter--;
00043
00044 if ((*iter) == '/')
00045 {
00046 _path.erase(iter);
00047 }
00048 }
00049
00050 void File::resolveAbsolutePath()
00051 {
00052 std::string::iterator iter = _path.begin();
00053
00054 if ((*iter) != '/')
00055 {
00056 _path = "./" + _path;
00057 }
00058 }
00059
00060 bool File::exists() const
00061 {
00062 struct stat st;
00063 if( stat(_path.c_str(), &st ) == 0)
00064 return true;
00065
00066 return false;
00067 }
00068
00069 void File::update()
00070 {
00071 struct stat s;
00072 int type;
00073
00074 if ( stat(_path.c_str(), &s) == 0 )
00075 {
00076 type = s.st_mode & S_IFMT;
00077
00078 switch (type)
00079 {
00080 case S_IFREG:
00081 _type = DT_REG;
00082 break;
00083
00084 case S_IFLNK:
00085 _type = DT_LNK;
00086 break;
00087
00088 case S_IFDIR:
00089 _type = DT_DIR;
00090 break;
00091
00092 default:
00093 _type = DT_UNKNOWN;
00094 break;
00095 }
00096 }
00097 }
00098
00099 File::~File()
00100 {}
00101
00102 unsigned char File::getType() const
00103 {
00104 return _type;
00105 }
00106
00107 int File::getFiles(list<File> &files)
00108 {
00109 if (!isDirectory()) return -1;
00110
00111 DIR *dp;
00112 struct dirent *dirp;
00113 if((dp = opendir(_path.c_str())) == NULL) {
00114 return errno;
00115 }
00116
00117 while ((dirp = readdir(dp)) != NULL)
00118 {
00119 string name = string(dirp->d_name);
00120 stringstream ss; ss << getPath() << "/" << name;
00121 File file(ss.str(), dirp->d_type);
00122 files.push_back(file);
00123 }
00124 closedir(dp);
00125
00126 return 0;
00127 }
00128
00129 bool File::isSystem() const
00130 {
00131 try {
00132 if ((_path.substr(_path.length() - 2, 2) == "..") || (_path.substr(_path.length() - 1, 1) == ".")) return true;
00133 } catch (std::out_of_range) {
00134 return false;
00135 }
00136 return false;
00137 }
00138
00139 bool File::isDirectory() const
00140 {
00141 if (_type == DT_DIR) return true;
00142 return false;
00143 }
00144
00145 string File::getPath() const
00146 {
00147 return _path;
00148 }
00149
00150 File File::get(string filename) const
00151 {
00152 stringstream ss; ss << getPath() << "/" << filename;
00153 File file(ss.str());
00154
00155 return file;
00156 }
00157
00158 int File::remove(bool recursive)
00159 {
00160 int ret;
00161
00162 if (isSystem()) return -1;
00163 if (_type == DT_UNKNOWN) return -1;
00164
00165 if (isDirectory())
00166 {
00167 if (recursive)
00168 {
00169
00170 list<File> files;
00171
00172
00173 if ((ret = getFiles(files)) < 0)
00174 return ret;
00175
00176 for (list<File>::iterator iter = files.begin(); iter != files.end(); iter++)
00177 {
00178 if (!(*iter).isSystem())
00179 {
00180 if ((ret = (*iter).remove(recursive)) < 0)
00181 return ret;
00182 }
00183 }
00184 }
00185
00186 ::rmdir(getPath().c_str());
00187 }
00188 else
00189 {
00190 ::remove(getPath().c_str());
00191 }
00192
00193 return 0;
00194 }
00195
00196 File File::getParent() const
00197 {
00198 size_t pos = _path.find_last_of('/');
00199 return File(_path.substr(0, pos));
00200 }
00201
00202 void File::createDirectory(File &path)
00203 {
00204 if (!path.exists())
00205 {
00206 File parent = path.getParent();
00207 File::createDirectory(parent);
00208
00209
00210 ::mkdir(path.getPath().c_str(), 0700);
00211
00212
00213 path.update();
00214 }
00215 }
00216
00217 size_t File::size() const
00218 {
00219 struct stat filestatus;
00220 stat( getPath().c_str(), &filestatus );
00221 return filestatus.st_size;
00222 }
00223
00224 TemporaryFile::TemporaryFile(const File &path, const std::string prefix)
00225 : File(tmpname(path, prefix))
00226 {
00227 }
00228
00229 TemporaryFile::~TemporaryFile()
00230 {
00231 }
00232
00233 std::string TemporaryFile::tmpname(const File &path, const std::string prefix)
00234 {
00235 std::string pattern = path.getPath() + "/" + prefix + "XXXXXXXX";
00236 char name[pattern.length()];
00237 ::strcpy(name, pattern.c_str());
00238
00239 int fd = mkstemp(name);
00240 if (fd == -1) throw ibrcommon::IOException("Could not create a temporary name.");
00241 ::close(fd);
00242
00243 return std::string(name);
00244 }
00245
00246 locked_ifstream::locked_ifstream(File &file, ios_base::openmode mode)
00247 #ifdef USE_FILE_LOCKING
00248 : _buf(NULL), _stream(NULL), _fd(0)
00249 #endif
00250 {
00251 open(file, mode);
00252 }
00253
00254 locked_ifstream::~locked_ifstream()
00255 {
00256 close();
00257 }
00258
00259 void locked_ifstream::open(File &file, ios_base::openmode mode)
00260 {
00261 #ifdef USE_FILE_LOCKING
00262 _fd = ::open(file.getPath().c_str(), locked_fstream::getopts(mode));
00263
00264 flock lock = { F_RDLCK, SEEK_SET, 0, 0, 0 };
00265 fcntl(_fd, F_SETLKW, &lock);
00266
00267 _buf = new __gnu_cxx::stdio_filebuf<char>(_fd, mode);
00268 _stream = new std::istream(_buf);
00269 #else
00270 _stream.open(file.getPath().c_str(), mode);
00271 #endif
00272 }
00273
00274 bool locked_ifstream::is_open()
00275 {
00276 #ifdef USE_FILE_LOCKING
00277 return (_stream != NULL);
00278 #else
00279 return _stream.is_open();
00280 #endif
00281 }
00282
00283 void locked_ifstream::close()
00284 {
00285 if (!is_open()) return;
00286
00287 #ifdef USE_FILE_LOCKING
00288 flock lock1 = { F_UNLCK, SEEK_SET, 0, 0, 0 };
00289 fcntl(_fd, F_SETLKW, &lock1);
00290
00291 delete _stream; _stream = NULL;
00292 delete _buf; _buf = NULL;
00293 ::close(_fd);
00294 #else
00295 _stream.close();
00296 #endif
00297 }
00298
00299 std::istream& locked_ifstream::operator*()
00300 {
00301 if (!is_open()) throw ibrcommon::IOException("no file open");
00302 #ifdef USE_FILE_LOCKING
00303 return *_stream;
00304 #else
00305 return _stream;
00306 #endif
00307 }
00308
00309 locked_ofstream::locked_ofstream(File &file, ios_base::openmode mode)
00310 #ifdef USE_FILE_LOCKING
00311 : _buf(NULL), _stream(NULL), _fd(0)
00312 #endif
00313 {
00314 open(file, mode);
00315 }
00316
00317 locked_ofstream::~locked_ofstream()
00318 {
00319 close();
00320 }
00321
00322 void locked_ofstream::open(File &file, ios_base::openmode mode)
00323 {
00324 #ifdef USE_FILE_LOCKING
00325 _fd = ::open(file.getPath().c_str(), locked_fstream::getopts(mode));
00326
00327 flock lock = { F_WRLCK, SEEK_SET, 0, 0, 0 };
00328 fcntl(_fd, F_SETLKW, &lock);
00329
00330 _buf = new __gnu_cxx::stdio_filebuf<char>(_fd, mode);
00331 _stream = new std::ostream(_buf);
00332
00333 if (mode & ios_base::ate)
00334 {
00335 _stream->seekp(0, ios::end);
00336 }
00337 #else
00338 _stream.open(file.getPath().c_str(), mode);
00339 #endif
00340 }
00341
00342 bool locked_ofstream::is_open()
00343 {
00344 #ifdef USE_FILE_LOCKING
00345 return (_stream != NULL);
00346 #else
00347 return _stream.is_open();
00348 #endif
00349 }
00350
00351 void locked_ofstream::close()
00352 {
00353 #ifdef USE_FILE_LOCKING
00354 if (!is_open()) return;
00355
00356 flock lock1 = { F_UNLCK, SEEK_SET, 0, 0, 0 };
00357 fcntl(_fd, F_SETLKW, &lock1);
00358
00359 delete _stream; _stream = NULL;
00360 delete _buf; _buf = NULL;
00361 ::close(_fd);
00362 #else
00363 _stream.close();
00364 #endif
00365 }
00366
00367 std::ostream& locked_ofstream::operator*()
00368 {
00369 if (!is_open()) throw ibrcommon::IOException("no file open");
00370 #ifdef USE_FILE_LOCKING
00371 return *_stream;
00372 #else
00373 return _stream;
00374 #endif
00375 }
00376
00377 locked_fstream::locked_fstream()
00378 #ifdef USE_FILE_LOCKING
00379 : _buf(NULL), _stream(NULL), _fd(0)
00380 #endif
00381 {
00382 }
00383
00384 locked_fstream::locked_fstream(File &file, ios_base::openmode mode)
00385 #ifdef USE_FILE_LOCKING
00386 : _buf(NULL), _stream(NULL), _fd(0)
00387 #endif
00388 {
00389 open(file, mode);
00390 }
00391
00392 locked_fstream::~locked_fstream()
00393 {
00394 close();
00395 }
00396
00397 void locked_fstream::open(File &file, ios_base::openmode mode)
00398 {
00399 #ifdef USE_FILE_LOCKING
00400 _fd = ::open(file.getPath().c_str(), locked_fstream::getopts(mode));
00401
00402 flock lock = { F_WRLCK, SEEK_SET, 0, 0, 0 };
00403 fcntl(_fd, F_SETLKW, &lock);
00404
00405 _buf = new __gnu_cxx::stdio_filebuf<char>(_fd, mode);
00406 _stream = new std::iostream(_buf);
00407
00408 if (mode & ios_base::ate)
00409 {
00410 _stream->seekp(0, ios::end);
00411 }
00412 #else
00413 _stream.open(file.getPath().c_str(), mode);
00414 #endif
00415 }
00416
00417 bool locked_fstream::is_open()
00418 {
00419 #ifdef USE_FILE_LOCKING
00420 return (_stream != NULL);
00421 #else
00422 return _stream.is_open();
00423 #endif
00424 }
00425
00426 void locked_fstream::close()
00427 {
00428 if (!is_open()) return;
00429
00430 #ifdef USE_FILE_LOCKING
00431 flock lock1 = { F_UNLCK, SEEK_SET, 0, 0, 0 };
00432 fcntl(_fd, F_SETLKW, &lock1);
00433
00434 delete _stream; _stream = NULL;
00435 delete _buf; _buf = NULL;
00436 ::close(_fd);
00437 #else
00438 _stream.close();
00439 #endif
00440 }
00441
00442 std::iostream& locked_fstream::operator*()
00443 {
00444 if (!is_open()) throw ibrcommon::IOException("no file open");
00445 #ifdef USE_FILE_LOCKING
00446 return *_stream;
00447 #else
00448 return _stream;
00449 #endif
00450 }
00451
00452 #ifdef USE_FILE_LOCKING
00453 unsigned int locked_fstream::getopts(ios_base::openmode mode)
00454 {
00455 unsigned int ret = 0;
00456 if (mode & ios_base::app) ret += O_APPEND;
00457 if (mode & ios_base::trunc) ret += O_TRUNC;
00458
00459 if (mode & (ios_base::in | ios_base::out)) ret += O_RDWR;
00460 else
00461 {
00462 if (mode & ios_base::in) ret += O_RDONLY;
00463 else if (mode & ios_base::out) ret += O_WRONLY;
00464 }
00465
00466
00467
00468
00469 return ret;
00470 }
00471 #endif
00472
00473 }