File_UNIX.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. //
  2. // File_UNIX.cpp
  3. //
  4. // $Id: //poco/1.4/Foundation/src/File_UNIX.cpp#1 $
  5. //
  6. // Library: Foundation
  7. // Package: Filesystem
  8. // Module: File
  9. //
  10. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #include "Poco/File_UNIX.h"
  16. #include "Poco/Buffer.h"
  17. #include "Poco/Exception.h"
  18. #include <algorithm>
  19. #include <sys/stat.h>
  20. #include <sys/types.h>
  21. #include <fcntl.h>
  22. #include <errno.h>
  23. #include <unistd.h>
  24. #include <stdio.h>
  25. #include <utime.h>
  26. #include <cstring>
  27. namespace Poco {
  28. FileImpl::FileImpl()
  29. {
  30. }
  31. FileImpl::FileImpl(const std::string& path): _path(path)
  32. {
  33. std::string::size_type n = _path.size();
  34. if (n > 1 && _path[n - 1] == '/')
  35. _path.resize(n - 1);
  36. }
  37. FileImpl::~FileImpl()
  38. {
  39. }
  40. void FileImpl::swapImpl(FileImpl& file)
  41. {
  42. std::swap(_path, file._path);
  43. }
  44. void FileImpl::setPathImpl(const std::string& path)
  45. {
  46. _path = path;
  47. std::string::size_type n = _path.size();
  48. if (n > 1 && _path[n - 1] == '/')
  49. _path.resize(n - 1);
  50. }
  51. bool FileImpl::existsImpl() const
  52. {
  53. poco_assert (!_path.empty());
  54. struct stat st;
  55. return stat(_path.c_str(), &st) == 0;
  56. }
  57. bool FileImpl::canReadImpl() const
  58. {
  59. poco_assert (!_path.empty());
  60. struct stat st;
  61. if (stat(_path.c_str(), &st) == 0)
  62. {
  63. if (st.st_uid == geteuid())
  64. return (st.st_mode & S_IRUSR) != 0;
  65. else if (st.st_gid == getegid())
  66. return (st.st_mode & S_IRGRP) != 0;
  67. else
  68. return (st.st_mode & S_IROTH) != 0 || geteuid() == 0;
  69. }
  70. else handleLastErrorImpl(_path);
  71. return false;
  72. }
  73. bool FileImpl::canWriteImpl() const
  74. {
  75. poco_assert (!_path.empty());
  76. struct stat st;
  77. if (stat(_path.c_str(), &st) == 0)
  78. {
  79. if (st.st_uid == geteuid())
  80. return (st.st_mode & S_IWUSR) != 0;
  81. else if (st.st_gid == getegid())
  82. return (st.st_mode & S_IWGRP) != 0;
  83. else
  84. return (st.st_mode & S_IWOTH) != 0 || geteuid() == 0;
  85. }
  86. else handleLastErrorImpl(_path);
  87. return false;
  88. }
  89. bool FileImpl::canExecuteImpl() const
  90. {
  91. poco_assert (!_path.empty());
  92. struct stat st;
  93. if (stat(_path.c_str(), &st) == 0)
  94. {
  95. if (st.st_uid == geteuid() || geteuid() == 0)
  96. return (st.st_mode & S_IXUSR) != 0;
  97. else if (st.st_gid == getegid())
  98. return (st.st_mode & S_IXGRP) != 0;
  99. else
  100. return (st.st_mode & S_IXOTH) != 0;
  101. }
  102. else handleLastErrorImpl(_path);
  103. return false;
  104. }
  105. bool FileImpl::isFileImpl() const
  106. {
  107. poco_assert (!_path.empty());
  108. struct stat st;
  109. if (stat(_path.c_str(), &st) == 0)
  110. return S_ISREG(st.st_mode);
  111. else
  112. handleLastErrorImpl(_path);
  113. return false;
  114. }
  115. bool FileImpl::isDirectoryImpl() const
  116. {
  117. poco_assert (!_path.empty());
  118. struct stat st;
  119. if (stat(_path.c_str(), &st) == 0)
  120. return S_ISDIR(st.st_mode);
  121. else
  122. handleLastErrorImpl(_path);
  123. return false;
  124. }
  125. bool FileImpl::isLinkImpl() const
  126. {
  127. poco_assert (!_path.empty());
  128. struct stat st;
  129. if (lstat(_path.c_str(), &st) == 0)
  130. return S_ISLNK(st.st_mode);
  131. else
  132. handleLastErrorImpl(_path);
  133. return false;
  134. }
  135. bool FileImpl::isDeviceImpl() const
  136. {
  137. poco_assert (!_path.empty());
  138. struct stat st;
  139. if (stat(_path.c_str(), &st) == 0)
  140. return S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode);
  141. else
  142. handleLastErrorImpl(_path);
  143. return false;
  144. }
  145. bool FileImpl::isHiddenImpl() const
  146. {
  147. poco_assert (!_path.empty());
  148. Path p(_path);
  149. p.makeFile();
  150. return p.getFileName()[0] == '.';
  151. }
  152. Timestamp FileImpl::createdImpl() const
  153. {
  154. poco_assert (!_path.empty());
  155. #if defined(__APPLE__) && defined(st_birthtime) && !defined(POCO_NO_STAT64) // st_birthtime is available only on 10.5
  156. struct stat64 st;
  157. if (stat64(_path.c_str(), &st) == 0)
  158. return Timestamp::fromEpochTime(st.st_birthtime);
  159. #elif defined(__FreeBSD__)
  160. struct stat st;
  161. if (stat(_path.c_str(), &st) == 0)
  162. return Timestamp::fromEpochTime(st.st_birthtime);
  163. #else
  164. struct stat st;
  165. if (stat(_path.c_str(), &st) == 0)
  166. return Timestamp::fromEpochTime(st.st_ctime);
  167. #endif
  168. else
  169. handleLastErrorImpl(_path);
  170. return 0;
  171. }
  172. Timestamp FileImpl::getLastModifiedImpl() const
  173. {
  174. poco_assert (!_path.empty());
  175. struct stat st;
  176. if (stat(_path.c_str(), &st) == 0)
  177. return Timestamp::fromEpochTime(st.st_mtime);
  178. else
  179. handleLastErrorImpl(_path);
  180. return 0;
  181. }
  182. void FileImpl::setLastModifiedImpl(const Timestamp& ts)
  183. {
  184. poco_assert (!_path.empty());
  185. struct utimbuf tb;
  186. tb.actime = ts.epochTime();
  187. tb.modtime = ts.epochTime();
  188. if (utime(_path.c_str(), &tb) != 0)
  189. handleLastErrorImpl(_path);
  190. }
  191. FileImpl::FileSizeImpl FileImpl::getSizeImpl() const
  192. {
  193. poco_assert (!_path.empty());
  194. struct stat st;
  195. if (stat(_path.c_str(), &st) == 0)
  196. return st.st_size;
  197. else
  198. handleLastErrorImpl(_path);
  199. return 0;
  200. }
  201. void FileImpl::setSizeImpl(FileSizeImpl size)
  202. {
  203. poco_assert (!_path.empty());
  204. if (truncate(_path.c_str(), size) != 0)
  205. handleLastErrorImpl(_path);
  206. }
  207. void FileImpl::setWriteableImpl(bool flag)
  208. {
  209. poco_assert (!_path.empty());
  210. struct stat st;
  211. if (stat(_path.c_str(), &st) != 0)
  212. handleLastErrorImpl(_path);
  213. mode_t mode;
  214. if (flag)
  215. {
  216. mode = st.st_mode | S_IWUSR;
  217. }
  218. else
  219. {
  220. mode_t wmask = S_IWUSR | S_IWGRP | S_IWOTH;
  221. mode = st.st_mode & ~wmask;
  222. }
  223. if (chmod(_path.c_str(), mode) != 0)
  224. handleLastErrorImpl(_path);
  225. }
  226. void FileImpl::setExecutableImpl(bool flag)
  227. {
  228. poco_assert (!_path.empty());
  229. struct stat st;
  230. if (stat(_path.c_str(), &st) != 0)
  231. handleLastErrorImpl(_path);
  232. mode_t mode;
  233. if (flag)
  234. {
  235. mode = st.st_mode | S_IXUSR;
  236. }
  237. else
  238. {
  239. mode_t wmask = S_IXUSR | S_IXGRP | S_IXOTH;
  240. mode = st.st_mode & ~wmask;
  241. }
  242. if (chmod(_path.c_str(), mode) != 0)
  243. handleLastErrorImpl(_path);
  244. }
  245. void FileImpl::copyToImpl(const std::string& path) const
  246. {
  247. poco_assert (!_path.empty());
  248. int sd = open(_path.c_str(), O_RDONLY);
  249. if (sd == -1) handleLastErrorImpl(_path);
  250. struct stat st;
  251. if (fstat(sd, &st) != 0)
  252. {
  253. close(sd);
  254. handleLastErrorImpl(_path);
  255. }
  256. const long blockSize = st.st_blksize;
  257. int dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode);
  258. if (dd == -1)
  259. {
  260. close(sd);
  261. handleLastErrorImpl(path);
  262. }
  263. Buffer<char> buffer(blockSize);
  264. try
  265. {
  266. int n;
  267. while ((n = read(sd, buffer.begin(), blockSize)) > 0)
  268. {
  269. if (write(dd, buffer.begin(), n) != n)
  270. handleLastErrorImpl(path);
  271. }
  272. if (n < 0)
  273. handleLastErrorImpl(_path);
  274. }
  275. catch (...)
  276. {
  277. close(sd);
  278. close(dd);
  279. throw;
  280. }
  281. close(sd);
  282. if (fsync(dd) != 0)
  283. {
  284. close(dd);
  285. handleLastErrorImpl(path);
  286. }
  287. if (close(dd) != 0)
  288. handleLastErrorImpl(path);
  289. }
  290. void FileImpl::renameToImpl(const std::string& path)
  291. {
  292. poco_assert (!_path.empty());
  293. if (rename(_path.c_str(), path.c_str()) != 0)
  294. handleLastErrorImpl(_path);
  295. }
  296. void FileImpl::removeImpl()
  297. {
  298. poco_assert (!_path.empty());
  299. int rc;
  300. if (!isLinkImpl() && isDirectoryImpl())
  301. rc = rmdir(_path.c_str());
  302. else
  303. rc = unlink(_path.c_str());
  304. if (rc) handleLastErrorImpl(_path);
  305. }
  306. bool FileImpl::createFileImpl()
  307. {
  308. poco_assert (!_path.empty());
  309. int n = open(_path.c_str(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  310. if (n != -1)
  311. {
  312. close(n);
  313. return true;
  314. }
  315. if (n == -1 && errno == EEXIST)
  316. return false;
  317. else
  318. handleLastErrorImpl(_path);
  319. return false;
  320. }
  321. bool FileImpl::createDirectoryImpl()
  322. {
  323. poco_assert (!_path.empty());
  324. if (existsImpl() && isDirectoryImpl())
  325. return false;
  326. if (mkdir(_path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) != 0)
  327. handleLastErrorImpl(_path);
  328. return true;
  329. }
  330. void FileImpl::handleLastErrorImpl(const std::string& path)
  331. {
  332. switch (errno)
  333. {
  334. case EIO:
  335. throw IOException(path, errno);
  336. case EPERM:
  337. throw FileAccessDeniedException("insufficient permissions", path, errno);
  338. case EACCES:
  339. throw FileAccessDeniedException(path, errno);
  340. case ENOENT:
  341. throw FileNotFoundException(path, errno);
  342. case ENOTDIR:
  343. throw OpenFileException("not a directory", path, errno);
  344. case EISDIR:
  345. throw OpenFileException("not a file", path, errno);
  346. case EROFS:
  347. throw FileReadOnlyException(path, errno);
  348. case EEXIST:
  349. throw FileExistsException(path, errno);
  350. case ENOSPC:
  351. throw FileException("no space left on device", path, errno);
  352. case EDQUOT:
  353. throw FileException("disk quota exceeded", path, errno);
  354. #if !defined(_AIX)
  355. case ENOTEMPTY:
  356. throw FileException("directory not empty", path, errno);
  357. #endif
  358. case ENAMETOOLONG:
  359. throw PathSyntaxException(path, errno);
  360. case ENFILE:
  361. case EMFILE:
  362. throw FileException("too many open files", path, errno);
  363. default:
  364. throw FileException(std::strerror(errno), path, errno);
  365. }
  366. }
  367. } // namespace Poco