| 1782 | } |
| 1783 | |
| 1784 | bool FileSystem::IsWritableFile(StringView path) |
| 1785 | { |
| 1786 | if (path.empty()) return false; |
| 1787 | |
| 1788 | #if defined(DEATH_TARGET_WINDOWS_RT) |
| 1789 | SmallVector<wchar_t, MAX_PATH + 1> pathW(DefaultInit, path.size() + 1); |
| 1790 | Utf8::ToUtf16(pathW.data(), std::int32_t(pathW.size()), path.data(), std::int32_t(path.size())); |
| 1791 | WIN32_FILE_ATTRIBUTE_DATA lpFileInfo; |
| 1792 | return (::GetFileAttributesExFromAppW(pathW.data(), GetFileExInfoStandard, &lpFileInfo) && (lpFileInfo.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) == 0); |
| 1793 | #elif defined(DEATH_TARGET_WINDOWS) |
| 1794 | SmallVector<wchar_t, MAX_PATH + 1> pathW(DefaultInit, path.size() + 1); |
| 1795 | Utf8::ToUtf16(pathW.data(), std::int32_t(pathW.size()), path.data(), std::int32_t(path.size())); |
| 1796 | const DWORD attrs = ::GetFileAttributesW(pathW.data()); |
| 1797 | return (attrs != INVALID_FILE_ATTRIBUTES && (attrs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) == 0); |
| 1798 | #else |
| 1799 | auto nullTerminatedPath = String::nullTerminatedView(path); |
| 1800 | # if defined(DEATH_TARGET_ANDROID) |
| 1801 | if (AndroidAssetStream::TryGetAssetPath(nullTerminatedPath)) { |
| 1802 | // Android assets are not writable |
| 1803 | return false; |
| 1804 | } |
| 1805 | # endif |
| 1806 | struct stat sb; |
| 1807 | if (::stat(nullTerminatedPath.data(), &sb) == 0) { |
| 1808 | return ((sb.st_mode & S_IFMT) == S_IFREG && (sb.st_mode & S_IWUSR) != 0); |
| 1809 | } |
| 1810 | #endif |
| 1811 | return false; |
| 1812 | } |
| 1813 | |
| 1814 | bool FileSystem::IsSymbolicLink(StringView path) |
| 1815 | { |