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
00034
00035
00036
00037 #include "Poco/File_UNIX.h"
00038 #include "Poco/Buffer.h"
00039 #include "Poco/Exception.h"
00040 #include <algorithm>
00041 #include <sys/stat.h>
00042 #include <sys/types.h>
00043 #include <fcntl.h>
00044 #include <errno.h>
00045 #include <unistd.h>
00046 #include <stdio.h>
00047 #include <utime.h>
00048 #include <cstring>
00049
00050
00051 namespace Poco {
00052
00053
00054 FileImpl::FileImpl()
00055 {
00056 }
00057
00058
00059 FileImpl::FileImpl(const std::string& path): _path(path)
00060 {
00061 std::string::size_type n = _path.size();
00062 if (n > 1 && _path[n - 1] == '/')
00063 _path.resize(n - 1);
00064 }
00065
00066
00067 FileImpl::~FileImpl()
00068 {
00069 }
00070
00071
00072 void FileImpl::swapImpl(FileImpl& file)
00073 {
00074 std::swap(_path, file._path);
00075 }
00076
00077
00078 void FileImpl::setPathImpl(const std::string& path)
00079 {
00080 _path = path;
00081 std::string::size_type n = _path.size();
00082 if (n > 1 && _path[n - 1] == '/')
00083 _path.resize(n - 1);
00084 }
00085
00086
00087 bool FileImpl::existsImpl() const
00088 {
00089 poco_assert (!_path.empty());
00090
00091 struct stat st;
00092 return stat(_path.c_str(), &st) == 0;
00093 }
00094
00095
00096 bool FileImpl::canReadImpl() const
00097 {
00098 poco_assert (!_path.empty());
00099
00100 struct stat st;
00101 if (stat(_path.c_str(), &st) == 0)
00102 {
00103 if (geteuid() == 0)
00104 return true;
00105 else if (st.st_uid == geteuid())
00106 return (st.st_mode & S_IRUSR) != 0;
00107 else if (st.st_gid == getegid())
00108 return (st.st_mode & S_IRGRP) != 0;
00109 else
00110 return (st.st_mode & S_IROTH) != 0;
00111 }
00112 else handleLastErrorImpl(_path);
00113 return false;
00114 }
00115
00116
00117 bool FileImpl::canWriteImpl() const
00118 {
00119 poco_assert (!_path.empty());
00120
00121 struct stat st;
00122 if (stat(_path.c_str(), &st) == 0)
00123 {
00124 if (geteuid() == 0)
00125 return true;
00126 else if (st.st_uid == geteuid())
00127 return (st.st_mode & S_IWUSR) != 0;
00128 else if (st.st_gid == getegid())
00129 return (st.st_mode & S_IWGRP) != 0;
00130 else
00131 return (st.st_mode & S_IWOTH) != 0;
00132 }
00133 else handleLastErrorImpl(_path);
00134 return false;
00135 }
00136
00137
00138 bool FileImpl::canExecuteImpl() const
00139 {
00140 poco_assert (!_path.empty());
00141
00142 struct stat st;
00143 if (stat(_path.c_str(), &st) == 0)
00144 {
00145 if (st.st_uid == geteuid() || geteuid() == 0)
00146 return (st.st_mode & S_IXUSR) != 0;
00147 else if (st.st_gid == getegid())
00148 return (st.st_mode & S_IXGRP) != 0;
00149 else
00150 return (st.st_mode & S_IXOTH) != 0;
00151 }
00152 else handleLastErrorImpl(_path);
00153 return false;
00154 }
00155
00156
00157 bool FileImpl::isFileImpl() const
00158 {
00159 poco_assert (!_path.empty());
00160
00161 struct stat st;
00162 if (stat(_path.c_str(), &st) == 0)
00163 return S_ISREG(st.st_mode);
00164 else
00165 handleLastErrorImpl(_path);
00166 return false;
00167 }
00168
00169
00170 bool FileImpl::isDirectoryImpl() const
00171 {
00172 poco_assert (!_path.empty());
00173
00174 struct stat st;
00175 if (stat(_path.c_str(), &st) == 0)
00176 return S_ISDIR(st.st_mode);
00177 else
00178 handleLastErrorImpl(_path);
00179 return false;
00180 }
00181
00182
00183 bool FileImpl::isLinkImpl() const
00184 {
00185 poco_assert (!_path.empty());
00186
00187 struct stat st;
00188 if (lstat(_path.c_str(), &st) == 0)
00189 return S_ISLNK(st.st_mode);
00190 else
00191 handleLastErrorImpl(_path);
00192 return false;
00193 }
00194
00195
00196 bool FileImpl::isDeviceImpl() const
00197 {
00198 poco_assert (!_path.empty());
00199
00200 struct stat st;
00201 if (stat(_path.c_str(), &st) == 0)
00202 return S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode);
00203 else
00204 handleLastErrorImpl(_path);
00205 return false;
00206 }
00207
00208
00209 bool FileImpl::isHiddenImpl() const
00210 {
00211 poco_assert (!_path.empty());
00212 Path p(_path);
00213 p.makeFile();
00214
00215 return p.getFileName()[0] == '.';
00216 }
00217
00218
00219 Timestamp FileImpl::createdImpl() const
00220 {
00221 poco_assert (!_path.empty());
00222
00223 #if defined(__APPLE__) && defined(st_birthtime) && !defined(POCO_NO_STAT64) // st_birthtime is available only on 10.5
00224 struct stat64 st;
00225 if (stat64(_path.c_str(), &st) == 0)
00226 return Timestamp::fromEpochTime(st.st_birthtime);
00227 #elif defined(__FreeBSD__)
00228 struct stat st;
00229 if (stat(_path.c_str(), &st) == 0)
00230 return Timestamp::fromEpochTime(st.st_birthtime);
00231 #else
00232 struct stat st;
00233 if (stat(_path.c_str(), &st) == 0)
00234 return Timestamp::fromEpochTime(st.st_ctime);
00235 #endif
00236 else
00237 handleLastErrorImpl(_path);
00238 return 0;
00239 }
00240
00241
00242 Timestamp FileImpl::getLastModifiedImpl() const
00243 {
00244 poco_assert (!_path.empty());
00245
00246 struct stat st;
00247 if (stat(_path.c_str(), &st) == 0)
00248 return Timestamp::fromEpochTime(st.st_mtime);
00249 else
00250 handleLastErrorImpl(_path);
00251 return 0;
00252 }
00253
00254
00255 void FileImpl::setLastModifiedImpl(const Timestamp& ts)
00256 {
00257 poco_assert (!_path.empty());
00258
00259 struct utimbuf tb;
00260 tb.actime = ts.epochTime();
00261 tb.modtime = ts.epochTime();
00262 if (utime(_path.c_str(), &tb) != 0)
00263 handleLastErrorImpl(_path);
00264 }
00265
00266
00267 FileImpl::FileSizeImpl FileImpl::getSizeImpl() const
00268 {
00269 poco_assert (!_path.empty());
00270
00271 struct stat st;
00272 if (stat(_path.c_str(), &st) == 0)
00273 return st.st_size;
00274 else
00275 handleLastErrorImpl(_path);
00276 return 0;
00277 }
00278
00279
00280 void FileImpl::setSizeImpl(FileSizeImpl size)
00281 {
00282 poco_assert (!_path.empty());
00283
00284 if (truncate(_path.c_str(), size) != 0)
00285 handleLastErrorImpl(_path);
00286 }
00287
00288
00289 void FileImpl::setWriteableImpl(bool flag)
00290 {
00291 poco_assert (!_path.empty());
00292
00293 struct stat st;
00294 if (stat(_path.c_str(), &st) != 0)
00295 handleLastErrorImpl(_path);
00296 mode_t mode;
00297 if (flag)
00298 {
00299 mode = st.st_mode | S_IWUSR;
00300 }
00301 else
00302 {
00303 mode_t wmask = S_IWUSR | S_IWGRP | S_IWOTH;
00304 mode = st.st_mode & ~wmask;
00305 }
00306 if (chmod(_path.c_str(), mode) != 0)
00307 handleLastErrorImpl(_path);
00308 }
00309
00310
00311 void FileImpl::setExecutableImpl(bool flag)
00312 {
00313 poco_assert (!_path.empty());
00314
00315 struct stat st;
00316 if (stat(_path.c_str(), &st) != 0)
00317 handleLastErrorImpl(_path);
00318 mode_t mode;
00319 if (flag)
00320 {
00321 mode = st.st_mode | S_IXUSR;
00322 }
00323 else
00324 {
00325 mode_t wmask = S_IXUSR | S_IXGRP | S_IXOTH;
00326 mode = st.st_mode & ~wmask;
00327 }
00328 if (chmod(_path.c_str(), mode) != 0)
00329 handleLastErrorImpl(_path);
00330 }
00331
00332
00333 void FileImpl::copyToImpl(const std::string& path) const
00334 {
00335 poco_assert (!_path.empty());
00336
00337 int sd = open(_path.c_str(), O_RDONLY);
00338 if (sd == -1) handleLastErrorImpl(_path);
00339
00340 struct stat st;
00341 if (fstat(sd, &st) != 0)
00342 {
00343 close(sd);
00344 handleLastErrorImpl(_path);
00345 }
00346 const long blockSize = st.st_blksize;
00347
00348 int dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode & S_IRWXU);
00349 if (dd == -1)
00350 {
00351 close(sd);
00352 handleLastErrorImpl(path);
00353 }
00354 Buffer<char> buffer(blockSize);
00355 try
00356 {
00357 int n;
00358 while ((n = read(sd, buffer.begin(), blockSize)) > 0)
00359 {
00360 if (write(dd, buffer.begin(), n) != n)
00361 handleLastErrorImpl(path);
00362 }
00363 if (n < 0)
00364 handleLastErrorImpl(_path);
00365 }
00366 catch (...)
00367 {
00368 close(sd);
00369 close(dd);
00370 throw;
00371 }
00372 close(sd);
00373 if (fsync(dd) != 0)
00374 {
00375 close(dd);
00376 handleLastErrorImpl(path);
00377 }
00378 if (close(dd) != 0)
00379 handleLastErrorImpl(path);
00380 }
00381
00382
00383 void FileImpl::renameToImpl(const std::string& path)
00384 {
00385 poco_assert (!_path.empty());
00386
00387 if (rename(_path.c_str(), path.c_str()) != 0)
00388 handleLastErrorImpl(_path);
00389 }
00390
00391
00392 void FileImpl::removeImpl()
00393 {
00394 poco_assert (!_path.empty());
00395
00396 int rc;
00397 if (!isLinkImpl() && isDirectoryImpl())
00398 rc = rmdir(_path.c_str());
00399 else
00400 rc = unlink(_path.c_str());
00401 if (rc) handleLastErrorImpl(_path);
00402 }
00403
00404
00405 bool FileImpl::createFileImpl()
00406 {
00407 poco_assert (!_path.empty());
00408
00409 int n = open(_path.c_str(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
00410 if (n != -1)
00411 {
00412 close(n);
00413 return true;
00414 }
00415 if (n == -1 && errno == EEXIST)
00416 return false;
00417 else
00418 handleLastErrorImpl(_path);
00419 return false;
00420 }
00421
00422
00423 bool FileImpl::createDirectoryImpl()
00424 {
00425 poco_assert (!_path.empty());
00426
00427 if (existsImpl() && isDirectoryImpl())
00428 return false;
00429 if (mkdir(_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
00430 handleLastErrorImpl(_path);
00431 return true;
00432 }
00433
00434
00435 void FileImpl::handleLastErrorImpl(const std::string& path)
00436 {
00437 switch (errno)
00438 {
00439 case EIO:
00440 throw IOException(path);
00441 case EPERM:
00442 throw FileAccessDeniedException("insufficient permissions", path);
00443 case EACCES:
00444 throw FileAccessDeniedException(path);
00445 case ENOENT:
00446 throw FileNotFoundException(path);
00447 case ENOTDIR:
00448 throw OpenFileException("not a directory", path);
00449 case EISDIR:
00450 throw OpenFileException("not a file", path);
00451 case EROFS:
00452 throw FileReadOnlyException(path);
00453 case EEXIST:
00454 throw FileExistsException(path);
00455 case ENOSPC:
00456 throw FileException("no space left on device", path);
00457 case EDQUOT:
00458 throw FileException("disk quota exceeded", path);
00459 #if !defined(_AIX)
00460 case ENOTEMPTY:
00461 throw FileException("directory not empty", path);
00462 #endif
00463 case ENAMETOOLONG:
00464 throw PathSyntaxException(path);
00465 case ENFILE:
00466 case EMFILE:
00467 throw FileException("too many open files", path);
00468 default:
00469 throw FileException(std::strerror(errno), path);
00470 }
00471 }
00472
00473
00474 }