File_WIN32.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. //
  2. // File_WIN32.cpp
  3. //
  4. // $Id: //poco/1.4/Foundation/src/File_WIN32.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_WIN32.h"
  16. #include "Poco/Exception.h"
  17. #include "Poco/String.h"
  18. #include "Poco/UnWindows.h"
  19. namespace Poco {
  20. class FileHandle
  21. {
  22. public:
  23. FileHandle(const std::string& path, DWORD access, DWORD share, DWORD disp)
  24. {
  25. _h = CreateFileA(path.c_str(), access, share, 0, disp, 0, 0);
  26. if (_h == INVALID_HANDLE_VALUE)
  27. {
  28. FileImpl::handleLastErrorImpl(path);
  29. }
  30. }
  31. ~FileHandle()
  32. {
  33. if (_h != INVALID_HANDLE_VALUE) CloseHandle(_h);
  34. }
  35. HANDLE get() const
  36. {
  37. return _h;
  38. }
  39. private:
  40. HANDLE _h;
  41. };
  42. FileImpl::FileImpl()
  43. {
  44. }
  45. FileImpl::FileImpl(const std::string& path): _path(path)
  46. {
  47. std::string::size_type n = _path.size();
  48. if (n > 1 && (_path[n - 1] == '\\' || _path[n - 1] == '/') && !((n == 3 && _path[1]==':')))
  49. {
  50. _path.resize(n - 1);
  51. }
  52. }
  53. FileImpl::~FileImpl()
  54. {
  55. }
  56. void FileImpl::swapImpl(FileImpl& file)
  57. {
  58. std::swap(_path, file._path);
  59. }
  60. void FileImpl::setPathImpl(const std::string& path)
  61. {
  62. _path = path;
  63. std::string::size_type n = _path.size();
  64. if (n > 1 && (_path[n - 1] == '\\' || _path[n - 1] == '/') && !((n == 3 && _path[1]==':')))
  65. {
  66. _path.resize(n - 1);
  67. }
  68. }
  69. bool FileImpl::existsImpl() const
  70. {
  71. poco_assert (!_path.empty());
  72. DWORD attr = GetFileAttributes(_path.c_str());
  73. if (attr == 0xFFFFFFFF)
  74. {
  75. switch (GetLastError())
  76. {
  77. case ERROR_FILE_NOT_FOUND:
  78. case ERROR_PATH_NOT_FOUND:
  79. case ERROR_NOT_READY:
  80. case ERROR_INVALID_DRIVE:
  81. return false;
  82. default:
  83. handleLastErrorImpl(_path);
  84. }
  85. }
  86. return true;
  87. }
  88. bool FileImpl::canReadImpl() const
  89. {
  90. poco_assert (!_path.empty());
  91. DWORD attr = GetFileAttributes(_path.c_str());
  92. if (attr == 0xFFFFFFFF)
  93. {
  94. switch (GetLastError())
  95. {
  96. case ERROR_ACCESS_DENIED:
  97. return false;
  98. default:
  99. handleLastErrorImpl(_path);
  100. }
  101. }
  102. return true;
  103. }
  104. bool FileImpl::canWriteImpl() const
  105. {
  106. poco_assert (!_path.empty());
  107. DWORD attr = GetFileAttributes(_path.c_str());
  108. if (attr == 0xFFFFFFFF)
  109. handleLastErrorImpl(_path);
  110. return (attr & FILE_ATTRIBUTE_READONLY) == 0;
  111. }
  112. bool FileImpl::canExecuteImpl() const
  113. {
  114. Path p(_path);
  115. return icompare(p.getExtension(), "exe") == 0;
  116. }
  117. bool FileImpl::isFileImpl() const
  118. {
  119. return !isDirectoryImpl() && !isDeviceImpl();
  120. }
  121. bool FileImpl::isDirectoryImpl() const
  122. {
  123. poco_assert (!_path.empty());
  124. DWORD attr = GetFileAttributes(_path.c_str());
  125. if (attr == 0xFFFFFFFF)
  126. handleLastErrorImpl(_path);
  127. return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
  128. }
  129. bool FileImpl::isLinkImpl() const
  130. {
  131. return false;
  132. }
  133. bool FileImpl::isDeviceImpl() const
  134. {
  135. return
  136. _path.compare(0, 4, "\\\\.\\") == 0 ||
  137. icompare(_path, "CON") == 0 ||
  138. icompare(_path, "PRN") == 0 ||
  139. icompare(_path, "AUX") == 0 ||
  140. icompare(_path, "NUL") == 0 ||
  141. ( (icompare(_path, 0, 3, "LPT") == 0 || icompare(_path, 0, 3, "COM") == 0) &&
  142. _path.size() == 4 &&
  143. _path[3] > 0x30 &&
  144. isdigit(_path[3])
  145. );
  146. }
  147. bool FileImpl::isHiddenImpl() const
  148. {
  149. poco_assert (!_path.empty());
  150. DWORD attr = GetFileAttributes(_path.c_str());
  151. if (attr == 0xFFFFFFFF)
  152. handleLastErrorImpl(_path);
  153. return (attr & FILE_ATTRIBUTE_HIDDEN) != 0;
  154. }
  155. Timestamp FileImpl::createdImpl() const
  156. {
  157. poco_assert (!_path.empty());
  158. WIN32_FILE_ATTRIBUTE_DATA fad;
  159. if (GetFileAttributesEx(_path.c_str(), GetFileExInfoStandard, &fad) == 0)
  160. handleLastErrorImpl(_path);
  161. return Timestamp::fromFileTimeNP(fad.ftCreationTime.dwLowDateTime, fad.ftCreationTime.dwHighDateTime);
  162. }
  163. Timestamp FileImpl::getLastModifiedImpl() const
  164. {
  165. poco_assert (!_path.empty());
  166. WIN32_FILE_ATTRIBUTE_DATA fad;
  167. if (GetFileAttributesEx(_path.c_str(), GetFileExInfoStandard, &fad) == 0)
  168. handleLastErrorImpl(_path);
  169. return Timestamp::fromFileTimeNP(fad.ftLastWriteTime.dwLowDateTime, fad.ftLastWriteTime.dwHighDateTime);
  170. }
  171. void FileImpl::setLastModifiedImpl(const Timestamp& ts)
  172. {
  173. poco_assert (!_path.empty());
  174. UInt32 low;
  175. UInt32 high;
  176. ts.toFileTimeNP(low, high);
  177. FILETIME ft;
  178. ft.dwLowDateTime = low;
  179. ft.dwHighDateTime = high;
  180. FileHandle fh(_path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING);
  181. if (SetFileTime(fh.get(), 0, &ft, &ft) == 0)
  182. handleLastErrorImpl(_path);
  183. }
  184. FileImpl::FileSizeImpl FileImpl::getSizeImpl() const
  185. {
  186. poco_assert (!_path.empty());
  187. WIN32_FILE_ATTRIBUTE_DATA fad;
  188. if (GetFileAttributesEx(_path.c_str(), GetFileExInfoStandard, &fad) == 0)
  189. handleLastErrorImpl(_path);
  190. LARGE_INTEGER li;
  191. li.LowPart = fad.nFileSizeLow;
  192. li.HighPart = fad.nFileSizeHigh;
  193. return li.QuadPart;
  194. }
  195. void FileImpl::setSizeImpl(FileSizeImpl size)
  196. {
  197. poco_assert (!_path.empty());
  198. FileHandle fh(_path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING);
  199. LARGE_INTEGER li;
  200. li.QuadPart = size;
  201. if (SetFilePointer(fh.get(), li.LowPart, &li.HighPart, FILE_BEGIN) == -1)
  202. handleLastErrorImpl(_path);
  203. if (SetEndOfFile(fh.get()) == 0)
  204. handleLastErrorImpl(_path);
  205. }
  206. void FileImpl::setWriteableImpl(bool flag)
  207. {
  208. poco_assert (!_path.empty());
  209. DWORD attr = GetFileAttributes(_path.c_str());
  210. if (attr == -1)
  211. handleLastErrorImpl(_path);
  212. if (flag)
  213. attr &= ~FILE_ATTRIBUTE_READONLY;
  214. else
  215. attr |= FILE_ATTRIBUTE_READONLY;
  216. if (SetFileAttributes(_path.c_str(), attr) == 0)
  217. handleLastErrorImpl(_path);
  218. }
  219. void FileImpl::setExecutableImpl(bool flag)
  220. {
  221. // not supported
  222. }
  223. void FileImpl::copyToImpl(const std::string& path) const
  224. {
  225. poco_assert (!_path.empty());
  226. if (CopyFileA(_path.c_str(), path.c_str(), FALSE) != 0)
  227. {
  228. FileImpl copy(path);
  229. copy.setWriteableImpl(true);
  230. }
  231. else handleLastErrorImpl(_path);
  232. }
  233. void FileImpl::renameToImpl(const std::string& path)
  234. {
  235. poco_assert (!_path.empty());
  236. if (MoveFileA(_path.c_str(), path.c_str()) == 0)
  237. handleLastErrorImpl(_path);
  238. }
  239. void FileImpl::removeImpl()
  240. {
  241. poco_assert (!_path.empty());
  242. if (isDirectoryImpl())
  243. {
  244. if (RemoveDirectoryA(_path.c_str()) == 0)
  245. handleLastErrorImpl(_path);
  246. }
  247. else
  248. {
  249. if (DeleteFileA(_path.c_str()) == 0)
  250. handleLastErrorImpl(_path);
  251. }
  252. }
  253. bool FileImpl::createFileImpl()
  254. {
  255. poco_assert (!_path.empty());
  256. HANDLE hFile = CreateFileA(_path.c_str(), GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0);
  257. if (hFile != INVALID_HANDLE_VALUE)
  258. {
  259. CloseHandle(hFile);
  260. return true;
  261. }
  262. else if (GetLastError() == ERROR_FILE_EXISTS)
  263. return false;
  264. else
  265. handleLastErrorImpl(_path);
  266. return false;
  267. }
  268. bool FileImpl::createDirectoryImpl()
  269. {
  270. poco_assert (!_path.empty());
  271. if (existsImpl() && isDirectoryImpl())
  272. return false;
  273. if (CreateDirectoryA(_path.c_str(), 0) == 0)
  274. handleLastErrorImpl(_path);
  275. return true;
  276. }
  277. void FileImpl::handleLastErrorImpl(const std::string& path)
  278. {
  279. DWORD err = GetLastError();
  280. switch (err)
  281. {
  282. case ERROR_FILE_NOT_FOUND:
  283. throw FileNotFoundException(path, err);
  284. case ERROR_PATH_NOT_FOUND:
  285. case ERROR_BAD_NETPATH:
  286. case ERROR_CANT_RESOLVE_FILENAME:
  287. case ERROR_INVALID_DRIVE:
  288. throw PathNotFoundException(path, err);
  289. case ERROR_ACCESS_DENIED:
  290. throw FileAccessDeniedException(path, err);
  291. case ERROR_ALREADY_EXISTS:
  292. case ERROR_FILE_EXISTS:
  293. throw FileExistsException(path, err);
  294. case ERROR_INVALID_NAME:
  295. case ERROR_DIRECTORY:
  296. case ERROR_FILENAME_EXCED_RANGE:
  297. case ERROR_BAD_PATHNAME:
  298. throw PathSyntaxException(path, err);
  299. case ERROR_FILE_READ_ONLY:
  300. throw FileReadOnlyException(path, err);
  301. case ERROR_CANNOT_MAKE:
  302. throw CreateFileException(path, err);
  303. case ERROR_DIR_NOT_EMPTY:
  304. throw FileException("directory not empty", path, err);
  305. case ERROR_WRITE_FAULT:
  306. throw WriteFileException(path, err);
  307. case ERROR_READ_FAULT:
  308. throw ReadFileException(path, err);
  309. case ERROR_SHARING_VIOLATION:
  310. throw FileException("sharing violation", path, err);
  311. case ERROR_LOCK_VIOLATION:
  312. throw FileException("lock violation", path, err);
  313. case ERROR_HANDLE_EOF:
  314. throw ReadFileException("EOF reached", path, err);
  315. case ERROR_HANDLE_DISK_FULL:
  316. case ERROR_DISK_FULL:
  317. throw WriteFileException("disk is full", path, err);
  318. case ERROR_NEGATIVE_SEEK:
  319. throw FileException("negative seek", path, err);
  320. default:
  321. throw FileException(path, err);
  322. }
  323. }
  324. } // namespace Poco