YSTest: MinGW32.cpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

MinGW32.cpp
浏览该文件的文档.
1 /*
2 © 2013-2017 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
29 #include "YCLib/YModules.h"
30 #include YFM_YCLib_Platform
31 #if YCL_Win32
32 # include YFM_Win32_YCLib_Registry // for platform::NodeCategory, ERROR_*,
33 // std::string, UniqueHandle, ::BY_HANDLE_FILE_INFORMATION, YCL_CallF_Win32,
34 // YCL_Raise_Win32E, NO_ERROR, ::OVERLAPPED, ::GetSystemDirectoryW,
35 // ::GetSystemWindowsDirectoryW, ystdex::rtrim, ::FormatMessageW, ::HMODULE,
36 // ::GetProcAddress, ::GetModuleFileNameW, ::CreateFileW, INVALID_HANDLE_VALUE,
37 // RegistryKey, HKEY_*, FindClose, ystdex::throw_error, ::FindFirstFileW,
38 // ::FindNextFileW, std::errc::not_supported, std::invalid_argument,
39 // ::LARGE_INTEGER, ::GetFileTime, ::SetFileTime, ::LockFileEx, ::UnlockFileEx,
40 // ::WaitForSingleObject;
41 # include <cerrno> // for EINVAL, ENOENT, EMFILE, EACCESS, EBADF, ENOMEM,
42 // ENOEXEC, EXDEV, EEXIST, EAGAIN, EPIPE, ENOSPC, ECHILD, ENOTEMPTY;
43 # include YFM_YSLib_Core_YCoreUtilities // for YSLib::IsInClosedInterval,
44 // YSLib::make_unique_default_init, YSLib::TryInvoke,
45 // platform::EndsWithNonSeperator;
46 # include YFM_Win32_YCLib_NLS // for WCSToUTF8;
47 # include <ystdex/container.hpp> // for ystdex::retry_for_vector;
48 # include <ystdex/scope_guard.hpp> // for ystdex::unique_guard,
49 // ystdex::dismiss, std::bind, std::placeholders::_1;
50
51 using namespace YSLib;
53 using platform::NodeCategory;
54 #endif
55
56 namespace platform_ex
57 {
58
59 #if YCL_Win32
60
61 inline namespace Windows
62 {
63
64 int
65 ConvertToErrno(ErrorCode err) ynothrow
66 {
67 // NOTE: This mapping is from universal CRT in Windows SDK 10.0.10150.0,
68 // ucrt/misc/errno.cpp, except for fix of the bug error 124: it shall be
69 // %ERROR_INVALID_LEVEL but not %ERROR_INVALID_HANDLE. See https://connect.microsoft.com/VisualStudio/feedback/details/1641428.
70 switch(err)
71 {
72 case ERROR_INVALID_FUNCTION:
73 return EINVAL;
74 case ERROR_FILE_NOT_FOUND:
75 case ERROR_PATH_NOT_FOUND:
76 return ENOENT;
77 case ERROR_TOO_MANY_OPEN_FILES:
78 return EMFILE;
79 case ERROR_ACCESS_DENIED:
80 return EACCES;
81 case ERROR_INVALID_HANDLE:
82 return EBADF;
83 case ERROR_ARENA_TRASHED:
84 case ERROR_NOT_ENOUGH_MEMORY:
85 case ERROR_INVALID_BLOCK:
86 return ENOMEM;
87 case ERROR_BAD_ENVIRONMENT:
88 return E2BIG;
89 case ERROR_BAD_FORMAT:
90 return ENOEXEC;
91 case ERROR_INVALID_ACCESS:
92 case ERROR_INVALID_DATA:
93 return EINVAL;
94 case ERROR_INVALID_DRIVE:
95 return ENOENT;
96 case ERROR_CURRENT_DIRECTORY:
97 return EACCES;
98 case ERROR_NOT_SAME_DEVICE:
99 return EXDEV;
100 case ERROR_NO_MORE_FILES:
101 return ENOENT;
102 case ERROR_LOCK_VIOLATION:
103 return EACCES;
104 case ERROR_BAD_NETPATH:
105 return ENOENT;
106 case ERROR_NETWORK_ACCESS_DENIED:
107 return EACCES;
108 case ERROR_BAD_NET_NAME:
109 return ENOENT;
110 case ERROR_FILE_EXISTS:
111 return EEXIST;
112 case ERROR_CANNOT_MAKE:
113 case ERROR_FAIL_I24:
114 return EACCES;
115 case ERROR_INVALID_PARAMETER:
116 return EINVAL;
117 case ERROR_NO_PROC_SLOTS:
118 return EAGAIN;
119 case ERROR_DRIVE_LOCKED:
120 return EACCES;
121 case ERROR_BROKEN_PIPE:
122 return EPIPE;
123 case ERROR_DISK_FULL:
124 return ENOSPC;
125 case ERROR_INVALID_TARGET_HANDLE:
126 return EBADF;
127 case ERROR_INVALID_LEVEL:
128 return EINVAL;
129 case ERROR_WAIT_NO_CHILDREN:
130 case ERROR_CHILD_NOT_COMPLETE:
131 return ECHILD;
132 case ERROR_DIRECT_ACCESS_HANDLE:
133 return EBADF;
134 case ERROR_NEGATIVE_SEEK:
135 return EINVAL;
136 case ERROR_SEEK_ON_DEVICE:
137 return EACCES;
138 case ERROR_DIR_NOT_EMPTY:
139 return ENOTEMPTY;
140 case ERROR_NOT_LOCKED:
141 return EACCES;
142 case ERROR_BAD_PATHNAME:
143 return ENOENT;
144 case ERROR_MAX_THRDS_REACHED:
145 return EAGAIN;
146 case ERROR_LOCK_FAILED:
147 return EACCES;
148 case ERROR_ALREADY_EXISTS:
149 return EEXIST;
150 case ERROR_FILENAME_EXCED_RANGE:
151 return ENOENT;
152 case ERROR_NESTING_NOT_ALLOWED:
153 return EAGAIN;
154 case ERROR_NOT_ENOUGH_QUOTA:
155 return ENOMEM;
156 default:
157 break;
158 }
159 if(IsInClosedInterval<ErrorCode>(err, ERROR_WRITE_PROTECT,
160 ERROR_SHARING_BUFFER_EXCEEDED))
161 return EACCES;
162 if(IsInClosedInterval<ErrorCode>(err, ERROR_INVALID_STARTING_CODESEG,
163 ERROR_INFLOOP_IN_RELOC_CHAIN))
164 return ENOEXEC;
165 return EINVAL;
166 }
167
168
170 namespace
171 {
172
173 class Win32ErrorCategory : public std::error_category
174 {
175 public:
176 PDefH(const char*, name, ) const ynothrow override
177 ImplRet("Win32Error")
179 PDefH(std::string, message, int ev) const override
180 // NOTE: For Win32 a %::DWORD can be mapped one-to-one for 32-bit %int.
181 ImplRet("Error " + std::to_string(ev) + ": "
182 + Win32Exception::FormatMessage(ErrorCode(ev)))
183 };
184
185
187
188 template<typename _func>
189 auto
190 FetchFileInfo(_func f, UniqueHandle::pointer h)
191 -> decltype(f(std::declval<::BY_HANDLE_FILE_INFORMATION&>()))
192 {
193 ::BY_HANDLE_FILE_INFORMATION info;
194
195 YCL_CallF_Win32(GetFileInformationByHandle, h, &info);
196 return f(info);
197 }
198
199 template<typename _func, typename... _tParams>
200 auto
201 MakeFileToDo(_func f, _tParams&&... args)
202 -> decltype(f(UniqueHandle::pointer()))
203 {
204 if(const auto h = MakeFile(yforward(args)...))
205 return f(h.get());
206 YCL_Raise_Win32E("CreateFileW", yfsig);
207 }
208
209 yconstfn
210 PDefH(FileAttributesAndFlags, FollowToAttr, bool follow_reparse_point) ynothrow
211 ImplRet(follow_reparse_point ? FileAttributesAndFlags::NormalWithDirectory
212 : FileAttributesAndFlags::NormalAll)
214
215
216 yconstexpr const auto FSCTL_GET_REPARSE_POINT(0x000900A8UL);
218
219
221
222 // TODO: Extract to %YCLib.NativeAPI?
223 yconstfn PDefH(unsigned long, High32, std::uint64_t val) ynothrow
224 ImplRet(static_cast<unsigned long>(val >> 32UL))
225
226 yconstfn PDefH(unsigned long, Low32, std::uint64_t val) ynothrow
227 ImplRet(static_cast<unsigned long>(val))
228
229 template<typename _func>
230 auto
231 DoWithDefaultOverlapped(_func f, std::uint64_t off)
232 -> decltype(f(std::declval<::OVERLAPPED&>()))
233 {
234 ::OVERLAPPED overlapped{0, 0, {Low32(off), High32(off)}, {}};
235
236 return f(overlapped);
237 }
239
240
242
243 enum class SystemPaths
244 {
245 System,
246 Windows
247 };
248
249 wstring
250 FetchFixedSystemPath(SystemPaths e, size_t s)
251 {
252 // XXX: Depends right behavior on external API.
253 const auto p_buf(make_unique_default_init<wchar_t[]>(s));
254 const auto str(p_buf.get());
255
256 switch(e)
257 {
258 case SystemPaths::System:
259 YCL_CallF_Win32(GetSystemDirectoryW, str, unsigned(s));
260 break;
261 case SystemPaths::Windows:
262 YCL_CallF_Win32(GetSystemWindowsDirectoryW, str, unsigned(s));
263 break;
264 }
265 return ystdex::rtrim(wstring(str), L'\\') + L'\\';
266 }
268
269 } // unnamed namespace;
270
271
272 Win32Exception::Win32Exception(ErrorCode ec, string_view msg, RecordLevel lv)
273 : Exception(int(ec), GetErrorCategory(), msg, lv)
274 {
275 YAssert(ec != 0, "No error should be thrown.");
276 }
277 Win32Exception::Win32Exception(ErrorCode ec, string_view msg, const char* sig,
278 RecordLevel lv)
279 : Win32Exception(ec, platform::ComposeMessageWithSignature(msg, sig), lv)
280 {}
281 ImplDeDtor(Win32Exception)
282
283 const std::error_category&
284 Win32Exception::GetErrorCategory()
285 {
286 static const Win32ErrorCategory ecat{};
287
288 return ecat;
289 }
290
291 std::string
292 Win32Exception::FormatMessage(ErrorCode ec) ynothrow
293 {
294 return TryInvoke([=]{
295 try
296 {
297 wchar_t* buf{};
298
299 YCL_CallF_Win32(FormatMessageW, FORMAT_MESSAGE_ALLOCATE_BUFFER
300 | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
301 {}, ec, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
302 reinterpret_cast<wchar_t*>(&buf), 1, {});
303
304 const auto p(unique_raw(buf, LocalDelete()));
305
306 return ystdex::rtrim(WCSToUTF8(buf));
307 }
308 CatchExpr(..., YTraceDe(Warning, "FormatMessage failed."), throw)
309 });
310 }
311
312
313 ModuleProc*
314 LoadProc(::HMODULE h_module, const char* proc)
315 {
316 return YCL_CallF_Win32(GetProcAddress, h_module, proc);
317 }
318
319
320 wstring
321 FetchModuleFileName(::HMODULE h_module, RecordLevel lv)
322 {
323 // TODO: Avoid retry for NT 6 %::GetModuleFileNameW?
324 return ystdex::retry_for_vector<wstring>(MAX_PATH,
325 [=](wstring& res, size_t s) -> bool{
326 const auto r(size_t(::GetModuleFileNameW(h_module, &res[0],
327 static_cast<unsigned long>(s))));
328 const auto err(::GetLastError());
329
330 if(err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
331 throw Win32Exception(err, "GetModuleFileNameW", lv);
332 if(r < s)
333 {
334 res.resize(r);
335 return {};
336 }
337 return true;
338 });
339 }
340
341
342 void
343 GlobalDelete::operator()(pointer h) const ynothrow
344 {
345 // NOTE: %::GlobalFree does not ignore null handle value.
346 if(h && YB_UNLIKELY(::GlobalFree(h)))
347 YCL_Trace_Win32E(Warning, GlobalFree, yfsig);
348 }
349
350
351 GlobalLocked::GlobalLocked(::HGLOBAL h)
352 : p_locked(YCL_CallF_Win32(GlobalLock, h))
353 {}
354 GlobalLocked::~GlobalLocked()
355 {
356 YCL_TraceCallF_Win32(GlobalUnlock, p_locked);
357 }
358
359
360 void
361 LocalDelete::operator()(pointer h) const ynothrow
362 {
363 // FIXME: For some platforms, no %::LocalFree available. See https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms679351(v=vs.85).aspx.
364 // NOTE: %::LocalFree ignores null handle value.
365 if(YB_UNLIKELY(::LocalFree(h)))
366 YCL_Trace_Win32E(Warning, LocalFree, yfsig);
367 }
368
369
370 NodeCategory
371 TryCategorizeNodeAttributes(UniqueHandle::pointer h)
372 {
373 return FetchFileInfo([&](::BY_HANDLE_FILE_INFORMATION& info)
374 -> NodeCategory{
375 return CategorizeNode(FileAttributes(info.dwFileAttributes));
376 }, h);
377 }
378
379 NodeCategory
380 TryCategorizeNodeDevice(UniqueHandle::pointer h)
381 {
382 NodeCategory res;
383
384 switch(::GetFileType(h))
385 {
386 case FILE_TYPE_CHAR:
387 res = NodeCategory::Character;
388 break;
389 case FILE_TYPE_PIPE:
390 res = NodeCategory::FIFO;
391 break;
392 case FILE_TYPE_UNKNOWN:
393 {
394 const auto err(::GetLastError());
395
396 if(err != NO_ERROR)
397 throw Win32Exception(err, "GetFileType", Err);
398 }
399 YB_ATTR_fallthrough;
400 default:
401 res = NodeCategory::Unknown;
402 }
403 return res;
404 }
405
406 NodeCategory
407 CategorizeNode(FileAttributes attr, unsigned long reparse_tag) ynothrow
408 {
409 auto res(NodeCategory::Empty);
410
411 if(IsDirectory(attr))
412 res |= NodeCategory::Directory;
413 if(attr & ReparsePoint)
414 {
415 switch(reparse_tag)
416 {
417 case IO_REPARSE_TAG_SYMLINK:
418 res |= NodeCategory::SymbolicLink;
419 break;
420 case IO_REPARSE_TAG_MOUNT_POINT:
421 res |= NodeCategory::MountPoint;
422 default:
423 ;
424 }
425 }
426 return res;
427 }
428 NodeCategory
429 CategorizeNode(UniqueHandle::pointer h) ynothrow
430 {
431 TryRet(TryCategorizeNodeAttributes(h) | TryCategorizeNodeDevice(h))
432 CatchIgnore(...)
433 return NodeCategory::Invalid;
434 }
435
436
437 UniqueHandle
438 MakeFile(const wchar_t* path, FileAccessRights desired_access,
439 FileShareMode shared_mode, CreationDisposition creation_disposition,
440 FileAttributesAndFlags attributes_and_flags) ynothrowv
441 {
442 using ystdex::underlying;
443 const auto h(::CreateFileW(Nonnull(path), underlying(
444 desired_access), underlying(shared_mode), {}, underlying(
445 creation_disposition), underlying(attributes_and_flags), {}));
446
447 return UniqueHandle(h != INVALID_HANDLE_VALUE ? h
448 : UniqueHandle::pointer());
449 }
450
451
452 bool
453 CheckWine()
454 {
455 try
456 {
457 RegistryKey k1(HKEY_CURRENT_USER, L"Software\\Wine");
458 RegistryKey k2(HKEY_LOCAL_MACHINE, L"Software\\Wine");
459
460 yunused(k1),
461 yunused(k2);
462 return true;
463 }
464 CatchIgnore(Win32Exception&)
465 return {};
466 }
467
468
469 void
470 DirectoryFindData::Deleter::operator()(pointer p) const ynothrowv
471 {
472 FilterExceptions(std::bind(YCL_WrapCall_Win32(FindClose, p), yfsig),
473 "directory find data deleter");
474 }
475
476
477 DirectoryFindData::DirectoryFindData(wstring name)
478 : dir_name(std::move(name)), find_data()
479 {
480 if(ystdex::rtrim(dir_name, L"/\\").empty())
481 dir_name = L'.';
482 YAssert(platform::EndsWithNonSeperator(dir_name),
483 "Invalid argument found.");
484
485 const auto attr(FileAttributes(::GetFileAttributesW(dir_name.c_str())));
486
487 if(attr != Invalid)
488 {
489 if(attr & Directory)
490 dir_name += L"\\*";
491 else
492 ystdex::throw_error(ENOTDIR, yfsig);
493 }
494 else
495 YCL_Raise_Win32E("GetFileAttributesW", yfsig);
496 }
497
498 NodeCategory
499 DirectoryFindData::GetNodeCategory() const ynothrow
500 {
501 if(p_node && find_data.cFileName[0] != wchar_t())
502 {
503 auto res(CategorizeNode(find_data));
504 wstring_view name(GetDirName());
505
506 name.remove_suffix(1);
507 TryInvoke([&]{
508 auto gd(ystdex::unique_guard([&]() ynothrow{
509 res |= NodeCategory::Invalid;
510 }));
511
512 // NOTE: Only existed and accessible files are considered.
513 // FIXME: Blocked. TOCTTOU access.
514 if(const auto h = MakeFile((wstring(name) + GetEntryName()).c_str(),
515 FileSpecificAccessRights::ReadAttributes,
516 FileAttributesAndFlags::NormalWithDirectory))
517 res |= TryCategorizeNodeAttributes(h.get())
518 | TryCategorizeNodeDevice(h.get());
519 ystdex::dismiss(gd);
520 });
521 return res;
522 }
523 return NodeCategory::Empty;
524 }
525
526 bool
527 DirectoryFindData::Read()
528 {
529 const auto chk_err([this](const char* fn, ErrorCode ec) YB_NONNULL(1){
530 const auto err(::GetLastError());
531
532 if(err != ec)
533 throw Win32Exception(err, fn, Err);
534 });
535
536 if(!p_node)
537 {
538 const auto h_node(::FindFirstFileW(GetDirName().c_str(), &find_data));
539
540 if(h_node != INVALID_HANDLE_VALUE)
541 p_node.reset(h_node);
542 else
543 chk_err("FindFirstFileW", ERROR_FILE_NOT_FOUND);
544 }
545 else if(!::FindNextFileW(p_node.get(), &find_data))
546 {
547 chk_err("FindNextFileW", ERROR_NO_MORE_FILES);
548 p_node.reset();
549 }
550 if(p_node)
551 return find_data.cFileName[0] != wchar_t();
552 find_data.cFileName[0] = wchar_t();
553 return {};
554 }
555
556 void
557 DirectoryFindData::Rewind() ynothrow
558 {
559 p_node.reset();
560 }
561
562
563 struct ReparsePointData::Data final
564 {
565 struct tagSymbolicLinkReparseBuffer
566 {
567 unsigned short SubstituteNameOffset;
568 unsigned short SubstituteNameLength;
569 unsigned short PrintNameOffset;
570 unsigned short PrintNameLength;
571 unsigned long Flags;
572 wchar_t PathBuffer[1];
573
574 DefGetter(const ynothrow, wstring_view, PrintName,
575 {PathBuffer + size_t(PrintNameOffset) / sizeof(wchar_t),
576 size_t(PrintNameLength / sizeof(wchar_t))})
577 };
578 struct tagMountPointReparseBuffer
579 {
580 unsigned short SubstituteNameOffset;
581 unsigned short SubstituteNameLength;
582 unsigned short PrintNameOffset;
583 unsigned short PrintNameLength;
584 wchar_t PathBuffer[1];
585
586 DefGetter(const ynothrow, wstring_view, PrintName,
587 {PathBuffer + size_t(PrintNameOffset) / sizeof(wchar_t),
588 size_t(PrintNameLength / sizeof(wchar_t))})
589 };
590 struct tagGenericReparseBuffer
591 {
592 unsigned char DataBuffer[1];
593 };
594
595 unsigned long ReparseTag;
596 unsigned short ReparseDataLength;
597 unsigned short Reserved;
598 union
599 {
600 tagSymbolicLinkReparseBuffer SymbolicLinkReparseBuffer;
601 tagMountPointReparseBuffer MountPointReparseBuffer;
602 tagGenericReparseBuffer GenericReparseBuffer;
603 };
604 };
605
606
607 ReparsePointData::ReparsePointData()
608 : pun(ystdex::default_init, &target_buffer)
609 {
610 static_assert(ystdex::is_aligned_storable<decltype(target_buffer), Data>(),
611 "Invalid buffer found.");
612 }
613 ImplDeDtor(ReparsePointData)
614
615
616 wstring
617 ResolveReparsePoint(const wchar_t* path)
618 {
619 return wstring(ResolveReparsePoint(path, ReparsePointData().Get()));
620 }
621 wstring_view
622 ResolveReparsePoint(const wchar_t* path, ReparsePointData::Data& rdb)
623 {
624 return MakeFileToDo([=, &rdb](UniqueHandle::pointer h){
625 return FetchFileInfo([&](::BY_HANDLE_FILE_INFORMATION& info)
626 -> wstring_view{
627 if(info.dwFileAttributes & ReparsePoint)
628 {
629 YCL_CallF_Win32(DeviceIoControl, h, FSCTL_GET_REPARSE_POINT, {},
630 0, &rdb, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, {}, {});
631 switch(rdb.ReparseTag)
632 {
633 case IO_REPARSE_TAG_SYMLINK:
634 return rdb.SymbolicLinkReparseBuffer.GetPrintName();
635 case IO_REPARSE_TAG_MOUNT_POINT:
636 return rdb.MountPointReparseBuffer.GetPrintName();
637 default:
638 YTraceDe(Warning, "Unsupported reparse tag '%lu' found",
639 rdb.ReparseTag);
640 ystdex::throw_error(std::errc::not_supported, yfsig);
641 }
642 }
643 throw std::invalid_argument(
644 "Specified file is not a reparse point.");
645 }, h);
646 }, path, FileAttributesAndFlags::NormalAll);
647 }
648
649
650 wstring
651 ExpandEnvironmentStrings(const wchar_t* p_src)
652 {
653 const auto w_len(YCL_CallF_Win32(ExpandEnvironmentStringsW, Nonnull(p_src),
654 {}, 0));
655 wstring wstr(w_len, wchar_t());
656
657 YCL_CallF_Win32(ExpandEnvironmentStringsW, p_src, &wstr[0], w_len);
658 return wstr;
659 }
660
661
662 size_t
663 QueryFileLinks(UniqueHandle::pointer h)
664 {
665 return FetchFileInfo([](::BY_HANDLE_FILE_INFORMATION& info){
666 return size_t(info.nNumberOfLinks);
667 }, h);
668 }
669 size_t
670 QueryFileLinks(const wchar_t* path, bool follow_reparse_point)
671 {
672 return MakeFileToDo<size_t(UniqueHandle::pointer)>(QueryFileLinks, path,
673 FollowToAttr(follow_reparse_point));
674 }
675
676 pair<VolumeID, FileID>
677 QueryFileNodeID(UniqueHandle::pointer h)
678 {
679 return FetchFileInfo([](::BY_HANDLE_FILE_INFORMATION& info) ynothrow
680 -> pair<VolumeID, FileID>{
681 return {VolumeID(info.dwVolumeSerialNumber),
682 FileID(info.nFileIndexHigh) << 32 | info.nFileIndexLow};
683 }, h);
684 }
685 pair<VolumeID, FileID>
686 QueryFileNodeID(const wchar_t* path, bool follow_reparse_point)
687 {
688 return MakeFileToDo<pair<VolumeID, FileID>(UniqueHandle::pointer)>(
689 QueryFileNodeID, path, FollowToAttr(follow_reparse_point));
690 }
691
692 std::uint64_t
693 QueryFileSize(UniqueHandle::pointer h)
694 {
695 ::LARGE_INTEGER sz;
696
697 YCL_CallF_Win32(GetFileSizeEx, h, &sz);
698
699 if(sz.QuadPart >= 0)
700 return std::uint64_t(sz.QuadPart);
701 throw std::invalid_argument("Negative file size found.");
702 }
703 std::uint64_t
704 QueryFileSize(const wchar_t* path)
705 {
706 return MakeFileToDo<std::uint64_t(UniqueHandle::pointer)>(
707 QueryFileSize, path, FileAttributesAndFlags::NormalWithDirectory);
708 }
709
710 void
711 QueryFileTime(UniqueHandle::pointer h, ::FILETIME* p_ctime, ::FILETIME* p_atime,
712 ::FILETIME* p_mtime)
713 {
714 YCL_CallF_Win32(GetFileTime, h, p_ctime, p_atime, p_mtime);
715 }
716 void
717 QueryFileTime(const wchar_t* path, ::FILETIME* p_ctime, ::FILETIME* p_atime,
718 ::FILETIME* p_mtime, bool follow_reparse_point)
719 {
720 MakeFileToDo(std::bind<void(UniqueHandle::pointer, ::FILETIME*, ::FILETIME*,
721 ::FILETIME*)>(QueryFileTime, std::placeholders::_1, p_ctime, p_atime,
722 p_mtime), path, AccessRights::GenericRead,
723 FollowToAttr(follow_reparse_point));
724 }
725
726 void
727 SetFileTime(UniqueHandle::pointer h, ::FILETIME* p_ctime, ::FILETIME* p_atime,
728 ::FILETIME* p_mtime)
729 {
730 using ::SetFileTime;
731
732 YCL_CallF_Win32(SetFileTime, h, p_ctime, p_atime, p_mtime);
733 }
734 void
735 SetFileTime(const wchar_t* path, ::FILETIME* p_ctime, ::FILETIME* p_atime,
736 ::FILETIME* p_mtime, bool follow_reparse_point)
737 {
738 MakeFileToDo(std::bind<void(UniqueHandle::pointer, ::FILETIME*, ::FILETIME*,
739 ::FILETIME*)>(SetFileTime, std::placeholders::_1, p_ctime, p_atime,
740 p_mtime), path, AccessRights::GenericWrite,
741 FollowToAttr(follow_reparse_point));
742 }
743
744 std::chrono::nanoseconds
745 ConvertTime(const ::FILETIME& file_time)
746 {
747 if(file_time.dwLowDateTime != 0 || file_time.dwHighDateTime != 0)
748 {
749 // FIXME: Local time conversion for FAT volumes.
750 // NOTE: See $2014-10 @ %Documentation::Workflow::Annual2014.
751 ::LARGE_INTEGER date;
752
753 // NOTE: The epoch is Jan. 1, 1601: 134774 days to Jan. 1, 1970, i.e.
754 // 11644473600 seconds, or 116444736000000000 * 100 nanoseconds.
755 // TODO: Strip away the magic number;
756 yunseq(date.HighPart = long(file_time.dwHighDateTime),
757 date.LowPart = file_time.dwLowDateTime);
758 return std::chrono::nanoseconds((date.QuadPart - 116444736000000000LL)
759 * 100U);
760 }
761 else
762 ystdex::throw_error(std::errc::not_supported, yfsig);
763 }
764 ::FILETIME
765 ConvertTime(std::chrono::nanoseconds file_time)
766 {
767 ::FILETIME res;
768 ::LARGE_INTEGER date;
769
770 date.QuadPart = file_time.count() / 100LL + 116444736000000000LL;
771 yunseq(res.dwHighDateTime = static_cast<unsigned long>(date.HighPart),
772 res.dwLowDateTime = date.LowPart);
773 if(res.dwLowDateTime != 0 || res.dwHighDateTime != 0)
774 return res;
775 ystdex::throw_error(std::errc::not_supported, yfsig);
776 }
777
778
779 void
780 LockFile(UniqueHandle::pointer h, std::uint64_t off, std::uint64_t len,
781 bool exclusive, bool immediate)
782 {
783 if(YB_UNLIKELY(!TryLockFile(h, off, len, exclusive, immediate)))
784 YCL_Raise_Win32E("LockFileEx", yfsig);
785 }
786
787 bool
788 TryLockFile(UniqueHandle::pointer h, std::uint64_t off, std::uint64_t len,
789 bool exclusive, bool immediate) ynothrow
790 {
791 return DoWithDefaultOverlapped([=](::OVERLAPPED& overlapped) ynothrow{
792 // NOTE: Since it can always be checked as result and this is called by
793 // %LockFile, no logging with %YCL_TraceCallF_Win32 is here.
794 return ::LockFileEx(h, (exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0UL)
795 | (immediate ? LOCKFILE_FAIL_IMMEDIATELY : 0UL), yimpl(0),
796 Low32(len), High32(len), &overlapped);
797 }, off);
798 }
799
800 bool
801 UnlockFile(UniqueHandle::pointer h, std::uint64_t off, std::uint64_t len)
802 ynothrow
803 {
804 return DoWithDefaultOverlapped([=](::OVERLAPPED& overlapped) ynothrow{
805 return
806 ::UnlockFileEx(h, yimpl(0), Low32(len), High32(len), &overlapped);
807 }, off);
808 }
809
810
811 void
812 WaitUnique(UniqueHandle::pointer h, unsigned long ms)
813 {
814 if(YB_UNLIKELY(::WaitForSingleObject(h, ms) == WAIT_FAILED))
815 YCL_Raise_Win32E("WaitForSingleObject", yfsig);
816 }
817
818 bool
819 TryWaitUnique(UniqueHandle::pointer h, unsigned long ms) ynothrow
820 {
821 return ::WaitForSingleObject(h, ms) == WAIT_OBJECT_0;
822 }
823
824
825 Mutex::Mutex(const wchar_t* name)
826 // TODO: Save last error and detect %ERROR_ALREADY_EXISTS?
827 // TODO: Use desired attributes with %::CreateMutexW?
828 : h_mutex(YCL_CallF_Win32(CreateMutexW, {}, {}, name))
829 {}
830
831 void
832 Mutex::unlock() ynothrowv
833 {
834 const auto res(YCL_TraceCallF_Win32(ReleaseMutex, native_handle()));
835
836 YAssert(res, "Narrow contract violated.");
837 yunused(res);
838 }
839
840
841 wstring
842 FetchSystemPath(size_t s)
843 {
844 return FetchFixedSystemPath(SystemPaths::System, s);
845 }
846
847 wstring
848 FetchWindowsPath(size_t s)
849 {
850 return FetchFixedSystemPath(SystemPaths::Windows, s);
851 }
852
853 } // inline namespace Windows;
854
855 #endif
856
857 } // namespace YSLib;
858
platform_ex::Windows::SetFileTime
YF_API void SetFileTime(UniqueHandle::pointer,::FILETIME *={},::FILETIME *={},::FILETIME *={})
设置文件的创建、访问和/或修改时间。
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:313
platform_ex::Windows::WaitUnique
YF_API void WaitUnique(UniqueHandle::pointer, unsigned long=INFINITE)
以指定的时间间隔上限等待句柄指定的同步对象。
YSLib::UI::ynothrow
AView &y ynothrow
Definition: YWidgetView.cpp:47
platform::containers::wstring
basic_string< wchar_t > wstring
Definition: Container.h:108
platform::msg
const string & msg
Definition: Debug.h:464
platform_ex::Windows::FileID
std::uint64_t FileID
文件标识。
Definition: MinGW32.h:825
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:680
platform_ex::Windows::ModuleProc
ystdex::remove_reference_t< decltype(*::GetProcAddress(::HMODULE(),{}))> ModuleProc
加载过程地址得到的过程类型。
Definition: MinGW32.h:222
platform_ex::Windows::QueryFileNodeID
YF_API pair< VolumeID, FileID > QueryFileNodeID(UniqueHandle::pointer)
查询文件标识。
platform_ex::Windows::QueryFileSize
YF_API std::uint64_t QueryFileSize(UniqueHandle::pointer)
查询文件大小。
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:45
platform_ex::Windows::QueryFileTime
YF_API YB_NONNULL(1) std YF_API void QueryFileTime(UniqueHandle::pointer,::FILETIME *={},::FILETIME *={},::FILETIME *={})
查询文件的创建、访问和/或修改时间。
ystdex::to_string
std::string to_string(const std::thread::id &)
转换 thread::id 为字符串表示。
FileAttributesAndFlags
FileAttributesAndFlags
Definition: MinGW32.h:504
platform
默认平台命名空间。
Definition: Container.h:47
platform_ex::Windows::FileAccessRights
YF_API FileAccessRights
Definition: MinGW32.h:593
platform_ex::Windows::TryWaitUnique
YF_API bool TryWaitUnique(UniqueHandle::pointer, unsigned long=0) ynothrow
platform::size_t
YF_API size_t
Definition: FileIO.h:1353
platform_ex::Windows::FileShareMode
YF_API FileShareMode
Definition: MinGW32.h:594
yfsig
#define yfsig
展开为表示函数签名的预定义变量的宏。
Definition: ydef.h:728
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
CHRLib::f
f(d, s)
ystdex::dismiss
auto dismiss(_type &gd) -> decltype(gd.dismiss())
解除操作。
Definition: scope_guard.hpp:138
FileAttributes
FileAttributes
文件共享模式。
Definition: MinGW32.h:447
ystdex::is_aligned_storable
判断是否可对齐存储。
Definition: type_pun.hpp:72
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:464
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:131
platform_ex::Windows::attributes_and_flags
const wchar_t FileAccessRights FileShareMode FileAttributesAndFlags attributes_and_flags ynothrowv const wchar_t FileAccessRights CreationDisposition FileAttributesAndFlags attributes_and_flags
Definition: MinGW32.h:606
YSLib::TryInvoke
ystdex::nonvoid_result_t< ystdex::result_of_t< _fCallable &&(_tParams &&...)> > TryInvoke(_fCallable &&f, _tParams &&...args) ynothrow
调用函数并尝试返回。
Definition: YException.h:186
YCL_Raise_Win32E
#define YCL_Raise_Win32E(...)
取转换为 errno 的 Win32 错误。
Definition: MinGW32.h:138
TryRet
#define TryRet(...)
指定表达式在 try 块中求值并返回。
Definition: YBaseMacro.h:124
CHRLib::args
_tParams && args
Definition: CharacterProcessing.h:538
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:679
platform::containers::string
basic_string< char > string
Definition: Container.h:101
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
YSLib::Text::buf
const char * buf
Definition: TextFile.h:81
platform::KeyCategory::Character
表示产生字符的键。
Definition: Keys.h:111
YCL_CallF_Win32
#define YCL_CallF_Win32(_fn,...)
Definition: MinGW32.h:190
ystdex::unique_raw
std::unique_ptr< _type > unique_raw(_pSrc *p)
Definition: memory.hpp:740
platform::KeyCodes::DS::L
Definition: Keys.h:227
YSLib::YAssert
YAssert(!(v< Deref(a)),"Value less than lower bound found.")
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1022
platform_ex::Windows::proc
const char * proc
Definition: MinGW32.h:240
platform_ex::Windows::WCSToUTF8
const char *str string_view sv WCSToUTF8
Definition: NLS.h:79
YSLib::RecordLevel
YF_API RecordLevel
Definition: YException.h:142
ystdex::wstring_view
basic_string_view< wchar_t > wstring_view
Definition: string_view.hpp:418
ystdex::throw_error
void throw_error(std::error_code ec, _tParams &&...args)
抛出错误： std::system_error 或允许相同构造函数参数的异常。
Definition: ystdex/exception.h:206
YSLib::PDefH
PDefH(Environment &, FetchEnvironment,) ImplRet(FetchGlobalInstance().GetEnvironmentRef()) inline PDefH(GUIHost &
取单一环境对象引用。
platform_ex::Windows::UnlockFile
bool UnlockFile(UniqueHandle::pointer, std::uint64_t=0, std::uint64_t=std::uint64_t(-1)) ynothrow
解锁文件。
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
YSLib::FilterExceptions
bool FilterExceptions(_func f, const char *desc={}, RecordLevel lv=Alert, ExceptionTracer trace=ExtractAndTrace) ynothrow
调用函数并过滤宿主异常。
Definition: YException.h:203
container.hpp
通用容器操作。
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
ystdex
特性测试宏。
Definition: ydef.h:822
platform::sig
const string const char *sig const char * sig
Definition: Debug.h:473
platform_ex::Windows::Invalid
Definition: MinGW32.h:471
platform_ex::Windows::creation_disposition
const wchar_t FileAccessRights FileShareMode FileAttributesAndFlags attributes_and_flags ynothrowv const wchar_t FileAccessRights CreationDisposition creation_disposition
Definition: MinGW32.h:603
YCL_WrapCall_Win32
#define YCL_WrapCall_Win32(_fn,...)
调用 Win32 API 或其它可用 ::GetLastError 取得调用状态的例程。
Definition: MinGW32.h:177
platform_ex::Windows::VolumeID
std::uint32_t VolumeID
卷序列号。
Definition: MinGW32.h:827
YModules.h
YSLib::yimpl
YF_API yimpl(GUIApplication &) FetchGlobalInstance()
取全局应用程序实例。
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:168
platform_ex::Windows::IsDirectory
yconstfn IsDirectory
Definition: MinGW32.h:522
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:968
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:786
ystdex::underlying
underlying_type_t< _type > underlying(_type val)
取枚举值的底层整数。
Definition: utility.hpp:240
ystdex::rtrim
_tString && rtrim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续后缀字符。
Definition: string.hpp:676
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
platform_ex::Windows::FetchWindowsPath
YF_API wstring FetchWindowsPath(size_t=MAX_PATH)
取系统目录路径。
YSLib::YB_NONNULL
YF_API YB_NONNULL(1, 2) ValueNode LoadNPLA1File(const char *disp
载入 NPLA1 配置文件。
platform_ex::Windows::QueryFileLinks
YF_API size_t QueryFileLinks(UniqueHandle::pointer)
查询文件链接数。
std
Definition: memory.hpp:1183
YSLib::ImplRet
ImplRet(FetchGlobalInstance().GetGUIHostRef()) YF_API void Execute(GUIApplication &
执行程序主消息循环。
platform_ex::Windows::TryLockFile
bool TryLockFile(UniqueHandle::pointer, std::uint64_t=0, std::uint64_t=std::uint64_t(-1), bool=true, bool=true) ynothrow
DefGetter
#define DefGetter(_q, _t, _n,...)
Definition: YBaseMacro.h:241
platform_ex::Windows::NormalWithDirectory
Definition: MinGW32.h:506
platform::Nonnull
_type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:422
platform_ex::Windows::NormalAll
Definition: MinGW32.h:507
platform::ComposeMessageWithSignature
ComposeMessageWithSignature
Definition: Debug.h:464
platform::Descriptions::Warning
Definition: YCommon.h:167
platform::Descriptions::Err
Definition: YCommon.h:166
scope_guard.hpp
作用域守护。
platform_ex::Windows::MakeFile
MakeFile
Definition: MinGW32.h:598
platform_ex
平台扩展命名空间。
Definition: Android.h:45
platform_ex::Windows::CreationDisposition
YF_API CreationDisposition
Definition: MinGW32.h:595
YSLib::UI::name
yconstfn const string & name
Definition: Loader.h:130
platform_ex::Windows::shared_mode
const wchar_t FileAccessRights FileShareMode shared_mode
Definition: MinGW32.h:598
YSLib::Text::str
const char const char * str
Definition: TextFile.h:81
platform::KeyCodes::Win32::Empty
Definition: Keys.h:279
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:995
YCL_TraceCallF_Win32
#define YCL_TraceCallF_Win32(_fn,...)
Definition: MinGW32.h:211
platform_ex::Windows::FetchSystemPath
YF_API wstring FetchSystemPath(size_t=MAX_PATH)
取系统目录路径。
platform_ex::Windows::ErrorCode
unsigned long ErrorCode
Definition: MinGW32.h:57
platform::KeyCategory::System
表示系统键（如 SysRq/PrintScr 、 Break/Pause 和电源管理）。
Definition: Keys.h:125
platform_ex::Windows::TryCategorizeNodeDevice
yconstfnconst::WIN32_FIND_DATAA &d ynothrowconst::WIN32_FIND_DATAW &d ynothrow ImplRet(IsDirectory(FileAttributes(d.dwFileAttributes))) YF_API platform YF_API platform::NodeCategory TryCategorizeNodeDevice(UniqueHandle::pointer)
按打开的文件句柄归类节点从属的属性类别。
platform_ex::Windows::desired_access
const wchar_t FileAccessRights desired_access
Definition: MinGW32.h:598
YSLib::UI::empty
!sv empty()&&sv.front()!
platform::CategorizeNode
enum NodeCategory std::uint_least32_t YF_API NodeCategory CategorizeNode(mode_t) ynothrow
文件节点类别。
Definition: FileIO.cpp:388
ystdex::make_unique_default_init
enable_if_t<!is_array< _type >::value, std::unique_ptr< _type > > make_unique_default_init()
Definition: memory.hpp:879
platform_ex::Windows::ConvertTime
YF_API std::chrono::nanoseconds ConvertTime(const ::FILETIME &)
转换文件时间为以 POSIX 历元起始度量的时间间隔。
ystdex::default_init
const struct ystdex::default_init_t default_init
YSLib::IO::int
YF_API int
Definition: File.h:51
YB_ATTR_fallthrough
#define YB_ATTR_fallthrough
用于 switch 语句的 fallthrough 属性。
Definition: ydef.h:383
platform_ex::Windows::ReparsePoint
Definition: MinGW32.h:458
YSLib::path
YF_API const char * path
Definition: Initialization.h:77
platform_ex::Windows::ConvertToErrno
YF_API YB_STATELESS int ConvertToErrno(ErrorCode) ynothrow
转换 Win32 错误为 errno 。
platform_ex::Windows::LockFile
void LockFile(UniqueHandle::pointer, std::uint64_t=0, std::uint64_t=std::uint64_t(-1), bool=true, bool={})
锁定文件。
platform_ex::Windows::FetchModuleFileName
YF_API wstring FetchModuleFileName(::HMODULE={}, YSLib::RecordLevel=YSLib::Err)
取模块映像路径。
ystdex::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:415
YCL_Trace_Win32E
#define YCL_Trace_Win32E(_lv, _fn, _sig)
跟踪 ::GetLastError 取得的调用状态结果。
Definition: MinGW32.h:157
CHRLib::p
const auto p(d)
YSLib::lv
RecordLevel lv
Definition: YException.cpp:58
platform_ex::Windows::Directory
Definition: MinGW32.h:452
YSLib::UI::ImplDeDtor
ImplDeDtor(Thumb) void DecorateAsCloseButton(Thumb &tmb)
Definition: Button.cpp:125