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 }