18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci#include "io/std_file.h" 178bf80f4bSopenharmony_ci 188bf80f4bSopenharmony_ci#include <cstdint> 198bf80f4bSopenharmony_ci 208bf80f4bSopenharmony_ci#ifdef __has_include 218bf80f4bSopenharmony_ci#if __has_include(<filesystem>) 228bf80f4bSopenharmony_ci#include <filesystem> 238bf80f4bSopenharmony_ci#endif 248bf80f4bSopenharmony_ci#endif 258bf80f4bSopenharmony_ci 268bf80f4bSopenharmony_ci#ifndef HAS_FILESYSTEM 278bf80f4bSopenharmony_ci#include <cerrno> 288bf80f4bSopenharmony_ci#include <dirent.h> 298bf80f4bSopenharmony_ci 308bf80f4bSopenharmony_ci#ifndef _DIRENT_HAVE_D_TYPE 318bf80f4bSopenharmony_ci#include <sys/stat.h> 328bf80f4bSopenharmony_ci#include <sys/types.h> 338bf80f4bSopenharmony_ci 348bf80f4bSopenharmony_ci#endif 358bf80f4bSopenharmony_ci#include <climits> 368bf80f4bSopenharmony_ci#define CORE_MAX_PATH PATH_MAX 378bf80f4bSopenharmony_ci#endif 388bf80f4bSopenharmony_ci 398bf80f4bSopenharmony_ci#include <base/containers/string.h> 408bf80f4bSopenharmony_ci#include <base/containers/string_view.h> 418bf80f4bSopenharmony_ci#include <core/io/intf_file.h> 428bf80f4bSopenharmony_ci#include <core/log.h> 438bf80f4bSopenharmony_ci#include <core/namespace.h> 448bf80f4bSopenharmony_ci 458bf80f4bSopenharmony_ci#include "io/std_directory.h" 468bf80f4bSopenharmony_ci 478bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE() 488bf80f4bSopenharmony_ciusing BASE_NS::string; 498bf80f4bSopenharmony_ciusing BASE_NS::string_view; 508bf80f4bSopenharmony_ci 518bf80f4bSopenharmony_cinamespace { 528bf80f4bSopenharmony_cistd::ios_base::openmode OpenFileAccessMode(IFile::Mode mode) 538bf80f4bSopenharmony_ci{ 548bf80f4bSopenharmony_ci switch (mode) { 558bf80f4bSopenharmony_ci case IFile::Mode::INVALID: 568bf80f4bSopenharmony_ci CORE_ASSERT_MSG(false, "Invalid file access mode."); 578bf80f4bSopenharmony_ci return {}; 588bf80f4bSopenharmony_ci case IFile::Mode::READ_ONLY: 598bf80f4bSopenharmony_ci return std::ios_base::binary | std::ios_base::in; 608bf80f4bSopenharmony_ci case IFile::Mode::READ_WRITE: 618bf80f4bSopenharmony_ci return std::ios_base::binary | std::ios_base::out | std::ios_base::in; 628bf80f4bSopenharmony_ci default: 638bf80f4bSopenharmony_ci return {}; 648bf80f4bSopenharmony_ci } 658bf80f4bSopenharmony_ci} 668bf80f4bSopenharmony_ci 678bf80f4bSopenharmony_cistd::ios_base::openmode CreateFileAccessMode(IFile::Mode mode) 688bf80f4bSopenharmony_ci{ 698bf80f4bSopenharmony_ci switch (mode) { 708bf80f4bSopenharmony_ci case IFile::Mode::INVALID: 718bf80f4bSopenharmony_ci case IFile::Mode::READ_ONLY: 728bf80f4bSopenharmony_ci CORE_ASSERT_MSG(false, "Invalid create file access mode."); 738bf80f4bSopenharmony_ci return {}; 748bf80f4bSopenharmony_ci case IFile::Mode::READ_WRITE: 758bf80f4bSopenharmony_ci return std::ios_base::binary | std::ios_base::out | std::ios_base::in | std::ios_base::trunc; 768bf80f4bSopenharmony_ci default: 778bf80f4bSopenharmony_ci return {}; 788bf80f4bSopenharmony_ci } 798bf80f4bSopenharmony_ci} 808bf80f4bSopenharmony_ci 818bf80f4bSopenharmony_ci#if defined(HAS_FILESYSTEM) 828bf80f4bSopenharmony_cistd::filesystem::path U8Path(string_view str) 838bf80f4bSopenharmony_ci{ 848bf80f4bSopenharmony_ci return std::filesystem::u8path(str.begin().ptr(), str.end().ptr()); 858bf80f4bSopenharmony_ci} 868bf80f4bSopenharmony_ci#endif 878bf80f4bSopenharmony_ci} // namespace 888bf80f4bSopenharmony_ci 898bf80f4bSopenharmony_ciStdFile::StdFile(Mode mode, std::fstream&& stream) : mode_(mode), file_(BASE_NS::move(stream)) {} 908bf80f4bSopenharmony_ci 918bf80f4bSopenharmony_ciStdFile::~StdFile() 928bf80f4bSopenharmony_ci{ 938bf80f4bSopenharmony_ci Close(); 948bf80f4bSopenharmony_ci} 958bf80f4bSopenharmony_ci 968bf80f4bSopenharmony_ciIFile::Mode StdFile::GetMode() const 978bf80f4bSopenharmony_ci{ 988bf80f4bSopenharmony_ci return mode_; 998bf80f4bSopenharmony_ci} 1008bf80f4bSopenharmony_ci 1018bf80f4bSopenharmony_cibool StdFile::IsValidPath(const string_view /* path */) 1028bf80f4bSopenharmony_ci{ 1038bf80f4bSopenharmony_ci // Path's should always be valid here. 1048bf80f4bSopenharmony_ci return true; 1058bf80f4bSopenharmony_ci} 1068bf80f4bSopenharmony_ci 1078bf80f4bSopenharmony_ciIFile::Ptr StdFile::Open(const string_view path, Mode mode) 1088bf80f4bSopenharmony_ci{ 1098bf80f4bSopenharmony_ci#if defined(HAS_FILESYSTEM) 1108bf80f4bSopenharmony_ci std::error_code ec; 1118bf80f4bSopenharmony_ci auto canonicalPath = std::filesystem::canonical(U8Path(path), ec); 1128bf80f4bSopenharmony_ci if (ec) { 1138bf80f4bSopenharmony_ci return {}; 1148bf80f4bSopenharmony_ci } 1158bf80f4bSopenharmony_ci 1168bf80f4bSopenharmony_ci if (std::filesystem::is_directory(canonicalPath)) { 1178bf80f4bSopenharmony_ci return {}; 1188bf80f4bSopenharmony_ci } 1198bf80f4bSopenharmony_ci 1208bf80f4bSopenharmony_ci if (auto stream = std::fstream(canonicalPath, OpenFileAccessMode(mode)); stream) { 1218bf80f4bSopenharmony_ci return IFile::Ptr { BASE_NS::make_unique<StdFile>(mode, BASE_NS::move(stream)).release() }; 1228bf80f4bSopenharmony_ci } 1238bf80f4bSopenharmony_ci#else 1248bf80f4bSopenharmony_ci char canonicalPath[CORE_MAX_PATH] = { 0 }; 1258bf80f4bSopenharmony_ci if (realpath(string(path).c_str(), canonicalPath) == nullptr) { 1268bf80f4bSopenharmony_ci return {}; 1278bf80f4bSopenharmony_ci } 1288bf80f4bSopenharmony_ci 1298bf80f4bSopenharmony_ci if (auto stream = std::fstream(canonicalPath, OpenFileAccessMode(mode)); stream) { 1308bf80f4bSopenharmony_ci return IFile::Ptr { BASE_NS::make_unique<StdFile>(mode, BASE_NS::move(stream)).release() }; 1318bf80f4bSopenharmony_ci } 1328bf80f4bSopenharmony_ci 1338bf80f4bSopenharmony_ci#endif 1348bf80f4bSopenharmony_ci return {}; 1358bf80f4bSopenharmony_ci} 1368bf80f4bSopenharmony_ci 1378bf80f4bSopenharmony_ciIFile::Ptr StdFile::Create(const string_view path, Mode mode) 1388bf80f4bSopenharmony_ci{ 1398bf80f4bSopenharmony_ci if (path.empty()) { 1408bf80f4bSopenharmony_ci return {}; 1418bf80f4bSopenharmony_ci } 1428bf80f4bSopenharmony_ci 1438bf80f4bSopenharmony_ci#if defined(HAS_FILESYSTEM) 1448bf80f4bSopenharmony_ci std::error_code ec; 1458bf80f4bSopenharmony_ci auto canonicalPath = std::filesystem::weakly_canonical(U8Path(path), ec); 1468bf80f4bSopenharmony_ci if (ec) { 1478bf80f4bSopenharmony_ci return {}; 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci // Create the file. 1508bf80f4bSopenharmony_ci if (auto stream = std::fstream(canonicalPath, CreateFileAccessMode(mode)); stream) { 1518bf80f4bSopenharmony_ci return IFile::Ptr { BASE_NS::make_unique<StdFile>(mode, BASE_NS::move(stream)).release() }; 1528bf80f4bSopenharmony_ci } 1538bf80f4bSopenharmony_ci#else 1548bf80f4bSopenharmony_ci // NOTE: As realpath requires that the path exists, we check that the 1558bf80f4bSopenharmony_ci // parent dir is valid instead of the full path of the file being created. 1568bf80f4bSopenharmony_ci const string parentDir = StdDirectory::GetDirName(path); 1578bf80f4bSopenharmony_ci char canonicalParentPath[CORE_MAX_PATH] = { 0 }; 1588bf80f4bSopenharmony_ci if (realpath(parentDir.c_str(), canonicalParentPath) == nullptr) { 1598bf80f4bSopenharmony_ci return {}; 1608bf80f4bSopenharmony_ci } 1618bf80f4bSopenharmony_ci const string filename = StdDirectory::GetBaseName(path); 1628bf80f4bSopenharmony_ci const string fullPath = string_view(canonicalParentPath) + '/' + filename; 1638bf80f4bSopenharmony_ci 1648bf80f4bSopenharmony_ci // Create the file. 1658bf80f4bSopenharmony_ci if (auto stream = std::fstream(fullPath.data(), CreateFileAccessMode(mode)); stream) { 1668bf80f4bSopenharmony_ci return IFile::Ptr { BASE_NS::make_unique<StdFile>(mode, BASE_NS::move(stream)).release() }; 1678bf80f4bSopenharmony_ci } 1688bf80f4bSopenharmony_ci#endif 1698bf80f4bSopenharmony_ci return {}; 1708bf80f4bSopenharmony_ci} 1718bf80f4bSopenharmony_ci 1728bf80f4bSopenharmony_civoid StdFile::Close() 1738bf80f4bSopenharmony_ci{ 1748bf80f4bSopenharmony_ci if (file_.is_open()) { 1758bf80f4bSopenharmony_ci file_ = {}; 1768bf80f4bSopenharmony_ci mode_ = Mode::INVALID; 1778bf80f4bSopenharmony_ci } 1788bf80f4bSopenharmony_ci} 1798bf80f4bSopenharmony_ci 1808bf80f4bSopenharmony_ciuint64_t StdFile::Read(void* buffer, uint64_t count) 1818bf80f4bSopenharmony_ci{ 1828bf80f4bSopenharmony_ci file_.read(static_cast<char*>(buffer), static_cast<std::streamsize>(count)); 1838bf80f4bSopenharmony_ci if (file_.eof() && file_.fail()) { 1848bf80f4bSopenharmony_ci file_.clear(); 1858bf80f4bSopenharmony_ci } 1868bf80f4bSopenharmony_ci return static_cast<uint64_t>(file_.gcount()); 1878bf80f4bSopenharmony_ci} 1888bf80f4bSopenharmony_ci 1898bf80f4bSopenharmony_ciuint64_t StdFile::Write(const void* buffer, uint64_t count) 1908bf80f4bSopenharmony_ci{ 1918bf80f4bSopenharmony_ci const auto pos = file_.tellp(); 1928bf80f4bSopenharmony_ci file_.write(static_cast<const char*>(buffer), static_cast<std::streamsize>(count)); 1938bf80f4bSopenharmony_ci return static_cast<uint64_t>(file_.tellp() - pos); 1948bf80f4bSopenharmony_ci} 1958bf80f4bSopenharmony_ci 1968bf80f4bSopenharmony_ciuint64_t StdFile::GetLength() const 1978bf80f4bSopenharmony_ci{ 1988bf80f4bSopenharmony_ci const auto offset = file_.tellg(); 1998bf80f4bSopenharmony_ci if (offset == decltype(file_)::pos_type(-1)) { 2008bf80f4bSopenharmony_ci return {}; 2018bf80f4bSopenharmony_ci } 2028bf80f4bSopenharmony_ci 2038bf80f4bSopenharmony_ci const auto end = file_.seekg(0, std::ios_base::end).tellg(); 2048bf80f4bSopenharmony_ci if (!file_.good()) { 2058bf80f4bSopenharmony_ci return {}; 2068bf80f4bSopenharmony_ci } 2078bf80f4bSopenharmony_ci const auto beg = file_.seekg(0, std::ios_base::beg).tellg(); 2088bf80f4bSopenharmony_ci file_.seekg(offset); 2098bf80f4bSopenharmony_ci return static_cast<uint64_t>(end - beg); 2108bf80f4bSopenharmony_ci} 2118bf80f4bSopenharmony_ci 2128bf80f4bSopenharmony_cibool StdFile::Seek(uint64_t offset) 2138bf80f4bSopenharmony_ci{ 2148bf80f4bSopenharmony_ci file_.seekg(static_cast<decltype(file_)::off_type>(offset), std::ios_base::beg); 2158bf80f4bSopenharmony_ci return file_.good(); 2168bf80f4bSopenharmony_ci} 2178bf80f4bSopenharmony_ci 2188bf80f4bSopenharmony_ciuint64_t StdFile::GetPosition() const 2198bf80f4bSopenharmony_ci{ 2208bf80f4bSopenharmony_ci return static_cast<uint64_t>(file_.tellg()); 2218bf80f4bSopenharmony_ci} 2228bf80f4bSopenharmony_ciCORE_END_NAMESPACE() 223