YSTest: FileIO.cpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

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

- 文件列表
- 文件成员

FileIO.cpp
浏览该文件的文档.
1 /*
2 © 2011-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
28 #undef __STRICT_ANSI__ // for ::fileno, ::pclose, ::popen, ::_wfopen;
29 #include "YCLib/YModules.h"
30 #include YFM_YCLib_FileIO // for std::is_same, ystdex::underlying_type_t,
31 // RetryOnInterrupted, std::errc::function_not_supported, YCL_CallF_CAPI,
32 // std::is_integral, ystdex::invoke, Nonnull, ystdex::temporary_buffer;
33 #include YFM_YCLib_NativeAPI // for Mode, ::HANDLE, struct ::stat,
34 // platform_ex::cstat, platform_ex::estat, ::futimens, OpenMode,
35 // YCL_CallGlobal, ::close, ::fcntl, F_GETFL, ::setmode, ::fchmod, ::_chsize,
36 // ::ftruncate, ::fsync, ::_wgetcwd, ::getcwd, ::chdir, ::rmdir, ::unlink,
37 // !defined(__STRICT_ANSI__) API, ::GetCurrentDirectoryW;
38 #include YFM_YCLib_FileSystem // for NodeCategory::*, CategorizeNode;
39 #include <ystdex/functional.hpp> // for ystdex::compose, ystdex::addrof;
40 #include <ystdex/streambuf.hpp> // for ystdex::streambuf_equal;
41 #if YCL_DS
42 # include "CHRLib/YModules.h"
43 # include YFM_CHRLib_CharacterProcessing // for CHRLib::MakeMBCS,
44 // CHRLib::MakeUCS2LE;
45
46 #elif YCL_Win32
47 # if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
48 // At least one headers of <stdlib.h>, <stdio.h>, <Windows.h>, <Windef.h>
49 // (and probably more) should have been included to make the MinGW-W64 macro
50 // available if it is really being used.
51 # undef _fileno
52 # endif
53 # include YFM_Win32_YCLib_MinGW32 // for platform_ex::FileAttributes,
54 // platform_ex::GetErrnoFromWin32, platform_ex::QueryFileLinks,
55 // platform_ex::QueryFileNodeID, platform_ex::QueryFileTime,
56 // platform_ex::ConvertTime, platform_ex::SetFileTime, platform_ex::UnlockFile,
57 // platform_ex::LockFile, platform_ex::TryLockFile;
58 # include YFM_Win32_YCLib_NLS // for platform_ex::UTF8ToWCS,
59 // platform_ex::WCSToUTF8;
60
62 using platform_ex::FileAttributes;
63 using platform_ex::GetErrnoFromWin32;
65 using platform_ex::QueryFileLinks;
67
68 using platform_ex::QueryFileNodeID;
69 using platform_ex::QueryFileTime;
71 using platform_ex::UTF8ToWCS;
72 using platform_ex::ConvertTime;
74 using platform_ex::MakePathStringW;
76 #elif YCL_API_POSIXFileSystem
77 # include "CHRLib/YModules.h"
78 # include YFM_CHRLib_CharacterProcessing // for CHRLib::MakeMBCS,
79 // CHRLib::MakeUCS2LE;
80 # include <sys/file.h> // for ::flock, LOCK_*;
81
83 using namespace CHRLib;
84 #else
85 # error "Unsupported platform found."
86 #endif
87
88 namespace platform
89 {
90
92 static_assert(std::is_same<mode_t, ystdex::underlying_type_t<Mode>>::value,
93 "Mismatched mode types found.");
94
95 namespace
96 {
97
99 using platform_ex::estat;
101 using platform_ex::cstat;
102 #if YCL_Win32
103 using platform_ex::ToHandle;
105
107 void
108 QueryFileTime(const char* path, ::FILETIME* p_ctime, ::FILETIME* p_atime,
109 ::FILETIME* p_mtime, bool follow_reparse_point)
110 {
111 QueryFileTime(MakePathStringW(path).c_str(), p_ctime, p_atime, p_mtime,
112 follow_reparse_point);
113 }
115
116 void
117 QueryFileTime(int fd, ::FILETIME* p_ctime, ::FILETIME* p_atime,
118 ::FILETIME* p_mtime)
119 {
120 QueryFileTime(ToHandle(fd), p_ctime, p_atime, p_mtime);
121 }
122
123 // TODO: Blocked. Use C++14 generic lambda expressions.
124 yconstexpr const struct
125 {
126 template<typename _tParam, typename... _tParams>
127 FileTime
128 operator()(_tParam arg, _tParams... args) const
129 {
130 ::FILETIME atime{};
131
132 QueryFileTime(arg, {}, &atime, {}, args...);
133 return ConvertTime(atime);
134 }
135 } get_st_atime{};
136 yconstexpr const struct
137 {
138 template<typename _tParam, typename... _tParams>
139 FileTime
140 operator()(_tParam arg, _tParams... args) const
141 {
142 ::FILETIME mtime{};
143
144 QueryFileTime(arg, {}, {}, &mtime, args...);
145 return ConvertTime(mtime);
146 }
147 } get_st_mtime{};
148 yconstexpr const struct
149 {
150 template<typename _tParam, typename... _tParams>
151 array<FileTime, 2>
152 operator()(_tParam arg, _tParams... args) const
153 {
154 ::FILETIME mtime{}, atime{};
155
156 QueryFileTime(arg, {}, &atime, &mtime, args...);
157 return array<FileTime, 2>{ConvertTime(mtime), ConvertTime(atime)};
158 }
159 } get_st_matime{};
161
163
164 YB_NONNULL(1) bool
165 UnlinkWithAttr(const wchar_t* path, FileAttributes attr) ynothrow
166 {
167 return !(attr & FileAttributes::ReadOnly) || ::SetFileAttributesW(path,
168 attr & ~FileAttributes::ReadOnly) ? ::_wunlink(path) == 0
169 : (errno = GetErrnoFromWin32(), false);
170 }
171
172 template<typename _func>
173 YB_NONNULL(2) bool
174 CallFuncWithAttr(_func f, const char* path)
175 {
176 const auto& wpath(MakePathStringW(path));
177 const auto& wstr(wpath.c_str());
178 const auto attr(FileAttributes(::GetFileAttributesW(wstr)));
179
180 return attr != platform_ex::Invalid ? f(wstr, attr)
181 : (errno = GetErrnoFromWin32(), false);
182 }
184 #else
185 inline PDefH(::timespec, ToTimeSpec, FileTime ft) ynothrow
186 ImplRet({std::time_t(ft.count() / 1000000000LL),
187 long(ft.count() % 1000000000LL)})
188
189 void
191 SetFileTime(int fd, const ::timespec(&times)[2])
192 {
193 #if YCL_DS
194 // XXX: Hack.
195 #ifndef UTIME_OMIT
196 # define UTIME_OMIT (-1L)
197 #endif
198 yunused(fd), yunused(times);
199 ystdex::throw_error(std::errc::function_not_supported, yfsig);
200 #else
201 YCL_CallF_CAPI(, ::futimens, fd, times);
202 #endif
203 }
204
206
207 const auto get_st_atime([](struct ::stat& st){
208 return FileTime(st.st_atime);
209 });
210 const auto get_st_mtime([](struct ::stat& st){
211 return FileTime(st.st_mtime);
212 });
213 const auto get_st_matime([](struct ::stat& st){
214 return array<FileTime, 2>{FileTime(st.st_mtime), FileTime(st.st_atime)};
215 });
217
219
220 static_assert(std::is_integral<::dev_t>(),
221 "Nonconforming '::dev_t' type found.");
222 static_assert(std::is_unsigned<::ino_t>(),
223 "Nonconforming '::ino_t' type found.");
224
225 inline PDefH(FileNodeID, get_file_node_id, struct ::stat& st) ynothrow
226 ImplRet({std::uint64_t(st.st_dev), std::uint64_t(st.st_ino)})
228 inline YB_NONNULL(2, 4) PDefH(void, cstat, struct ::stat& st,
230 const char16_t* path, bool follow_link, const char* sig)
231 ImplRet(cstat(st, MakePathString(path).c_str(), follow_link, sig))
233 inline YB_NONNULL(2) PDefH(int, estat, struct ::stat& st, const char16_t* path,
234 bool follow_link)
235 ImplRet(estat(st, MakePathString(path).c_str(), follow_link))
236 #endif
237
239 template<typename _func, typename... _tParams>
240 auto
241 FetchFileTime(_func f, _tParams... args)
242 #if YCL_Win32
243 -> ystdex::result_of_t<_func(_tParams&...)>
244 #else
245 -> ystdex::result_of_t<_func(struct ::stat&)>
246 #endif
247 {
248 #if YCL_Win32
249 // NOTE: The %::FILETIME has resolution of 100 nanoseconds.
250 // XXX: Error handling for indirect calls.
251 return f(args...);
252 #else
253 // TODO: Get more precise time count.
254 struct ::stat st;
255
256 cstat(st, args..., yfsig);
257 return f(st);
258 #endif
259 }
260
262 template<int _vErr, typename _fCallable, class _tObj, typename _tByteBuf,
263 typename... _tParams>
264 _tByteBuf
265 FullReadWrite(_fCallable f, _tObj&& obj, _tByteBuf ptr, size_t nbyte,
266 _tParams&&... args)
267 {
268 while(nbyte > 0)
269 {
270 const auto n(ystdex::invoke(f, obj, ptr, nbyte, yforward(args)...));
271
272 if(n == size_t(-1))
273 break;
274 if(n == 0)
275 {
276 errno = _vErr;
277 break;
278 }
279 yunseq(ptr += n, nbyte -= n);
280 }
281 return ptr;
282 }
283
285
286 #if YCL_Win64
287 using rwsize_t = unsigned;
288 #else
289 using rwsize_t = size_t;
290 #endif
291
292 template<typename _func, typename _tBuf>
293 size_t
294 SafeReadWrite(_func f, int fd, _tBuf buf, rwsize_t nbyte) ynothrowv
295 {
296 YAssert(fd != -1, "Invalid file descriptor found.");
297 return size_t(RetryOnInterrupted([&]{
298 return f(fd, Nonnull(buf), nbyte);
299 }));
300 }
302
303 #if !YCL_DS
304 YB_NONNULL(2) void
306 UnlockFileDescriptor(int fd, const char* sig) ynothrowv
307 {
308 # if YCL_Win32
309 const auto res(platform_ex::UnlockFile(ToHandle(fd)));
310
311 if(YB_UNLIKELY(!res))
312 YCL_Trace_Win32E(Descriptions::Warning, UnlockFileEx, sig);
313 YAssert(res, "Narrow contract violated.");
314 # else
315 const auto res(YCL_TraceCall_CAPI(::flock, sig, fd, LOCK_UN));
316
317 YAssert(res == 0, "Narrow contract violated.");
318 yunused(res);
319 # endif
320 }
321 #endif
322
324 bool
325 IsNodeShared_Impl(const char* a, const char* b, bool follow_link) ynothrow
326 {
327 #if YCL_Win32
328 return CallNothrow({}, [=]{
329 return QueryFileNodeID(MakePathStringW(a).c_str(), follow_link)
330 == QueryFileNodeID(MakePathStringW(b).c_str(), follow_link);
331 });
332 #else
333 struct ::stat st;
334
335 if(estat(st, a, follow_link) != 0)
336 return {};
337
338 const auto id(get_file_node_id(st));
339
340 if(estat(st, b, follow_link) != 0)
341 return {};
342
343 return IsNodeShared(id, get_file_node_id(st));
344 #endif
345 }
347 bool
348 IsNodeShared_Impl(const char16_t* a, const char16_t* b, bool follow_link)
349 ynothrow
350 {
351 #if YCL_Win32
352 return CallNothrow({}, [=]{
353 return QueryFileNodeID(wcast(a), follow_link)
354 == QueryFileNodeID(wcast(b), follow_link);
355 });
356 #else
357 return IsNodeShared_Impl(MakePathString(a).c_str(),
358 MakePathString(b).c_str(), follow_link);
359 #endif
360 }
361
363 template<typename _tChar>
364 YB_NONNULL(1, 2) pair<UniqueFile, UniqueFile>
365 HaveSameContents_Impl(const _tChar* path_a, const _tChar* path_b, mode_t mode)
366 {
367 if(UniqueFile p_a{uopen(path_a, int(OpenMode::ReadRaw), mode)})
368 if(UniqueFile p_b{uopen(path_b, int(OpenMode::ReadRaw), mode)})
369 return {std::move(p_a), std::move(p_b)};
370 return {};
371 }
372
373 } // unnamed namespace;
374
375
376 string
377 MakePathString(const char16_t* s)
378 {
379 #if YCL_Win32
380 return platform_ex::WCSToUTF8(wcast(s));
381 #else
382 return CHRLib::MakeMBCS(s);
383 #endif
384 }
385
386
387 NodeCategory
388 CategorizeNode(mode_t st_mode) ynothrow
389 {
390 auto res(NodeCategory::Empty);
391 const auto m(Mode(st_mode) & Mode::FileType);
392
393 if((m & Mode::Directory) == Mode::Directory)
394 res |= NodeCategory::Directory;
395 #if !YCL_Win32
396 if((m & Mode::Link) == Mode::Link)
397 res |= NodeCategory::Link;
398 #endif
399 if((m & Mode::Regular) == Mode::Regular)
400 res |= NodeCategory::Regular;
401 if(YB_UNLIKELY((m & Mode::Character) == Mode::Character))
402 res |= NodeCategory::Character;
403 #if !YCL_Win32
404 else if(YB_UNLIKELY((m & Mode::Block) == Mode::Block))
405 res |= NodeCategory::Block;
406 #endif
407 if(YB_UNLIKELY((m & Mode::FIFO) == Mode::FIFO))
408 res |= NodeCategory::FIFO;
409 #if !YCL_Win32
410 if((m & Mode::Socket) == Mode::Socket)
411 res |= NodeCategory::Socket;
412 #endif
413 return res;
414 }
415
416
417 void
418 FileDescriptor::Deleter::operator()(pointer p) const ynothrow
419 {
420 if(p && YB_UNLIKELY(YCL_CallGlobal(close, *p) < 0))
421 // NOTE: This is not a necessarily error. See $2016-04
422 // @ %Documentation::Workflow::Annual2016.
423 YTraceDe(Descriptions::Warning,
424 "Falied closing file descriptor, errno = %d.", errno);
425 }
426
427
428 FileDescriptor::FileDescriptor(std::FILE* fp) ynothrow
429 : desc(fp ? YCL_CallGlobal(fileno, fp) : -1)
430 {}
431
432 FileTime
433 FileDescriptor::GetAccessTime() const
434 {
435 return FetchFileTime(get_st_atime, desc);
436 }
437 NodeCategory
438 FileDescriptor::GetCategory() const ynothrow
439 {
440 #if YCL_Win32
441 return platform_ex::CategorizeNode(ToHandle(desc));
442 #else
443 struct ::stat st;
444
445 return estat(st, desc) == 0 ? CategorizeNode(st.st_mode)
446 : NodeCategory::Invalid;
447 #endif
448 }
449 int
450 FileDescriptor::GetFlags() const
451 {
452 #if YCL_API_POSIXFileSystem
453 return YCL_CallF_CAPI(, ::fcntl, desc, F_GETFL);
454 #else
455 ystdex::throw_error(std::errc::function_not_supported, yfsig);
456 #endif
457 }
458 mode_t
459 FileDescriptor::GetMode() const
460 {
461 struct ::stat st;
462
463 cstat(st, desc, yfsig);
464 return st.st_mode;
465 }
466 FileTime
467 FileDescriptor::GetModificationTime() const
468 {
469 return FetchFileTime(get_st_mtime, desc);
470 }
471 array<FileTime, 2>
472 FileDescriptor::GetModificationAndAccessTime() const
473 {
474 return FetchFileTime(get_st_matime, desc);
475 }
476 FileNodeID
477 FileDescriptor::GetNodeID() const ynothrow
478 {
479 #if YCL_Win32
480 return CallNothrow({}, [=]{
481 return QueryFileNodeID(ToHandle(desc));
482 });
483 #else
484 struct ::stat st;
485
486 return estat(st, desc) == 0 ? get_file_node_id(st) : FileNodeID();
487 #endif
488 }
489 size_t
490 FileDescriptor::GetNumberOfLinks() const ynothrow
491 {
492 #if YCL_Win32
493 return CallNothrow({}, [=]{
494 return QueryFileLinks(ToHandle(desc));
495 });
496 #else
497 struct ::stat st;
498 static_assert(std::is_unsigned<decltype(st.st_nlink)>(),
499 "Unsupported 'st_nlink' type found.");
500
501 return estat(st, desc) == 0 ? size_t(st.st_nlink) : size_t();
502 #endif
503 }
504 std::uint64_t
505 FileDescriptor::GetSize() const
506 {
507 #if YCL_Win32
508 return platform_ex::QueryFileSize(ToHandle(desc));
509 #else
510 struct ::stat st;
511
512 YCL_CallF_CAPI(, ::fstat, desc, &st);
513
514 // XXX: No negative file size should be found. See also:
515 // http://stackoverflow.com/questions/12275831/why-is-the-st-size-field-in-struct-stat-signed.
516 if(st.st_size >= 0)
517 return std::uint64_t(st.st_size);
518 throw std::invalid_argument("Negative file size found.");
519 #endif
520 }
521
522 void
523 FileDescriptor::SetAccessTime(FileTime ft) const
524 {
525 #if YCL_Win32
526 auto atime(ConvertTime(ft));
527
528 platform_ex::SetFileTime(ToHandle(desc), {}, &atime, {});
529 #else
530 const ::timespec times[]{ToTimeSpec(ft), {yimpl(0), UTIME_OMIT}};
531
532 SetFileTime(desc, times);
533 #endif
534 }
535 bool
536 FileDescriptor::SetBlocking() const
537 {
538 #if YCL_API_POSIXFileSystem
539 // NOTE: Read-modify-write operation is needed for compatibility.
540 // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html.
541 const auto oflags((OpenMode(GetFlags())));
542
543 return bool(oflags & OpenMode::Nonblocking)
544 ? (SetFlags(int(oflags & ~OpenMode::Nonblocking)), true) : false;
545 #else
546 ystdex::throw_error(std::errc::function_not_supported, yfsig);
547 #endif
548 }
549 void
550 FileDescriptor::SetFlags(int flags) const
551 {
552 #if YCL_API_POSIXFileSystem
553 YCL_CallF_CAPI(, ::fcntl, desc, F_SETFL, flags);
554 #else
555 // TODO: Try using NT6 %::SetFileInformationByHandle for Win32.
556 yunused(flags);
557 ystdex::throw_error(std::errc::function_not_supported, yfsig);
558 #endif
559 }
560 void
561 FileDescriptor::SetMode(mode_t mode) const
562 {
563 #if YCL_API_POSIXFileSystem
564 YCL_CallF_CAPI(, ::fchmod, desc, mode);
565 #else
566 yunused(mode);
567 ystdex::throw_error(std::errc::function_not_supported, yfsig);
568 #endif
569 }
570 void
571 FileDescriptor::SetModificationTime(FileTime ft) const
572 {
573 #if YCL_Win32
574 auto mtime(ConvertTime(ft));
575
576 platform_ex::SetFileTime(ToHandle(desc), {}, {}, &mtime);
577 #else
578 const ::timespec times[]{{yimpl(0), UTIME_OMIT}, ToTimeSpec(ft)};
579
580 SetFileTime(desc, times);
581 #endif
582 }
583 void
584 FileDescriptor::SetModificationAndAccessTime(array<FileTime, 2> fts) const
585 {
586 #if YCL_Win32
587 auto atime(ConvertTime(fts[0])), mtime(ConvertTime(fts[1]));
588
589 platform_ex::SetFileTime(ToHandle(desc), {}, &atime, &mtime);
590 #else
591 const ::timespec times[]{ToTimeSpec(fts[0]), ToTimeSpec(fts[1])};
592
593 SetFileTime(desc, times);
594 #endif
595 }
596 bool
597 FileDescriptor::SetNonblocking() const
598 {
599 #if YCL_API_POSIXFileSystem
600 // NOTE: Read-modify-write operation is need for compatibility.
601 // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html.
602 const auto oflags((OpenMode(GetFlags())));
603
604 return !bool(oflags & OpenMode::Nonblocking)
605 ? (SetFlags(int(oflags | OpenMode::Nonblocking)), true) : false;
606 #else
607 ystdex::throw_error(std::errc::function_not_supported, yfsig);
608 #endif
609 }
610 bool
611 FileDescriptor::SetSize(size_t size) ynothrow
612 {
613 #if YCL_Win32
614 return ::_chsize(desc, long(size)) == 0;
615 #else
616 // FIXME: It seems that on Android 32-bit size is always used even if
617 // '_FILE_OFFSET_BITS == 1'. Thus it is not safe and would better to be
618 // ignored slightly.
619 return ::ftruncate(desc, ::off_t(size)) == 0;
620 #endif
621 }
622 int
623 FileDescriptor::SetTranslationMode(int mode) const ynothrow
624 {
625 // TODO: Other platforms.
626 #if YCL_Win32 || (defined(_NEWLIB_VERSION) && defined(__SCLE))
627 return YCL_CallGlobal(setmode, desc, mode);
628 #else
629 // NOTE: No effect.
630 yunused(mode);
631 return 0;
632 #endif
633 }
634
635 void
636 FileDescriptor::Flush()
637 {
638 #if YCL_Win32
639 YCL_CallF_CAPI(, ::_commit, desc);
640 #else
641 // XXX: http://austingroupbugs.net/view.php?id=672.
642 YCL_CallF_CAPI(, ::fsync, desc);
643 #endif
644 }
645
646 size_t
647 FileDescriptor::FullRead(void* buf, size_t nbyte) ynothrowv
648 {
649 using namespace std::placeholders;
650 const auto p_buf(static_cast<char*>(buf));
651
652 return size_t(FullReadWrite<0>(&FileDescriptor::Read, this, p_buf, nbyte)
653 - p_buf);
654 }
655
656 size_t
657 FileDescriptor::FullWrite(const void* buf, size_t nbyte) ynothrowv
658 {
659 using namespace std::placeholders;
660 const auto p_buf(static_cast<const char*>(buf));
661
662 return size_t(FullReadWrite<ENOSPC>(&FileDescriptor::Write, this, p_buf,
663 nbyte) - p_buf);
664 }
665
666 size_t
667 FileDescriptor::Read(void* buf, size_t nbyte) ynothrowv
668 {
669 return SafeReadWrite(YCL_ReservedGlobal(read), desc, buf, rwsize_t(nbyte));
670 }
671
672 size_t
673 FileDescriptor::Write(const void* buf, size_t nbyte) ynothrowv
674 {
675 return SafeReadWrite(YCL_ReservedGlobal(write), desc, buf, rwsize_t(nbyte));
676 }
677
678 void
679 FileDescriptor::WriteContent(FileDescriptor ofd, FileDescriptor ifd,
680 byte* buf, size_t size)
681 {
682 YAssertNonnull(ifd),
683 YAssertNonnull(ofd),
684 YAssertNonnull(buf),
685 YAssert(size != 0, "Invalid size found.");
686
687 ystdex::retry_on_cond([&](size_t len){
688 if(len == size_t(-1))
689 YCL_Raise_SysE(, "Failed reading source file '" + to_string(*ifd),
690 yfsig);
691 if(ofd.FullWrite(buf, len) == size_t(-1))
692 YCL_Raise_SysE(,
693 "Failed writing destination file '" + to_string(*ofd), yfsig);
694 return len != 0;
695 }, &FileDescriptor::Read, &ifd, buf, size);
696 }
697 void
698 FileDescriptor::WriteContent(FileDescriptor ofd, FileDescriptor ifd,
699 size_t size)
700 {
701 ystdex::temporary_buffer<byte> buf(size);
702
703 WriteContent(ofd, ifd, buf.get().get(), buf.size());
704 }
705
706 void
707 FileDescriptor::lock()
708 {
709 #if YCL_DS
710 #elif YCL_Win32
711 platform_ex::LockFile(ToHandle(desc));
712 #else
713 YCL_CallF_CAPI(, ::flock, desc, LOCK_EX);
714 #endif
715 }
716
717 void
718 FileDescriptor::lock_shared()
719 {
720 #if YCL_DS
721 #elif YCL_Win32
722 platform_ex::LockFile(ToHandle(desc), 0, std::uint64_t(-1), {});
723 #else
724 YCL_CallF_CAPI(, ::flock, desc, LOCK_SH);
725 #endif
726 }
727
728 bool
729 FileDescriptor::try_lock() ynothrowv
730 {
731 #if YCL_DS
732 return true;
733 #elif YCL_Win32
734 return platform_ex::TryLockFile(ToHandle(desc), 0, std::uint64_t(-1));
735 #else
736 return YCL_TraceCallF_CAPI(::flock, desc, LOCK_EX | LOCK_NB) != -1;
737 #endif
738 }
739
740 bool
741 FileDescriptor::try_lock_shared() ynothrowv
742 {
743 #if YCL_DS
744 return true;
745 #elif YCL_Win32
746 return platform_ex::TryLockFile(ToHandle(desc), 0, std::uint64_t(-1), {});
747 #else
748 return YCL_TraceCallF_CAPI(::flock, desc, LOCK_SH | LOCK_NB) != -1;
749 #endif
750 }
751
752 void
753 FileDescriptor::unlock() ynothrowv
754 {
755 #if YCL_DS
756 #else
757 UnlockFileDescriptor(desc, yfsig);
758 #endif
759 }
760
761 void
762 FileDescriptor::unlock_shared() ynothrowv
763 {
764 #if YCL_DS
765 #else
766 UnlockFileDescriptor(desc, yfsig);
767 #endif
768 }
769
770
771 mode_t
772 DefaultPMode() ynothrow
773 {
774 #if YCL_Win32
775 // XXX: For compatibility with newer version of MSVCRT, no %_umask call
776 // would be considered. See https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx.
777 return mode_t(Mode::UserReadWrite);
778 #else
779 return mode_t(Mode::UserReadWrite | Mode::GroupReadWrite | Mode::OtherRead);
780 #endif
781 }
782
783 void
784 SetBinaryIO(std::FILE* stream) ynothrowv
785 {
786 #if YCL_Win32
787 FileDescriptor(Nonnull(stream)).SetTranslationMode(int(OpenMode::Binary));
788 #else
789 // NOTE: No effect.
790 Nonnull(stream);
791 #endif
792 }
793
794
795 int
796 omode_conv(std::ios_base::openmode mode) ynothrow
797 {
798 using namespace std;
799 auto res(OpenMode::None);
800
801 switch(unsigned((mode &= ~ios_base::ate)
802 & ~(ios_base::binary | ios_nocreate | ios_noreplace)))
803 {
804 case ios_base::out:
805 res = OpenMode::Create | OpenMode::Write;
806 break;
807 case ios_base::out | ios_base::trunc:
808 res = OpenMode::Create | OpenMode::WriteTruncate;
809 break;
810 case ios_base::out | ios_base::app:
811 case ios_base::app:
812 res = OpenMode::Create | OpenMode::WriteAppend;
813 break;
814 case ios_base::in:
815 res = OpenMode::Read;
816 break;
817 case ios_base::in | ios_base::out:
818 res = OpenMode::ReadWrite;
819 break;
820 case ios_base::in | ios_base::out | ios_base::trunc:
821 res = OpenMode::Create | OpenMode::ReadWriteTruncate;
822 break;
823 case ios_base::in | ios_base::out | ios_base::app:
824 case ios_base::in | ios_base::app:
825 res = OpenMode::Create | OpenMode::ReadWriteAppend;
826 break;
827 default:
828 return int(res);
829 }
830 // XXX: Order is significant.
831 if(mode & ios_noreplace)
832 res |= OpenMode::CreateExclusive;
833 // NOTE: %O_EXCL without %O_CREAT leads to undefined behavior in POSIX.
834 if(mode & ios_nocreate)
835 res &= ~OpenMode::CreateExclusive;
836 return int(res);
837 }
838
839 int
840 omode_convb(std::ios_base::openmode mode) ynothrow
841 {
842 return omode_conv(mode)
843 | int(mode & std::ios_base::binary ? OpenMode::Binary : OpenMode::Text);
844 }
845
846
847 int
848 uaccess(const char* path, int amode) ynothrowv
849 {
850 YAssertNonnull(path);
851 #if YCL_Win32
852 return CallNothrow(-1, [=]{
853 return ::_waccess(MakePathStringW(path).c_str(), amode);
854 });
855 #else
856 return ::access(path, amode);
857 #endif
858 }
859 int
860 uaccess(const char16_t* path, int amode) ynothrowv
861 {
862 YAssertNonnull(path);
863 #if YCL_Win32
864 return ::_waccess(wcast(path), amode);
865 #else
866 return CallNothrow(-1, [=]{
867 return ::access(MakePathString(path).c_str(), amode);
868 });
869 #endif
870 }
871
872 int
873 uopen(const char* filename, int oflag, mode_t pmode) ynothrowv
874 {
875 YAssertNonnull(filename);
876 #if YCL_Win32
877 return CallNothrow(-1, [=]{
878 return ::_wopen(MakePathStringW(filename).c_str(), oflag, int(pmode));
879 });
880 #else
881 return ::open(filename, oflag, pmode);
882 #endif
883 }
884 int
885 uopen(const char16_t* filename, int oflag, mode_t pmode) ynothrowv
886 {
887 YAssertNonnull(filename);
888 #if YCL_Win32
889 return ::_wopen(wcast(filename), oflag, int(pmode));
890 #else
891 return CallNothrow(-1, [=]{
892 return ::open(MakePathString(filename).c_str(), oflag, pmode);
893 });
894 #endif
895 }
896
897 std::FILE*
898 ufopen(const char* filename, const char* mode) ynothrowv
899 {
900 YAssertNonnull(filename);
901 YAssert(Deref(mode) != char(), "Invalid argument found.");
902 #if YCL_Win32
903 return CallNothrow({}, [=]{
904 return ::_wfopen(MakePathStringW(filename).c_str(),
905 MakePathStringW(mode).c_str());
906 });
907 #else
908 return std::fopen(filename, mode);
909 #endif
910 }
911 std::FILE*
912 ufopen(const char16_t* filename, const char16_t* mode) ynothrowv
913 {
914 YAssertNonnull(filename);
915 YAssert(Deref(mode) != char(), "Invalid argument found.");
916 #if YCL_Win32
917 return ::_wfopen(wcast(filename), wcast(mode));
918 #else
919 return CallNothrow({}, [=]{
920 return std::fopen(MakePathString(filename).c_str(),
921 MakePathString(mode).c_str());
922 });
923 #endif
924 }
925 std::FILE*
926 ufopen(const char* filename, std::ios_base::openmode mode) ynothrowv
927 {
928 if(const auto c_mode = ystdex::openmode_conv(mode))
929 return ufopen(filename, c_mode);
930 return {};
931 }
932 std::FILE*
933 ufopen(const char16_t* filename, std::ios_base::openmode mode) ynothrowv
934 {
935 YAssertNonnull(filename);
936 if(const auto c_mode = ystdex::openmode_conv(mode))
937 return CallNothrow({}, [=]{
938 #if YCL_Win32
939 return ::_wfopen(wcast(filename), MakePathStringW(c_mode).c_str());
940 #else
941 return std::fopen(MakePathString(filename).c_str(), c_mode);
942 #endif
943 });
944 return {};
945 }
946
947 bool
948 ufexists(const char* filename) ynothrowv
949 {
950 #if YCL_Win32
951 return ystdex::call_value_or(ystdex::compose(std::fclose,
952 ystdex::addrof<>()), ufopen(filename, "rb"), yimpl(1)) == 0;
953 #else
954 return ystdex::fexists(filename);
955 #endif
956 }
957 bool
958 ufexists(const char16_t* filename) ynothrowv
959 {
960 return ystdex::call_value_or(ystdex::compose(std::fclose,
961 ystdex::addrof<>()), ufopen(filename, u"rb"), yimpl(1)) == 0;
962 }
963
964 char*
965 ugetcwd(char* buf, size_t size) ynothrowv
966 {
967 YAssertNonnull(buf);
968 if(size != 0)
969 {
970 using namespace std;
971
972 #if YCL_Win32
973 try
974 {
975 const auto p(make_unique<wchar_t[]>(size));
976
977 if(const auto cwd = ::_wgetcwd(p.get(), int(size)))
978 {
979 const auto res(MakePathString(ucast(cwd)));
980 const auto len(res.length());
981
982 if(size < len + 1)
983 errno = ERANGE;
984 else
985 return ystdex::ntctscpy(buf, res.data(), len);
986 }
987 }
988 CatchExpr(std::bad_alloc&, errno = ENOMEM);
989 #else
990 // NOTE: POSIX.1 2004 has no guarantee about slashes. POSIX.1 2013
991 // mandates there are no redundant slashes. See http://pubs.opengroup.org/onlinepubs/009695399/functions/getcwd.html.
992 return ::getcwd(buf, size);
993 #endif
994 }
995 else
996 errno = EINVAL;
997 return {};
998 }
999 char16_t*
1000 ugetcwd(char16_t* buf, size_t len) ynothrowv
1001 {
1002 YAssertNonnull(buf);
1003 if(len != 0)
1004 {
1005 using namespace std;
1006
1007 #if YCL_Win32
1008 // NOTE: Win32 guarantees there will be a separator if and only if when
1009 // the result is root directory for ::_wgetcwd, and actually it is
1010 // the same in ::%GetCurrentDirectoryW.
1011 const auto n(::GetCurrentDirectoryW(len, wcast(buf)));
1012
1013 if(n != 0)
1014 return buf;
1015 errno = GetErrnoFromWin32();
1016 return {};
1017 #else
1018 // XXX: Alias by %char array is safe.
1019 if(const auto cwd
1020 = ::getcwd(ystdex::aligned_store_cast<char*>(buf), len))
1021 try
1022 {
1023 const auto res(platform_ex::MakePathStringU(cwd));
1024 const auto rlen(res.length());
1025
1026 if(len < rlen + 1)
1027 errno = ERANGE;
1028 else
1029 return ystdex::ntctscpy(buf, res.data(), rlen);
1030 }
1031 CatchExpr(std::bad_alloc&, errno = ENOMEM)
1032 #endif
1033 }
1034 else
1035 errno = EINVAL;
1036 return {};
1037 }
1038
1039 #define YCL_Impl_FileSystem_ufunc_1(_n) \
1040 bool \
1041 _n(const char* path) ynothrowv \
1042 { \
1043 YAssertNonnull(path); \
1044
1045 #if YCL_Win32
1046 # define YCL_Impl_FileSystem_ufunc_2(_fn, _wfn) \
1047 return CallNothrow({}, [&]{ \
1048 return _wfn(MakePathStringW(path).c_str()) == 0; \
1049 }); \
1050 }
1051 #else
1052 # define YCL_Impl_FileSystem_ufunc_2(_fn, _wfn) \
1053 return _fn(path) == 0; \
1054 }
1055 #endif
1056
1057 #define YCL_Impl_FileSystem_ufunc(_n, _fn, _wfn) \
1058 YCL_Impl_FileSystem_ufunc_1(_n) \
1059 YCL_Impl_FileSystem_ufunc_2(_fn, _wfn)
1060
1061 YCL_Impl_FileSystem_ufunc(uchdir, ::chdir, ::_wchdir)
1062
1063 YCL_Impl_FileSystem_ufunc_1(umkdir)
1064 #if YCL_Win32
1065 YCL_Impl_FileSystem_ufunc_2(_unused_, ::_wmkdir)
1066 #else
1067 return ::mkdir(path, mode_t(Mode::Access)) == 0;
1068 }
1069 #endif
1070
1071 YCL_Impl_FileSystem_ufunc(urmdir, ::rmdir, ::_wrmdir)
1072
1073 YCL_Impl_FileSystem_ufunc_1(uunlink)
1074 #if YCL_Win32
1075 return CallNothrow({}, [=]{
1076 return CallFuncWithAttr(UnlinkWithAttr, path);
1077 });
1078 }
1079 #else
1080 YCL_Impl_FileSystem_ufunc_2(::unlink, )
1081 #endif
1082
1083 YCL_Impl_FileSystem_ufunc_1(uremove)
1084 #if YCL_Win32
1085 // NOTE: %::_wremove is same to %::_wunlink on Win32 which cannot delete
1086 // empty directories.
1087 return CallNothrow({}, [=]{
1088 return CallFuncWithAttr([](const wchar_t* wstr, FileAttributes attr)
1089 YB_NONNULL(1) ynothrow{
1090 return attr & FileAttributes::Directory ? ::_wrmdir(wstr) == 0
1091 : UnlinkWithAttr(wstr, attr);
1092 }, path);
1093 });
1094 }
1095 #else
1096 YCL_Impl_FileSystem_ufunc_2(std::remove, )
1097 #endif
1098
1099 #undef YCL_Impl_FileSystem_ufunc_1
1100 #undef YCL_Impl_FileSystem_ufunc_2
1101 #undef YCL_Impl_FileSystem_ufunc
1102
1103
1104 #if YCL_Win32
1105 template<>
1106 YF_API string
1107 FetchCurrentWorkingDirectory(size_t init)
1108 {
1109 return MakePathString(FetchCurrentWorkingDirectory<char16_t>(init));
1110 }
1111 template<>
1112 YF_API u16string
1113 FetchCurrentWorkingDirectory(size_t)
1114 {
1115 u16string res;
1116 unsigned long len, rlen(0);
1117
1118 // NOTE: Retry is necessary to prevent failure due to modification of
1119 // current directory from other threads.
1120 ystdex::retry_on_cond([&]() -> bool{
1121 if(rlen < len)
1122 {
1123 res.pop_back();
1124 return {};
1125 }
1126 if(rlen != 0)
1127 return true;
1128 YCL_Raise_Win32E("GetCurrentDirectoryW", yfsig);
1129 }, [&]{
1130 if((len = ::GetCurrentDirectoryW(0, {})) != 0)
1131 {
1132 res.resize(size_t(len + 1));
1133 rlen = ::GetCurrentDirectoryW(len, wcast(&res[0]));
1134 }
1135 });
1136 res.resize(rlen);
1137 return res;
1138 }
1139 #endif
1140
1141
1142 FileTime
1143 GetFileAccessTimeOf(const char* filename, bool follow_link)
1144 {
1145 return FetchFileTime(get_st_atime, filename, follow_link);
1146 }
1147 FileTime
1148 GetFileAccessTimeOf(const char16_t* filename, bool follow_link)
1149 {
1150 return FetchFileTime(get_st_atime, wcast(filename), follow_link);
1151 }
1152
1153 FileTime
1154 GetFileModificationTimeOf(const char* filename, bool follow_link)
1155 {
1156 return FetchFileTime(get_st_mtime, filename, follow_link);
1157 }
1158 FileTime
1159 GetFileModificationTimeOf(const char16_t* filename, bool follow_link)
1160 {
1161 return FetchFileTime(get_st_mtime, wcast(filename), follow_link);
1162 }
1163
1164 array<FileTime, 2>
1165 GetFileModificationAndAccessTimeOf(const char* filename, bool follow_link)
1166 {
1167 return FetchFileTime(get_st_matime, filename, follow_link);
1168 }
1169 array<FileTime, 2>
1170 GetFileModificationAndAccessTimeOf(const char16_t* filename, bool follow_link)
1171 {
1172 return FetchFileTime(get_st_matime, wcast(filename), follow_link);
1173 }
1174
1175 YB_NONNULL(1) size_t
1176 FetchNumberOfLinks(const char* path, bool follow_link)
1177 {
1178 #if YCL_Win32
1179 return QueryFileLinks(MakePathStringW(path).c_str(), follow_link);
1180 #else
1181 struct ::stat st;
1182 static_assert(std::is_unsigned<decltype(st.st_nlink)>(),
1183 "Unsupported 'st_nlink' type found.");
1184
1185 cstat(st, path, follow_link, yfsig);
1186 return st.st_nlink;
1187 #endif
1188 }
1189 YB_NONNULL(1) size_t
1190 FetchNumberOfLinks(const char16_t* path, bool follow_link)
1191 {
1192 #if YCL_Win32
1193 return QueryFileLinks(wcast(path), follow_link);
1194 #else
1195 return FetchNumberOfLinks(MakePathString(path).c_str(), follow_link);
1196 #endif
1197 }
1198
1199
1200 UniqueFile
1201 EnsureUniqueFile(const char* dst, mode_t mode, size_t allowed_links,
1202 bool share)
1203 {
1204 static yconstexpr const auto oflag(OpenMode::Create
1205 | OpenMode::WriteTruncate | OpenMode::Binary);
1206
1207 mode &= mode_t(Mode::User);
1208 if(UniqueFile
1209 p_file{uopen(dst, int(oflag | OpenMode::Exclusive), mode)})
1210 return p_file;
1211 if(allowed_links != 0 && errno == EEXIST)
1212 {
1213 const auto n_links(FetchNumberOfLinks(dst, true));
1214
1215 // FIXME: Blocked. TOCTTOU access.
1216 if(!(allowed_links < n_links)
1217 && (n_links == 1 || share || uunlink(dst) || errno == ENOENT))
1218 if(UniqueFile p_file{uopen(dst, int(oflag), mode)})
1219 return p_file;
1220 }
1221 YCL_Raise_SysE(, "::open", yfsig);
1222 }
1223
1224 bool
1225 HaveSameContents(const char* path_a, const char* path_b, mode_t mode)
1226 {
1227 auto pr(HaveSameContents_Impl(path_a, path_b, mode));
1228
1229 return pr.first ? HaveSameContents(std::move(pr.first),
1230 std::move(pr.second), path_a, path_b) : false;
1231 }
1232 bool
1233 HaveSameContents(const char16_t* path_a, const char16_t* path_b, mode_t mode)
1234 {
1235 auto pr(HaveSameContents_Impl(path_a, path_b, mode));
1236
1237 // TODO: Support names in exception messages.
1238 return pr.first ? HaveSameContents(std::move(pr.first),
1239 std::move(pr.second), {}, {}) : false;
1240 }
1241 bool
1242 HaveSameContents(UniqueFile p_a, UniqueFile p_b, const char* name_a,
1243 const char* name_b)
1244 {
1245 if(!(bool(Nonnull(p_a)->GetCategory() & NodeCategory::Directory)
1246 || bool(Nonnull(p_b)->GetCategory() & NodeCategory::Directory)))
1247 {
1248 if(IsNodeShared(p_a.get(), p_b.get()))
1249 return true;
1250
1251 filebuf fb_a, fb_b;
1252
1253 errno = 0;
1254 // FIXME: Implement for streams without open-by-raw-file extension.
1255 // TODO: Throw a nested exception with %errno if 'errno != 0'.
1256 if(!fb_a.open(std::move(p_a),
1257 std::ios_base::in | std::ios_base::binary))
1258 ystdex::throw_error(std::errc::bad_file_descriptor,
1259 name_a ? ("Failed opening first file '" + string(name_a) + '\'')
1260 .c_str() : "Failed opening first file");
1261 // TODO: Throw a nested exception with %errno if 'errno != 0'.
1262 if(!fb_b.open(std::move(p_b),
1263 std::ios_base::in | std::ios_base::binary))
1264 ystdex::throw_error(std::errc::bad_file_descriptor,
1265 name_b ? ("Failed opening second file '" + string(name_b)
1266 + '\'').c_str() : "Failed opening second file");
1267 return ystdex::streambuf_equal(fb_a, fb_b);
1268 }
1269 return {};
1270 }
1271
1272 bool
1273 IsNodeShared(const char* a, const char* b, bool follow_link) ynothrowv
1274 {
1275 return a == b || ystdex::ntctscmp(Nonnull(a), Nonnull(b)) == 0
1276 || IsNodeShared_Impl(a, b, follow_link);
1277 }
1278 bool
1279 IsNodeShared(const char16_t* a, const char16_t* b, bool follow_link) ynothrowv
1280 {
1281 return a == b || ystdex::ntctscmp(Nonnull(a), Nonnull(b)) == 0
1282 || IsNodeShared_Impl(a, b, follow_link);
1283 }
1284 bool
1285 IsNodeShared(FileDescriptor x, FileDescriptor y) ynothrow
1286 {
1287 const auto id(x.GetNodeID());
1288
1289 return id != FileNodeID() && id == y.GetNodeID();
1290 }
1291
1292 } // namespace platform;
1293
1294 namespace platform_ex
1295 {
1296
1297 #if YCL_Win32
1298 wstring
1299 MakePathStringW(const char* s)
1300 {
1301 return platform_ex::UTF8ToWCS(s);
1302 }
1303 #else
1304 u16string
1305 MakePathStringU(const char* s)
1306 {
1307 return CHRLib::MakeUCS2LE(s);
1308 }
1309 #endif
1310
1311 } // namespace platform_ex;
1312
platform_ex::Windows::ReadOnly
Definition: MinGW32.h:449
platform_ex::Windows::SetFileTime
YF_API void SetFileTime(UniqueHandle::pointer,::FILETIME *={},::FILETIME *={},::FILETIME *={})
设置文件的创建、访问和/或修改时间。
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:313
ystdex::ntctscpy
enable_if_irreplaceable_char_t< _tChar, _tChar * > ntctscpy(_tChar *s1, const _tChar *s2)
复制 NTCTS 。
Definition: cstring.h:250
platform::containers::wstring
basic_string< wchar_t > wstring
Definition: Container.h:108
ystdex::cpp2014::result_of_t
typename result_of< _type >::type result_of_t
Definition: type_traits.hpp:355
platform::FileDescriptor
文件描述符包装类。
Definition: FileIO.h:146
NPL::dst
YF_API const char src const string const char * dst
Definition: Dependency.h:95
YCL_Impl_FileSystem_ufunc_2
#define YCL_Impl_FileSystem_ufunc_2(_fn, _wfn)
Definition: FileIO.cpp:1052
CHRLib::PDefH
PDefH(char16_t, FetchBiCharBE, const char *c_ptr) ImplRet(yconstraint(c_ptr)
取 c_ptr 指向的大端序双字节字符。
platform_ex::Windows::QueryFileNodeID
YF_API pair< VolumeID, FileID > QueryFileNodeID(UniqueHandle::pointer)
查询文件标识。
platform_ex::Windows::QueryFileSize
YF_API std::uint64_t QueryFileSize(UniqueHandle::pointer)
查询文件大小。
platform::GetFileAccessTimeOf
FileTime GetFileAccessTimeOf(const char16_t *filename, bool follow_link)
Definition: FileIO.cpp:1148
platform::containers::u16string
basic_string< char16_t > u16string
Definition: Container.h:103
YCL_Impl_FileSystem_ufunc_1
#define YCL_Impl_FileSystem_ufunc_1(_n)
Definition: FileIO.cpp:1039
platform_ex::Windows::QueryFileTime
YF_API YB_NONNULL(1) std YF_API void QueryFileTime(UniqueHandle::pointer,::FILETIME *={},::FILETIME *={},::FILETIME *={})
查询文件的创建、访问和/或修改时间。
platform::ufexists
bool ufexists(const char16_t *filename) ynothrowv
Definition: FileIO.cpp:958
ystdex::to_string
std::string to_string(const std::thread::id &)
转换 thread::id 为字符串表示。
platform::ufopen
std::FILE * ufopen(const char16_t *filename, std::ios_base::openmode mode) ynothrowv
Definition: FileIO.cpp:933
platform
默认平台命名空间。
Definition: Container.h:47
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:451
platform::GetFileModificationTimeOf
FileTime GetFileModificationTimeOf(const char16_t *filename, bool follow_link)
Definition: FileIO.cpp:1159
YSLib::UI::y
SPos SPos y
Definition: YWidget.cpp:44
NPL::x
const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow TermNode &term const TermNode &term ValueNode &node const ValueNode &node const _type & x
Definition: SContext.h:94
platform::follow_link
bool follow_link
Definition: FileIO.cpp:1177
yfsig
#define yfsig
展开为表示函数签名的预定义变量的宏。
Definition: ydef.h:728
platform::ugetcwd
char16_t * ugetcwd(char16_t *buf, size_t len) ynothrowv
Definition: FileIO.cpp:1000
platform::omode_conv
int omode_conv(std::ios_base::openmode mode) ynothrow
Definition: FileIO.cpp:796
platform::uunlink
bool uunlink(const char *path) ynothrowv
Definition: FileIO.cpp:1073
CHRLib::f
f(d, s)
ystdex::call_value_or
auto call_value_or(_func f, _type &&p) -> decay_t< decltype(f(*std::forward< decltype(p)>(p)))>
调用非空值或取默认值。
Definition: deref_op.hpp:140
CHRLib::MakeMBCS
_tDst MakeMBCS(string_view sv, Encoding enc)
Definition: CharacterProcessing.h:603
ystdex::ntctscmp
int ntctscmp(const _tChar *s1, const _tChar *s2)
按字典序比较简单 NTCTS 。
Definition: cstring.h:154
platform::bool
std::FILE *fp bool
Definition: FileIO.h:1280
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:262
FileAttributes
FileAttributes
文件共享模式。
Definition: MinGW32.h:447
ystdex::compose
composed< _func, _func2 > compose(_func f, _func2 g)
函数复合。
Definition: functional.hpp:686
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:120
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
ystdex::cpp2014::make_unique
enable_if_t<!is_array< _type >::value, std::unique_ptr< _type > > make_unique(_tParams &&...args)
使用 new 和指定参数构造指定类型的 std::unique_ptr 对象。
Definition: memory.hpp:852
platform::UniqueFile
unique_ptr_from< FileDescriptor::Deleter > UniqueFile
Definition: FileIO.h:464
platform::omode_convb
std::ios_base::sync_with_stdio(sync)) YF_API YB_STATELESS int omode_conv(std YF_API YB_STATELESS int omode_convb(std::ios_base::openmode) ynothrow
ISO C++ 标准输入输出接口打开模式转换为 POSIX 文件打开模式。
Definition: FileIO.cpp:840
platform::FetchCurrentWorkingDirectory
basic_string< _tChar > FetchCurrentWorkingDirectory(size_t init)
尝试按指定的起始缓冲区大小取当前工作目录的路径。
Definition: FileIO.h:1135
YCL_Raise_Win32E
#define YCL_Raise_Win32E(...)
取转换为 errno 的 Win32 错误。
Definition: MinGW32.h:138
CHRLib::args
_tParams && args
Definition: CharacterProcessing.h:538
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:679
platform::KeyCategory::None
表示未分配或保留的键。
Definition: Keys.h:101
platform::IsNodeShared
bool IsNodeShared(const char16_t *a, const char16_t *b, bool follow_link) ynothrowv
Definition: FileIO.cpp:1279
YSLib::Text::buf
const char * buf
Definition: TextFile.h:81
platform::uaccess
int uaccess(const char16_t *path, int amode) ynothrowv
Definition: FileIO.cpp:860
platform::KeyCategory::Character
表示产生字符的键。
Definition: Keys.h:111
YSLib::IO::FileDescriptor
YF_API const char *YF_API FileDescriptor
Definition: YSLib/Service/FileSystem.h:740
YCL_Raise_SysE
#define YCL_Raise_SysE(_t, _msg, _sig)
按错误值和指定参数抛出第一参数指定类型的对象。
Definition: FileIO.h:1178
YCL_ReservedGlobal
#define YCL_ReservedGlobal(_n)
按实现修饰全局保留名称。
Definition: NativeAPI.h:64
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1022
platform_ex::Windows::unsigned
YF_API unsigned
Definition: NLS.h:52
platform_ex::Windows::WCSToUTF8
const char *str string_view sv WCSToUTF8
Definition: NLS.h:79
platform::EnsureUniqueFile
UniqueFile EnsureUniqueFile(const char *dst, mode_t mode, size_t allowed_links, bool share)
Definition: FileIO.cpp:1201
platform::uopen
int uopen(const char16_t *filename, int oflag, mode_t pmode) ynothrowv
Definition: FileIO.cpp:885
ystdex::throw_error
void throw_error(std::error_code ec, _tParams &&...args)
抛出错误： std::system_error 或允许相同构造函数参数的异常。
Definition: ystdex/exception.h:206
platform::urmdir
bool urmdir(const char *path) ynothrowv
Definition: FileIO.cpp:1071
YSLib::a
YB_PURE const _type * a
Definition: YCoreUtilities.h:167
platform_ex::Windows::UnlockFile
bool UnlockFile(UniqueHandle::pointer, std::uint64_t=0, std::uint64_t=std::uint64_t(-1)) ynothrow
解锁文件。
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:111
platform::HaveSameContents
bool HaveSameContents(const char16_t *path_a, const char16_t *path_b, mode_t mode)
Definition: FileIO.cpp:1233
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
CHRLib::YB_NONNULL
YB_NONNULL(1) PDefH(ConversionResult
转换指定编码的多字节字符串为指定类型的 UCS-2 字符串。
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:766
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
CHRLib::fp
std::FILE ConversionState fp
Definition: CharacterProcessing.h:92
CHRLib::ImplRet
const char *c_ptr ImplRet(yconstraint(c_ptr), char16_t((c_ptr[1]<< CHAR_BIT)|*c_ptr)) enum class ConversionResult
编码转换结果。
Definition: CharacterMapping.h:84
YCL_CallGlobal
#define YCL_CallGlobal(_n,...)
调用按实现修饰的具有全局保留名称的函数。
Definition: NativeAPI.h:67
platform::sig
const string const char *sig const char * sig
Definition: Debug.h:473
platform_ex::Windows::Invalid
Definition: MinGW32.h:471
YModules.h
YF_API
#define YF_API
Definition: Platform.h:56
CHRLib::MakeUCS2LE
_tDst MakeUCS2LE(basic_string_view< char > sv, _tParams &&...args)
Definition: CharacterProcessing.h:538
YModules.h
YCL_Impl_FileSystem_ufunc
#define YCL_Impl_FileSystem_ufunc(_n, _fn, _wfn)
Definition: FileIO.cpp:1057
platform::oflag
YF_API int oflag
Definition: FileIO.h:542
ystdex::fexists
bool fexists(const char *)
判断指定路径的文件是否存在。
Definition: cstdio.cpp:59
platform::SetBinaryIO
YF_API void SetBinaryIO(std::FILE *) ynothrowv
设置标准库流二进制输入/输出模式。
Definition: FileIO.cpp:784
platform::GetFileModificationAndAccessTimeOf
GetFileModificationAndAccessTimeOf
Definition: FileIO.h:1312
functional.hpp
函数和可调用对象。
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:968
platform::RetryOnInterrupted
_type RetryOnInterrupted(_func f)
循环可能被中断的操作。
Definition: YCommon.h:261
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:786
platform_ex::Windows::UTF8ToWCS
UTF8ToWCS
Definition: NLS.h:72
platform::uremove
bool uremove(const char *path) ynothrowv
Definition: FileIO.cpp:1083
platform_ex::Windows::QueryFileLinks
YF_API size_t QueryFileLinks(UniqueHandle::pointer)
查询文件链接数。
CHRLib
Definition: CharacterDefinition.h:38
std
Definition: memory.hpp:1183
platform_ex::Windows::TryLockFile
bool TryLockFile(UniqueHandle::pointer, std::uint64_t=0, std::uint64_t=std::uint64_t(-1), bool=true, bool=true) ynothrow
ystdex::byte
unsigned char byte
字节类型。
Definition: ydef.h:834
platform::pmode
YF_API int mode_t pmode
Definition: FileIO.h:542
platform::Nonnull
_type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:422
platform::cstat
cstat(st, path, follow_link, yfsig)
platform::Descriptions::Warning
Definition: YCommon.h:167
streambuf.hpp
ISO C++ 标准库标准流缓冲扩展。
ystdex::single_thread::try_lock
int try_lock(_tLock1 &&, _tLock2 &&, _tLocks &&...)
Definition: pseudo_mutex.h:983
platform_ex
平台扩展命名空间。
Definition: Android.h:45
platform::KeyCodes::Win32::Empty
Definition: Keys.h:279
platform::umkdir
bool umkdir(const char *path) ynothrowv
Definition: FileIO.cpp:1063
YCL_TraceCall_CAPI
#define YCL_TraceCall_CAPI(_fn, _sig,...)
Definition: FileIO.h:1255
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:995
platform::MakePathString
string MakePathString(const char16_t *s)
Definition: FileIO.cpp:377
ystdex::addrof
一元 & 操作。
Definition: functor.hpp:437
platform::uchdir
bool uchdir(const char *path) ynothrowv
Definition: FileIO.cpp:1061
ystdex::retry_on_cond
result_of_t< _fCallable &&(_tParams &&...)> retry_on_cond(_fCond cond, _fCallable &&f, _tParams &&...args)
循环重复调用：代替直接使用 do-while 语句以避免过多引入作用域外的变量。
Definition: functional.hpp:1152
ystdex::invoke
result_of_t< _fCallable &&(_tParams &&...)> invoke(_fCallable &&f, _tParams &&...args)
调用可调用对象。
Definition: functional.hpp:339
ystdex::single_thread::lock
void lock(_tLock1 &&, _tLock2 &&, _tLocks &&...)
Definition: pseudo_mutex.h:990
CHRLib::char16_t
char16_t((*c_ptr<< CHAR_BIT)|c_ptr[1])) inline PDefH(char16_t
取 c_ptr 指向的小端序双字节字符。
platform::CategorizeNode
enum NodeCategory std::uint_least32_t YF_API NodeCategory CategorizeNode(mode_t) ynothrow
文件节点类别。
Definition: FileIO.cpp:388
ystdex::size
auto size(const _tRange &c) -> decltype(c.size())
类容器访问。
Definition: range.hpp:233
YCL_CallF_CAPI
#define YCL_CallF_CAPI(_t, _fn,...)
Definition: FileIO.h:1237
platform_ex::Windows::ConvertTime
YF_API std::chrono::nanoseconds ConvertTime(const ::FILETIME &)
转换文件时间为以 POSIX 历元起始度量的时间间隔。
YSLib::IO::int
YF_API int
Definition: File.h:51
ystdex::temporary_buffer
临时缓冲区。
Definition: memory.hpp:461
ystdex::streambuf_equal
bool streambuf_equal(std::basic_streambuf< _tChar, _tTraits > &a, std::basic_streambuf< _tChar, _tTraits > &b)
比较指定流缓冲区的内容相等。
Definition: streambuf.hpp:45
CHRLib::size_t
return size_t(d-p)
platform_ex::MakePathStringU
u16string MakePathStringU(const char *s)
Definition: FileIO.cpp:1305
platform_ex::MakePathStringU
MakePathStringU
Definition: FileIO.h:1443
YSLib::path
YF_API const char * path
Definition: Initialization.h:77
platform::mode_t
::mode_t mode_t
文件模式类型。
Definition: FileIO.h:114
ystdex::openmode_conv
const char * openmode_conv(std::ios_base::openmode)
ISO C/C++ 标准输入输出接口打开模式转换。
Definition: cstdio.cpp:68
platform::DefaultPMode
YF_API YB_STATELESS mode_t DefaultPMode() ynothrow
取默认权限。
Definition: FileIO.cpp:772
ystdex::write
std::basic_ostream< _tChar, typename _tString::traits_type > & write(std::basic_ostream< _tChar, typename _tString::traits_type > &os, const _tString &str, typename _tString::size_type pos=0, typename _tString::size_type n=_tString::npos)
非格式输出。
Definition: string.hpp:981
platform_ex::Windows::LockFile
void LockFile(UniqueHandle::pointer, std::uint64_t=0, std::uint64_t=std::uint64_t(-1), bool=true, bool={})
锁定文件。
YCL_Trace_Win32E
#define YCL_Trace_Win32E(_lv, _fn, _sig)
跟踪 ::GetLastError 取得的调用状态结果。
Definition: MinGW32.h:157
YCL_TraceCallF_CAPI
#define YCL_TraceCallF_CAPI(_fn,...)
Definition: FileIO.h:1258
CHRLib::p
const auto p(d)
platform_ex::Windows::Directory
Definition: MinGW32.h:452