YSTest: FileSystem.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

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

- 文件列表
- 文件成员

YCLib/FileSystem.cpp
浏览该文件的文档.
1 /*
2 © 2011-2016 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 #include "YCLib/YModules.h"
29 #include YFM_YCLib_FileSystem // for std::tm, default_delete, make_observer,
30 // std::accumulate, std::min, ystdex::read_uint_le, YAssertNonnull,
31 // ystdex::write_uint_le, std::bind, std::ref, ystdex::retry_on_cond;
32 #include YFM_YCLib_NativeAPI // for Mode, struct ::stat, ::lstat;
33 #include YFM_YCLib_FileIO // for CategorizeNode, Deref, ystdex::to_array,
34 // ystdex::throw_error, std::errc::function_not_supported,
35 // ThrowFileOperationFailure, ystdex::ntctslen, std::strchr, std::wctob,
36 // std::towupper, ystdex::restrict_length, std::min, ystdex::ntctsicmp,
37 // std::errc::invalid_argument;
38 #include "CHRLib/YModules.h"
39 #include YFM_CHRLib_CharacterProcessing // for CHRLib::MakeMBCS,
40 // CHRLib::MakeUCS2LE;
41 #if YCL_Win32
42 # include YFM_Win32_YCLib_MinGW32 // for platform_ex::UTF8ToWCS,
43 // platform_ex::WCSToUTF8, platform_ex::ResolveReparsePoint,
44 // platform_ex::DirectoryFindData;
45 # include <time.h> // for ::localtime_s;
46
48 namespace
49 {
50
51 namespace YCL_Impl_details
52 {
53
54 // NOTE: To avoid hiding of global name, the declarations shall not be under
55 // namespace %platform.
56 YCL_DeclW32Call(CreateSymbolicLinkW, kernel32, unsigned char, const wchar_t*, \
57 const wchar_t*, unsigned long)
58 using platform::wcast;
59
60 // NOTE: As %SYMBOLIC_LINK_FLAG_DIRECTORY, but with correct type.
61 yconstexpr const auto SymbolicLinkFlagDirectory(1UL);
62
63 inline PDefH(void, W32_CreateSymbolicLink, const char16_t* dst,
64 const char16_t* src, unsigned long flags)
65 ImplExpr(YCL_CallWin32F(CreateSymbolicLinkW, wcast(dst), wcast(src), flags))
66
67 } // namespace YCL_Impl_details;
68
69 } // unnamed namespace;
70
72 using platform_ex::UTF8ToWCS;
74 using platform_ex::WCSToUTF8;
76 using platform_ex::DirectoryFindData;
77 #elif YCL_API_POSIXFileSystem
78 # include <dirent.h>
79 # include <time.h> // for ::localtime_r;
80 #endif
81
83 using namespace CHRLib;
84
85 namespace platform
86 {
87
88 namespace
89 {
90
91 #if YCL_Win32
92 inline PDefH(u16string, WToU16, const wstring& wstr)
94 ImplRet({ucast(wstr.c_str()), wstr.length()})
95 #endif
96
98 yconstfn bool
99 is_time_no_leap_valid(const std::tm& t)
100 {
101 return !(t.tm_hour < 0 || 23 < t.tm_hour || t.tm_hour < 0 || 59 < t.tm_min
102 || t.tm_sec < 0 || 59 < t.tm_min);
103 }
104
106 yconstfn bool
107 is_date_range_valid(const std::tm& t)
108 {
109 return !(t.tm_mon < 0 || 12 < t.tm_mon || t.tm_mday < 1 || 31 < t.tm_mday);
110 }
111
113
114 // TODO: Simplify and expose as public API.
115 YB_NONNULL(1) bool
116 IsDirectoryImpl(const char*);
117 YB_NONNULL(1) bool
118 IsDirectoryImpl(const char16_t*);
119 bool
120 IsDirectoryImpl(const char* path)
121 {
122 #if YCL_Win32
123 return IsDirectoryImpl(ucast(UTF8ToWCS(path).c_str()));
124 #else
125 // TODO: Merge imlementation. See %estat in %FileIO?
126 struct ::stat st;
127
128 return ::stat(path, &st) == 0 && bool(Mode(st.st_mode) & Mode::Directory);
129 #endif
130 }
131 bool
132 IsDirectoryImpl(const char16_t* path)
133 {
134 // TODO: Simplify.
135 #if YCL_Win32
136 return platform_ex::FileAttributes(::GetFileAttributesW(wcast(path))
137 & platform_ex::Directory);
138 #else
139 return IsDirectoryImpl(MakeMBCS(path).c_str());
140 #endif
141 }
142
143 template<typename _tChar>
144 YB_NONNULL(1) basic_string<_tChar>
145 ResolvePathImpl(const _tChar* path, size_t n)
146 {
147 YAssertNonnull(path);
148 #if YCL_DS
149 yunused(n);
150 #endif
151
152 using string_t = basic_string<_tChar>;
153 basic_string_view<_tChar> s(path);
154 string_t res;
155 const bool absolute(IsAbsolute(path));
156
157 if(!absolute)
158 {
159 res = TryGetCurrentWorkingDirectory<_tChar>(yimpl(PATH_MAX));
160 YAssert(!res.empty() && res.back() != YCL_PATH_DELIMITER,
161 "Invalid path converted.");
162 }
163 ystdex::split(s.cbegin(), s.cend(), [](_tChar c){
164 return YCL_FS_CharIsDelimiter(c, _tChar);
165 }, [&](decltype(s.cend()) b, decltype(s.cend()) e){
166 if(b != e)
167 {
168 if(!res.empty())
169 res += string_t(b, e);
170 else
171 {
172 string_t head(b, e);
173
174 if(absolute && !IsAbsolute(head.c_str()))
175 res += YCL_PATH_DELIMITER;
176 res += std::move(head);
177 }
178 if(!res.empty())
179 {
180 #if !YCL_DS
181 try
182 {
183 // TODO: Throw with context information about failed path?
184 res = ReadLink(res.c_str());
185 if(n != 0)
186 --n;
187 else
188 // XXX: Enumerator
189 // %std::errc::too_many_symbolic_link_levels is
190 // commented out in MinGW-w64 configuration of
191 // libstdc++. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71444.
192 ystdex::throw_error(ELOOP);
193 }
194 CatchIgnore(std::invalid_argument&)
195 #endif
196 }
197 if(IsDirectoryImpl(res.c_str()))
198 res += YCL_PATH_DELIMITER;
199 }
200 });
201 return res;
202 }
204
205 } // unnamed namespace;
206
207 void
208 CreateHardLink(const char* dst, const char* src)
209 {
210 #if YCL_DS
211 YAssertNonnull(dst), YAssertNonnull(src);
212 ystdex::throw_error(std::errc::function_not_supported);
213 #elif YCL_Win32
214 CreateHardLink(ucast(UTF8ToWCS(dst).c_str()),
215 ucast(UTF8ToWCS(src).c_str()));
216 #else
217 // NOTE: POSIX %::link is implementation-defined to following symbolic
218 // link target.
219 if(::linkat(AT_FDCWD, Nonnull(src), AT_FDCWD, Nonnull(dst),
220 AT_SYMLINK_FOLLOW) != 0)
221 ystdex::throw_error(errno);
222 #endif
223 }
224 void
225 CreateHardLink(const char16_t* dst, const char16_t* src)
226 {
227 #if YCL_DS
228 YAssertNonnull(dst), YAssertNonnull(src);
229 ystdex::throw_error(std::errc::function_not_supported);
230 #elif YCL_Win32
231 YCL_CallWin32F(CreateHardLinkW, wcast(dst), wcast(src), {});
232 #else
233 // TODO: To make the behavior specific and same as on platform %Win32, use
234 // %::realpath on platform %Linux, etc.
235 CreateHardLink(MakeMBCS(dst).c_str(), MakeMBCS(src).c_str());
236 #endif
237 }
238
239 void
240 CreateSymbolicLink(const char* dst, const char* src, bool is_dir)
241 {
242 #if YCL_Win32
243 using namespace platform_ex;
244
245 CreateSymbolicLink(ucast(UTF8ToWCS(dst).c_str()),
246 ucast(UTF8ToWCS(src).c_str()), is_dir);
247 #elif YCL_DS
248 yunused(dst), yunused(src), yunused(is_dir);
249 ystdex::throw_error(std::errc::function_not_supported);
250 #else
251 yunused(is_dir);
252 if(::symlink(Nonnull(src), Nonnull(dst)) != 0)
253 ystdex::throw_error(errno);
254 #endif
255 }
256 void
257 CreateSymbolicLink(const char16_t* dst, const char16_t* src, bool is_dir)
258 {
259 #if YCL_Win32
260 YCL_Impl_details::W32_CreateSymbolicLink(dst, src,
261 is_dir ? YCL_Impl_details::SymbolicLinkFlagDirectory : 0UL);
262 #elif YCL_DS
263 yunused(dst), yunused(src), yunused(is_dir);
264 ystdex::throw_error(std::errc::function_not_supported);
265 #else
266 CreateSymbolicLink(MakeMBCS(dst).c_str(), MakeMBCS(src).c_str(), is_dir);
267 #endif
268 }
269
270 string
271 ReadLink(const char* path)
272 {
273 #if YCL_DS
274 YAssertNonnull(path);
275 ystdex::throw_error(std::errc::function_not_supported);
276 #elif YCL_Win32
277 // TODO: Simplify?
278 return WCSToUTF8(wcast(ReadLink(ucast(UTF8ToWCS(path).c_str())).c_str()));
279 #else
280 struct ::stat st;
281
282 if(::lstat(Nonnull(path), &st) == 0)
283 {
284 const auto n(st.st_size);
285
286 if(n > 0)
287 {
288 string res(size_t(n), char{});
289 const auto size(::readlink(path, &res[0], size_t(n)));
290
291 if(size >= 0)
292 {
293 res.resize(size_t(size));
294 return res;
295 }
296 }
297 else if(n == 0)
298 return {};
299 else if(errno == EINVAL)
300 throw std::invalid_argument("Specified file is not a link.");
301 }
302 ystdex::throw_error(errno);
303 #endif
304 }
305 u16string
306 ReadLink(const char16_t* path)
307 {
308 #if YCL_DS
309 YAssertNonnull(path);
310 ystdex::throw_error(std::errc::function_not_supported);
311 #elif YCL_Win32
312 // TODO: Simplify?
313 return WToU16(platform_ex::ResolveReparsePoint(wcast(path)));
314 #else
315 return MakeUCS2LE(ReadLink(MakeMBCS(path).c_str()));
316 #endif
317 }
318
319 YB_NONNULL(1) string
320 ResolvePath(const char* path, size_t n)
321 {
322 return ResolvePathImpl<char>(path, n);
323 }
324 YB_NONNULL(1) u16string
325 ResolvePath(const char16_t* path, size_t n)
326 {
327 return ResolvePathImpl<char16_t>(path, n);
328 }
329
330
331 #if YCL_Win32
332 class DirectorySession::Data : public DirectoryFindData
333 {
334 public:
335 using DirectoryFindData::DirectoryFindData;
336 };
337 #else
338 namespace
340 {
341
342 PDefH(::DIR*, ToDirPtr, DirectorySession::NativeHandle p)
343 ImplRet(static_cast<::DIR*>(p))
344
345 } // unnamed namespace;
346 #endif
347 void
348 DirectorySession::Deleter::operator()(pointer p) const ynothrowv
349 {
350 #if YCL_Win32
351 default_delete<Data>()(p);
352 #else
353 const auto res(::closedir(ToDirPtr(p)));
354
355 YAssert(res == 0, "No valid directory found.");
356 yunused(res);
357 #endif
358 }
359
360
361 DirectorySession::DirectorySession()
362 #if YCL_Win32
363 : DirectorySession(u".")
364 #else
365 : DirectorySession(".")
366 #endif
367 {}
368 DirectorySession::DirectorySession(const char* path)
369 #if YCL_Win32
370 : dir(new Data(UTF8ToWCS(path)))
371 #else
372 : sDirPath([](const char* p) YB_NONNULL(1){
373 const auto res(ystdex::rtrim(string(Deref(p) != char() ? p : "."),
374 YCL_PATH_DELIMITER));
375
376 YAssert(EndsWithNonSeperator(res),
377 "Invalid directory name state found.");
378 return res + YCL_PATH_DELIMITER;
379 }(path)),
380 dir(::opendir(sDirPath.c_str()))
381 #endif
382 {
383 #if !YCL_Win32
384 if(!dir)
385 ThrowFileOperationFailure("Opening directory failed.");
386 #endif
387 }
388 DirectorySession::DirectorySession(const char16_t* path)
389 #if YCL_Win32
390 : dir(new Data(wcast(path)))
391 #else
392 : DirectorySession(MakeMBCS(path).c_str())
393 #endif
394 {}
395
396 void
397 DirectorySession::Rewind() ynothrow
398 {
399 YAssert(dir, "Invalid native handle found.");
400 #if YCL_Win32
401 Deref(dir.get()).Rewind();
402 #else
403 ::rewinddir(ToDirPtr(dir.get()));
404 #endif
405 }
406
407
408 HDirectory&
409 HDirectory::operator++()
410 {
411 YAssert(!p_dirent || bool(GetNativeHandle()), "Invariant violation found.");
412 p_dirent
413 #if YCL_Win32
414 = static_cast<DirectoryFindData*>(GetNativeHandle())->Read();
415 #else
416 = make_observer(::readdir(ToDirPtr(GetNativeHandle())));
417 #endif
418 return *this;
419 }
420
421 NodeCategory
422 HDirectory::GetNodeCategory() const ynothrow
423 {
424 if(p_dirent)
425 {
426 YAssert(bool(GetNativeHandle()), "Invariant violation found.");
427 #if YCL_Win32
428 YAssert(!p_dirent->empty(), "Invariant violation found.");
429
430 const auto res(Deref(static_cast<platform_ex::DirectoryFindData*>(
431 GetNativeHandle())).GetNodeCategory());
432 #else
433 auto res(NodeCategory::Empty);
434
435 try
436 {
437 auto name(sDirPath + Deref(p_dirent).d_name);
438 struct ::stat st;
439
440 # if YCL_DS
441 if(::stat(name.c_str(), &st) == 0)
442 # else
443 // XXX: Value of %errno might be overwrite.
444 if(::lstat(name.c_str(), &st) == 0)
445 res |= CategorizeNode(st.st_mode);
446 if(bool(res & NodeCategory::Link) && ::stat(name.c_str(), &st) == 0)
447 # endif
448 res |= CategorizeNode(st.st_mode);
449 }
450 // TODO: Log on failure.
451 CatchIgnore(...)
452 #endif
453 return res != NodeCategory::Empty ? res : NodeCategory::Invalid;
454 }
455 return NodeCategory::Empty;
456 }
457
458 HDirectory::operator string() const
459 {
460 #if !YCL_Win32
461 return GetNativeName();
462 #else
463 return WCSToUTF8(wcast(GetNativeName()));
464 #endif
465 }
466 HDirectory::operator u16string() const
467 {
468 #if !YCL_Win32
469 return MakeUCS2LE(GetNativeName());
470 #else
471 return ucast(GetNativeName());
472 #endif
473 }
474
475 const HDirectory::NativeChar*
476 HDirectory::GetNativeName() const ynothrow
477 {
478 #if !YCL_Win32
479 return p_dirent ? p_dirent->d_name : ".";
480 #else
481 if(p_dirent)
482 {
483 const auto& child(Deref(p_dirent));
484
485 YAssert(!child.empty(), "Invariant violation found.");
486 return ucast(child.data());
487 }
488 return u".";
489 #endif
490 }
491
492
493 namespace FAT
494 {
495
496 namespace LFN
497 {
498
499 tuple<string, string, bool>
500 ConvertToAlias(const u16string& long_name)
501 {
502 YAssert(ystdex::ntctslen(long_name.c_str()) == long_name.length(),
503 "Invalid long file name found.");
504
505 string alias;
506 // NOTE: Strip leading periods.
507 size_t offset(long_name.find_first_not_of(u'.'));
508 // NOTE: Set when the alias had to be modified to be valid.
509 bool lossy(offset != 0);
510 const auto check_char([&](string& str, char16_t uc){
511 int bc(std::wctob(std::towupper(wint_t(uc))));
512
513 if(!lossy && std::wctob(wint_t(uc)) != bc)
514 lossy = true;
515 if(bc == ' ')
516 {
517 // NOTE: Skip spaces in filename.
518 lossy = true;
519 return;
520 }
521 // TODO: Optimize.
522 if(bc == EOF || string(IllegalAliasCharacters).find(char(bc))
523 != string::npos)
524 // NOTE: Replace unconvertible or illegal characters with
525 // underscores. See Microsoft FAT specification Section 7.4.
526 yunseq(bc = '_', lossy = true);
527 str += char(bc);
528 });
529 const auto len(long_name.length());
530
531 for(; alias.length() < MaxAliasMainPartLength && long_name[offset] != u'.'
532 && offset != len; ++offset)
533 check_char(alias, long_name[offset]);
534 if(!lossy && long_name[offset] != u'.' && long_name[offset] != char16_t())
535 // NOTE: More than 8 characters in name.
536 lossy = true;
537
538 auto ext_pos(long_name.rfind(u'.'));
539 string ext;
540
541 if(!lossy && ext_pos != u16string::npos && long_name.rfind(u'.', ext_pos)
542 != u16string::npos)
543 // NOTE: More than one period in name.
544 lossy = true;
545 if(ext_pos != u16string::npos && ext_pos + 1 != len)
546 {
547 ++ext_pos;
548 for(size_t ext_len(0); ext_len < LFN::MaxAliasExtensionLength
549 && ext_pos != len; yunseq(++ext_len, ++ext_pos))
550 check_char(ext, long_name[ext_pos]);
551 if(ext_pos != len)
552 // NOTE: More than 3 characters in extension.
553 lossy = true;
554 }
555 return make_tuple(std::move(alias), std::move(ext), lossy);
556 }
557
558 string
559 ConvertToMBCS(const char16_t* path)
560 {
561 // TODO: Optimize?
562 ImplRet(ystdex::restrict_length(MakeMBCS({path,
563 std::min<size_t>(ystdex::ntctslen(path), MaxLength)}), MaxMBCSLength))
564 }
565
566 EntryDataUnit
567 GenerateAliasChecksum(const EntryDataUnit* p) ynothrowv
568 {
569 static_assert(std::is_same<EntryDataUnit, unsigned char>::value,
570 "Only unsigned char as byte is supported by checksum generation.");
571
572 YAssertNonnull(p);
573 // NOTE: The operation is an unsigned char rotate right.
574 return std::accumulate(p, p + AliasEntryLength, 0,
575 [](EntryDataUnit v, EntryDataUnit b){
576 return ((v & 1) != 0 ? 0x80 : 0) + (v >> 1) + b;
577 });
578 }
579
580 bool
581 ValidateName(string_view name) ynothrowv
582 {
583 YAssertNonnull(name.data());
584 return std::all_of(begin(name), end(name), [](char c) ynothrow{
585 // TODO: Use interval arithmetic.
586 return c >= 0x20 && static_cast<unsigned char>(c) < 0xF0;
587 });
588 }
589
590 void
591 WriteNumericTail(string& alias, size_t k) ynothrowv
592 {
593 YAssert(!(MaxAliasMainPartLength < alias.length()), "Invalid alias found.");
594
595 auto p(&alias[MaxAliasMainPartLength - 1]);
596
597 while(k > 0)
598 {
599 YAssert(p != &alias[0], "Value is too large to store in the alias.");
600 *p-- = '0' + k % 10;
601 k /= 10;
602 }
603 *p = '~';
604 }
605
606 } // namespace LFN;
607
608 std::time_t
609 ConvertFileTime(Timestamp d, Timestamp t) ynothrow
610 {
611 struct std::tm time_parts;
612
613 yunseq(
614 time_parts.tm_hour = t >> 11,
615 time_parts.tm_min = (t >> 5) & 0x3F,
616 time_parts.tm_sec = (t & 0x1F) << 1,
617 time_parts.tm_mday = d & 0x1F,
618 time_parts.tm_mon = ((d >> 5) & 0x0F) - 1,
619 time_parts.tm_year = (d >> 9) + 80,
620 time_parts.tm_isdst = 0
621 );
622 return std::mktime(&time_parts);
623 }
624
625 pair<Timestamp, Timestamp>
626 FetchDateTime() ynothrow
627 {
628 struct std::tm tmp;
629 std::time_t epoch;
630
631 if(std::time(&epoch) != std::time_t(-1))
632 {
633 #if YCL_Win32
634 // NOTE: The return type and parameter order differs than ISO C11
635 // library extension.
636 ::localtime_s(&tmp, &epoch);
637 #else
638 ::localtime_r(&epoch, &tmp);
639 // FIXME: For platforms without %::(localtime_r, localtime_s).
640 #endif
641 // NOTE: Microsoft FAT base year is 1980.
642 return {is_date_range_valid(tmp) ? ((tmp.tm_year - 80) & 0x7F) << 9
643 | ((tmp.tm_mon + 1) & 0xF) << 5 | (tmp.tm_mday & 0x1F) : 0,
644 is_time_no_leap_valid(tmp) ? (tmp.tm_hour & 0x1F) << 11
645 | (tmp.tm_min & 0x3F) << 5 | ((tmp.tm_sec >> 1) & 0x1F) : 0};
646 }
647 return {0, 0};
648 }
649
650
651 void
652 EntryData::CopyLFN(char16_t* str) const ynothrowv
653 {
654 const auto pos(LFN::FetchLongNameOffset((*this)[LFN::Ordinal]));
655
656 YAssertNonnull(str);
657 for(size_t i(0); i < LFN::EntryLength; ++i)
658 if(pos + i < LFN::MaxLength - 1)
659 str[pos + i]
660 = ystdex::read_uint_le<16>(data() + LFN::OffsetTable[i]);
661 }
662
663 pair<EntryDataUnit, size_t>
664 EntryData::FillNewName(string_view name,
665 std::function<bool(string_view)> verify)
666 {
667 YAssertNonnull(name.data()),
668 YAssertNonnull(verify);
669
670 EntryDataUnit alias_check_sum(0);
671 size_t entry_size;
672
673 ClearAlias();
674 if(name == ".")
675 {
676 SetDot(0),
677 entry_size = 1;
678 }
679 else if(name == "..")
680 {
681 SetDot(0),
682 SetDot(1),
683 entry_size = 1;
684 }
685 else
686 {
687 const auto& long_name(MakeUCS2LE(name));
688 const auto len(long_name.length());
689
690 if(len < LFN::MaxLength)
691 {
692 auto alias_tp(LFN::ConvertToAlias(long_name));
693 auto& pri(get<0>(alias_tp));
694 const auto& ext(get<1>(alias_tp));
695 auto alias(pri);
696 const auto check(std::bind(verify, std::ref(alias)));
697
698 if(!ext.empty())
699 alias += '.' + ext;
700 if((get<2>(alias_tp) ? alias.length() : 0) == 0)
701 entry_size = 1;
702 else
703 {
704 entry_size
705 = (len + LFN::EntryLength - 1) / LFN::EntryLength + 1;
706 if(ystdex::ntctsicmp(alias.c_str(), name.data(),
707 LFN::MaxAliasLength) != 0 || check())
708 {
709 size_t i(1);
710
711 pri.resize(LFN::MaxAliasMainPartLength, '_');
712 alias = pri + '.' + ext;
713 ystdex::retry_on_cond(check, [&]{
714 if(YB_UNLIKELY(LFN::MaxNumericTail < i))
715 ystdex::throw_error(std::errc::invalid_argument);
716 LFN::WriteNumericTail(alias, i++);
717 });
718 }
719 }
720 WriteAlias(alias);
721 }
722 else
723 ystdex::throw_error(std::errc::invalid_argument);
724 alias_check_sum = LFN::GenerateAliasChecksum(data());
725 }
726 return {alias_check_sum, entry_size};
727 }
728
729 bool
730 EntryData::FindAlias(string_view name) const
731 {
732 const auto alias(GenerateAlias());
733
734 return ystdex::ntctsicmp(Nonnull(name.data()), alias.c_str(),
735 std::min<size_t>(name.length(), alias.length())) == 0;
736 }
737
738 string
739 EntryData::GenerateAlias() const
740 {
741 if((*this)[0] != Free)
742 {
743 if((*this)[0] == '.')
744 return (*this)[1] == '.' ? ".." : ".";
745
746 // NOTE: Copy the base filename.
747 bool case_info(((*this)[CaseInfo] & LFN::CaseLowerBasename) != 0);
748 const auto conv([&](size_t i){
749 const auto c((*this)[i]);
750
751 return char(case_info ? std::tolower(int(c)) : c);
752 });
753 string res;
754
755 res.reserve(LFN::MaxAliasLength - 1);
756 for(size_t i(0); i < LFN::MaxAliasMainPartLength
757 && (*this)[Name + i] != ' '; ++i)
758 res += conv(Name + i);
759 if((*this)[Extension] != ' ')
760 {
761 res += '.';
762 case_info = ((*this)[CaseInfo] & LFN::CaseLowerExtension) != 0;
763 for(size_t i(0); i < LFN::MaxAliasExtensionLength
764 && (*this)[Extension + i] != ' '; ++i)
765 res += conv(Extension + i);
766 }
767 return res;
768 }
769 return {};
770 }
771
772 void
773 EntryData::SetupRoot(ClusterIndex root_cluster) ynothrow
774 {
775 Clear();
776 ClearAlias(),
777 SetDot(Name),
778 SetDirectoryAttribute();
779 WriteCluster(root_cluster);
780 }
781
782 void
783 EntryData::WriteCluster(ClusterIndex c) ynothrow
784 {
785 using ystdex::write_uint_le;
786
787 write_uint_le<16>(data() + Cluster, c),
788 write_uint_le<16>(data() + ClusterHigh, c >> 16);
789 }
790
791 void
792 EntryData::WriteAlias(const string& alias) ynothrow
793 {
794 size_t i(0), j(0);
795
796 for(; j < LFN::MaxAliasMainPartLength && alias[i] != '.'
797 && alias[i] != char(); yunseq(++i, ++j))
798 (*this)[j] = EntryDataUnit(alias[i]);
799 while(j < LFN::MaxAliasMainPartLength)
800 {
801 (*this)[j] = ' ';
802 ++j;
803 }
804 if(alias[i] == '.')
805 for(++i; alias[i] != char() && j < LFN::AliasEntryLength;
806 yunseq(++i, ++j))
807 (*this)[j] = EntryDataUnit(alias[i]);
808 for(; j < LFN::AliasEntryLength; ++j)
809 (*this)[j] = ' ';
810 }
811
812 void
813 EntryData::WriteCDateTime() ynothrow
814 {
815 using ystdex::write_uint_le;
816 const auto& date_time(FetchDateTime());
817
818 write_uint_le<16>(data() + CTime, date_time.second),
819 write_uint_le<16>(data() + CDate, date_time.first);
820 }
821
822 void
823 EntryData::WriteDateTime() ynothrow
824 {
825 using ystdex::write_uint_le;
826 using ystdex::unseq_apply;
827 const auto date_time(FetchDateTime());
828 const auto dst(data());
829
830 unseq_apply([&](size_t offset){
831 write_uint_le<16>(dst + offset, date_time.first);
832 }, CDate, MDate, ADate),
833 unseq_apply([&](size_t offset){
834 write_uint_le<16>(dst + offset, date_time.second);
835 }, CTime, MTime);
836 }
837
838 const char*
839 CheckColons(const char* path)
840 {
841 if(const auto p_col = std::strchr(Nonnull(path), ':'))
842 {
843 path = p_col + 1;
844 if(std::strchr(path, ':'))
845 ystdex::throw_error(std::errc::invalid_argument);
846 }
847 return path;
848 }
849
850 } // namespace FAT;
851
852 } // namespace platform;
853
854 namespace platform_ex
855 {
856
857 } // namespace platform_ex;
858
CHRLib::YB_NONNULL
YB_NONNULL(1) PDefH(ConversionResult
转换指定编码的多字节字符串为指定类型的 UCS-2 字符串。
ystdex::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:415
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:653
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:740
platform::containers::string
basic_string< char > string
Definition: Container.h:101
platform::Nonnull
_type && Nonnull(_type &&p) ynothrow
断言并返回非空指针。
Definition: Debug.h:411
platform::FAT::LFN::GenerateAliasChecksum
EntryDataUnit GenerateAliasChecksum(const EntryDataUnit *p) ynothrowv
Definition: YCLib/FileSystem.cpp:567
v
byte v
Definition: CharRenderer.cpp:75
platform::CreateHardLink
void CreateHardLink(const char16_t *dst, const char16_t *src)
Definition: YCLib/FileSystem.cpp:225
CHRLib::MakeUCS2LE
_tDst MakeUCS2LE(basic_string_view< char > sv, _tParams &&...args)
Definition: CharacterProcessing.h:538
ystdex::unseq_apply
void unseq_apply(_func &&f, _tParams &&...args)
无序调用。
Definition: functional.hpp:241
platform::FAT::LFN::Ordinal
长文件名序数。
Definition: YCLib/FileSystem.h:837
platform::FAT::CheckColons
const char * CheckColons(const char *path)
Definition: YCLib/FileSystem.cpp:839
platform::containers::u16string
basic_string< char16_t > u16string
Definition: Container.h:103
NPL::A1::name
ctx const string & name
Definition: NPLA1.h:248
platform::FAT::FetchDateTime
YF_API pair< Timestamp, Timestamp > FetchDateTime() ynothrow
取以实时时钟的文件日期和时间。
Definition: YCLib/FileSystem.cpp:626
ystdex::write_uint_le
void write_uint_le(byte *buf, typename make_width_int< _vWidth >::unsigned_type val)
向字节缓冲区写入指定宽的小端序无符号整数。
Definition: cstdint.hpp:339
platform::FAT::LFN::CaseLowerExtension
WinNT 小写扩展名。
Definition: YCLib/FileSystem.h:884
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
platform::NodeCategory
NodeCategory
文件节点类别。
Definition: FileIO.h:117
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:760
platform::FAT::LFN::OffsetTable
yconstexpr const size_t OffsetTable[]
组成长文件名中的 UCS-2 字符在项中的偏移量表。
Definition: YCLib/FileSystem.h:862
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:139
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:105
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:942
ystdex::data
auto data(_tRange &c) -> decltype(c.data())
Definition: range.hpp:280
platform_ex::Windows::Directory
Definition: MinGW32.h:442
platform::FAT::ConvertFileTime
YF_API std::time_t ConvertFileTime(Timestamp, Timestamp) ynothrow
转换日期和时间的时间戳为标准库时间类型。
Definition: YCLib/FileSystem.cpp:609
platform::FAT::LFN::MaxAliasExtensionLength
Definition: YCLib/FileSystem.h:874
CHRLib::c
c
Definition: CharacterProcessing.h:81
platform::FAT::LFN::MaxNumericTail
Definition: YCLib/FileSystem.h:876
platform_ex::Windows::Invalid
Definition: MinGW32.h:461
YCL_CallWin32F
#define YCL_CallWin32F(_fn,...)
Definition: MinGW32.h:179
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:256
CHRLib::char16_t
char16_t((*c_ptr<< CHAR_BIT)|c_ptr[1])) inline PDefH(char16_t
取 c_ptr 指向的小端序双字节字符。
CHRLib::p
const auto p(d)
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
platform::HDirectory::NativeChar
char NativeChar
Definition: YCLib/FileSystem.h:514
ystdex::ntctsicmp
int ntctsicmp(const _tChar *s1, const _tChar *s2)
按字典序比较简单 NTCTS （忽略大小写）。
Definition: cstring.h:213
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:438
platform::FAT::LFN::ValidateName
YF_API bool ValidateName(string_view) ynothrowv
检查名称是否为合法的可被 UCS-2 表示的非控制字符组成。
Definition: YCLib/FileSystem.cpp:581
ystdex::restrict_length
_tString && restrict_length(_tString &&str, const typename string_traits< _tString >::size_type n)
限制长度不超过指定参数。
Definition: string.hpp:455
NPL::dst
YF_API const char src const string const char * dst
Definition: Dependency.h:93
ystdex::rtrim
_tString && rtrim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续后缀字符。
Definition: string.hpp:618
ystdex::throw_error
void throw_error(std::error_code ec, _tParams &&...args)
抛出错误： std::system_error 或允许相同构造函数参数的异常。
Definition: ystdex/exception.h:162
FileAttributes
FileAttributes
文件共享模式。
Definition: MinGW32.h:437
platform
默认平台命名空间。
Definition: Container.h:47
platform::FAT::LFN::ConvertToAlias
YF_API tuple< string, string, bool > ConvertToAlias(const u16string &)
转换长文件名为别名。
Definition: YCLib/FileSystem.cpp:500
YCL_DeclW32Call
#define YCL_DeclW32Call(_fn, _module, _tRet,...)
声明调用 WinAPI 的例程。
Definition: MinGW32.h:244
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:440
platform::CreateSymbolicLink
void CreateSymbolicLink(const char16_t *dst, const char16_t *src, bool is_dir)
Definition: YCLib/FileSystem.cpp:257
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:114
platform::FAT::LFN::MaxLength
UCS-2 项最大长度。
Definition: YCLib/FileSystem.h:868
CHRLib::PDefH
PDefH(char16_t, FetchBiCharBE, const char *c_ptr) ImplRet(yconstraint(c_ptr)
取 c_ptr 指向的大端序双字节字符。
platform::FAT::LFN::WriteNumericTail
YF_API void WriteNumericTail(string &, size_t) ynothrowv
在指定字符串写前缀字符 '~' 和整数的后缀以作为短文件名。
Definition: YCLib/FileSystem.cpp:591
platform::KeyCodes::Win32::Empty
Definition: Keys.h:279
ystdex::size
auto size(const _tRange &c) -> decltype(c.size())
类容器访问。
Definition: range.hpp:233
ystdex::basic_string_view
Definition: string_view.hpp:49
platform_ex::Windows::CategorizeNode
const ::WIN32_FIND_DATAW &d ynothrow ImplRet(d.dwFileAttributes &Directory) YF_API platform YF_API platform::NodeCategory CategorizeNode(UniqueHandle::pointer) ynothrowv
按 ::WIN32_FIND_DATAW 归类节点类别。
Definition: MinGW32.h:532
platform::containers::wstring
basic_string< wchar_t > wstring
Definition: Container.h:108
platform::FAT::LFN::ConvertToMBCS
string ConvertToMBCS(const char16_t *path)
Definition: YCLib/FileSystem.cpp:559
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:996
platform_ex
平台扩展命名空间。
Definition: Android.h:45
YSLib::path
YF_API const char * path
Definition: Initialization.h:74
platform::FAT::LFN::CaseLowerBasename
WinNT 小写文件名。
Definition: YCLib/FileSystem.h:882
platform::DirectorySession
目录会话：表示打开的目录。
Definition: YCLib/FileSystem.h:416
YSLib::Text::str
const char const char * str
Definition: TextFile.h:77
YModules.h
YModules.h
YSLib::i
return i
Definition: YCoreUtilities.h:176
CHRLib
Definition: CharacterDefinition.h:38
platform::FAT::LFN::MaxMBCSLength
UTF-8 项最大长度。
Definition: YCLib/FileSystem.h:870
platform::DirectorySession::Deleter::pointer
NativeHandle pointer
Definition: YCLib/FileSystem.h:433
platform::containers::basic_string
std::basic_string< _tChar, _tTraits, _tAlloc > basic_string
满足 ISO C++03 std::basic_string 但不保证满足 ISO C++11 的实现。
Definition: Container.h:98
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:654
platform::FAT::LFN::MaxAliasMainPartLength
Definition: YCLib/FileSystem.h:873
platform::FAT::LFN::MaxAliasLength
Definition: YCLib/FileSystem.h:875
platform::ReadLink
u16string ReadLink(const char16_t *path)
Definition: YCLib/FileSystem.cpp:306
platform::FAT::LFN::AliasEntryLength
Definition: YCLib/FileSystem.h:872
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
platform::FAT::ClusterIndex
std::uint32_t ClusterIndex
Definition: YCLib/FileSystem.h:629
CHRLib::MakeMBCS
_tDst MakeMBCS(string_view sv, Encoding enc)
Definition: CharacterProcessing.h:603
ystdex::split
void split(_tIn b, _tIn e, _fPred is_delim, _fInsert insert)
以指定分隔符分割序列。
Definition: algorithm.hpp:209
ystdex::make_observer
observer_ptr< _type > make_observer(_type *p)
Definition: memory.hpp:1042
platform::FAT::IllegalAliasCharacters
const char IllegalAliasCharacters[]
非法别名字符。
Definition: YCLib/FileSystem.h:800
platform_ex::Windows::WCSToUTF8
const char *str string_view sv WCSToUTF8
Definition: MinGW32.h:657
YSLib::char
char
Definition: ValueNode.h:851
ystdex::cpp2011::begin
_type * begin(_type(&&array)[_vN])
Definition: range.hpp:46
ystdex::retry_on_cond
result_of_t< _fCallable &&(_tParams &&...)> retry_on_cond(_fCond cond, _fCallable &&f, _tParams &&...args)
循环重复调用：代替直接使用 do-while 语句以避免过多引入作用域外的变量。
Definition: functional.hpp:1019
platform::FAT::Timestamp
std::uint16_t Timestamp
时间戳：表示日期和时间的整数类型。
Definition: YCLib/FileSystem.h:814
platform::FAT::LFN::EntryLength
Definition: YCLib/FileSystem.h:871
platform::FAT::EntryDataUnit
std::uint8_t EntryDataUnit
Definition: YCLib/FileSystem.h:628
ystdex::tolower
_tChar tolower(_tChar c)
转换大小写字符。
Definition: cctype.h:137
ystdex::ntctslen
size_t ntctslen(const _tChar *s)
计算简单 NTCTS 长度。
Definition: cstring.h:456
ystdex::cpp2011::end
_type * end(_type(&&array)[_vN])
Definition: range.hpp:54
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
platform_ex::Windows::UTF8ToWCS
UTF8ToWCS
Definition: MinGW32.h:650
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
platform::bool
std::FILE *fp bool
Definition: FileIO.h:1187
platform::n
size_t n
Definition: YCLib/FileSystem.cpp:321
YSLib::IO::IsAbsolute
IsAbsolute
Definition: YSLib/Service/FileSystem.h:351
ystdex::ref
lref< _type > ref(_type &t)
构造引用包装。
Definition: ref.hpp:120