* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/platform/file.h"
#include <string>
#include <string_view>
#include <windef.h>
#include <winbase.h>
#include <winnt.h>
#include <climits>
#include <system_error>
#include <fileapi.h>
#ifdef ERROR
#undef ERROR
#endif
#ifdef VOID
#undef VOID
#endif
#ifdef CONST
#undef CONST
#endif
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_string.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/log_wrapper.h"
namespace panda::ecmascript {
std::string GetFileDelimiter()
{
return ";";
}
std::string GetPathSeparator()
{
return "\\";
}
bool RealPath(const std::string &path, std::string &realPath, [[maybe_unused]] bool readOnly)
{
realPath = "";
if (path.empty() || path.size() > PATH_MAX) {
LOG_ECMA(WARN) << "File path is illeage";
return false;
}
char buffer[PATH_MAX] = { '\0' };
if (!_fullpath(buffer, path.c_str(), sizeof(buffer) - 1)) {
LOG_ECMA(WARN) << "File path:" << path << " full path failure";
return false;
}
realPath = std::string(buffer);
return true;
}
bool RealPathByChar(const char *path, char *realPath, int rowLength, bool readOnly)
{
(void)path;
(void)realPath;
(void)rowLength;
(void)readOnly;
return false;
}
void DPrintf(fd_t fd, const std::string &buffer)
{
LOG_ECMA(DEBUG) << "Unsupport dprintf fd(" << fd << ") in windows, buffer:" << buffer;
}
void FSync(fd_t fd)
{
LOG_ECMA(DEBUG) << "Unsupport fsync fd(" << fd << ") in windows";
}
void FdsanExchangeOwnerTag(fd_t fd)
{
LOG_ECMA(DEBUG) << "Unsupport FdsanExchangeOwnerTag fd(" << fd << ") in windows";
}
void Close(fd_t fd)
{
CloseHandle(fd);
}
MemMap FileMap(const char *fileName, int flag, int prot, int64_t offset)
{
if (prot == PAGE_PROT_READWRITE) {
flag |= FILE_RDONLY | FILE_WRONLY;
}
fd_t fd = CreateFile(fileName, flag, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (fd == INVALID_FD) {
LOG_ECMA(ERROR) << fileName << " file open failed";
return MemMap();
}
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(fd, &fileSize)) {
CloseHandle(fd);
LOG_ECMA(ERROR) << "GetFileSize failed with error code:" << GetLastError();
return MemMap();
}
auto size = fileSize.QuadPart;
if (size <= 0) {
CloseHandle(fd);
LOG_HOST_TOOL_ERROR << fileName << " file is empty";
return MemMap();
}
fd_t extra = CreateFileMapping(fd, NULL, prot, size >> 32, size & 0xffffffff, nullptr);
if (extra == nullptr) {
CloseHandle(fd);
LOG_ECMA(ERROR) << "CreateFileMapping failed with error code:" << GetLastError();
return MemMap();
}
int accessor = (prot == PAGE_PROT_READ) ? FILE_MAP_READ : FILE_MAP_WRITE;
void *addr = MapViewOfFile(extra, accessor, offset >> 32, offset & 0xffffffff, size);
CloseHandle(extra);
CloseHandle(fd);
if (addr == nullptr) {
LOG_ECMA(ERROR) << "MapViewOfFile failed with error code:" << GetLastError();
}
return MemMap(addr, size);
}
MemMap CreateFileMap([[maybe_unused]] const char *fileName, [[maybe_unused]] int fileSize,
[[maybe_unused]] int flag, [[maybe_unused]] int prot)
{
LOG_ECMA(INFO) << "Unsupport CreateFileMap";
return MemMap(nullptr, 0);
}
MemMap FileMapForAlignAddressByFd(const fd_t fd, int prot, int64_t offset, uint32_t offStart)
{
LOG_ECMA(INFO) << "Don't used fd:" << fd
<< " prot:" << prot << " offset:" << offset << " offStart:" << offStart;
return MemMap();
}
int FileUnMap(MemMap addr)
{
if (UnmapViewOfFile(addr.GetOriginAddr()) == 0) {
return FILE_FAILED;
}
return FILE_SUCCESS;
}
int FileSync(MemMap addr, int flag)
{
LOG_ECMA(INFO) << "Don't used MemMap:" << addr.GetOriginAddr() << ", flag:" << flag;
return -1;
}
CString ResolveFilenameFromNative(JSThread *thread, const CString &dirname,
CString request)
{
std::string relativePath;
int suffixEnd = static_cast<int>(request.find_last_of('.'));
if (request[1] == ':') {
relativePath = request.substr(0, suffixEnd) + ".abc";
} else {
int pos = static_cast<int>(dirname.find_last_of('\\'));
relativePath = dirname.substr(0, pos + 1) + request.substr(0, suffixEnd) + ".abc";
}
std::string absPath;
if (RealPath(relativePath, absPath)) {
CString returnValue(absPath);
return returnValue;
}
THROW_REFERENCE_ERROR_AND_RETURN(thread, "resolve absolute path fail", CString());
}
bool FileExist(const char *filename)
{
return (_access(filename, 0) != -1);
}
int Unlink(const char *filename)
{
return _unlink(filename);
}
void *LoadLib([[maybe_unused]] const std::string &liname)
{
LOG_ECMA(INFO) << "Unsupport LoadLib";
return nullptr;
}
void *FindSymbol([[maybe_unused]] void *handle, [[maybe_unused]] const char *symbol)
{
LOG_ECMA(INFO) << "Unsupport FindSymbol";
return nullptr;
}
int CloseLib([[maybe_unused]] void *handle)
{
LOG_ECMA(INFO) << "Unsupport CloseLib";
return 0;
}
char *LoadLibError()
{
LOG_ECMA(INFO) << "Unsupport LoadLibError";
return nullptr;
}
void DeleteFilesWithSuffix(const std::string &dirPath, const std::string &suffix)
{
LOG_ECMA(INFO) << "Unsupport dirPath: " << dirPath << ", suffix: " << suffix;
}
void LogUnsupportedPlatform(const std::string_view &tag)
{
LOG_ECMA(WARN) << "\"" << tag << "\" is not supported on this platform.";
_set_errno(ENOSYS);
}
template <typename T> T LogUnsupportedPlatform(const std::string_view &tag, T ret)
{
LogUnsupportedPlatform(tag);
return ret;
}
std::error_code Iterdir(const std::string& path, const IterdirCallback& callback)
{
return LogUnsupportedPlatform(__func__, std::error_code(ENOSYS, std::generic_category()));
}
bool Chmod([[maybe_unused]] const std::string_view &path, [[maybe_unused]] const std::string_view &mode)
{
LOG_ECMA(WARN) << "Chmod is not supported on this platform.";
return false;
}
bool Chmod([[maybe_unused]] const std::string_view &path,
[[maybe_unused]] const std::string_view &mode,
[[maybe_unused]] std::error_code &errorCode)
{
return LogUnsupportedPlatform(__func__, false);
}
std::error_code Rename(const char *oldPath, const char *newPath, bool existOk)
{
return LogUnsupportedPlatform(__func__, std::error_code(ENOSYS, std::generic_category()));
}
constexpr const std::string_view POSIX_FILE_CLASS_NAME = "PosixFile";
PosixFile::PosixFile([[maybe_unused]] const std::string_view &path,
[[maybe_unused]] const std::string_view &flags,
[[maybe_unused]] const std::string_view &mode)
{
LogUnsupportedPlatform(POSIX_FILE_CLASS_NAME);
}
PosixFile::~PosixFile() {}
int64_t PosixFile::Write([[maybe_unused]] const char *data, [[maybe_unused]] size_t size)
{
return LogUnsupportedPlatform(POSIX_FILE_CLASS_NAME, -1);
}
int64_t PosixFile::Read([[maybe_unused]] char *buf, [[maybe_unused]] size_t size)
{
return LogUnsupportedPlatform(POSIX_FILE_CLASS_NAME, -1);
}
int64_t PosixFile::Seek([[maybe_unused]] int64_t off, [[maybe_unused]] SeekOrigin whence)
{
return LogUnsupportedPlatform(POSIX_FILE_CLASS_NAME, -1);
}
int64_t PosixFile::Tell() { return LogUnsupportedPlatform(POSIX_FILE_CLASS_NAME, -1); }
int64_t PosixFile::Size() { return LogUnsupportedPlatform(POSIX_FILE_CLASS_NAME, -1); }
}