File_WIN32U.cpp 8.4 KB

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