1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/platform/file.h"
17
18#include <windef.h>
19#include <winbase.h>
20#include <winnt.h>
21#include <climits>
22#include <fileapi.h>
23
24#ifdef ERROR
25#undef ERROR
26#endif
27
28#ifdef VOID
29#undef VOID
30#endif
31
32#ifdef CONST
33#undef CONST
34#endif
35
36#include "ecmascript/ecma_macros.h"
37#include "ecmascript/ecma_string.h"
38#include "ecmascript/js_tagged_value-inl.h"
39#include "ecmascript/log_wrapper.h"
40#include "ecmascript/platform/map.h"
41
42namespace panda::ecmascript {
43std::string GetFileDelimiter()
44{
45    return ";";
46}
47
48std::string GetPathSeparator()
49{
50    return "\\";
51}
52
53bool RealPath(const std::string &path, std::string &realPath, [[maybe_unused]] bool readOnly)
54{
55    realPath = "";
56    if (path.empty() || path.size() > PATH_MAX) {
57        LOG_ECMA(WARN) << "File path is illeage";
58        return false;
59    }
60    char buffer[PATH_MAX] = { '\0' };
61    if (!_fullpath(buffer, path.c_str(), sizeof(buffer) - 1)) {
62        LOG_ECMA(WARN) << "File path:" << path << " full path failure";
63        return false;
64    }
65    realPath = std::string(buffer);
66    return true;
67}
68
69bool RealPathByChar(const char *path, char *realPath, int rowLength, bool readOnly)
70{
71    (void)path;
72    (void)realPath;
73    (void)rowLength;
74    (void)readOnly;
75    return false;
76}
77
78void DPrintf(fd_t fd, const std::string &buffer)
79{
80    LOG_ECMA(DEBUG) << "Unsupport dprintf fd(" << fd << ") in windows, buffer:" << buffer;
81}
82
83void FSync(fd_t fd)
84{
85    LOG_ECMA(DEBUG) << "Unsupport fsync fd(" << fd << ") in windows";
86}
87
88void Close(fd_t fd)
89{
90    CloseHandle(fd);
91}
92
93MemMap FileMap(const char *fileName, int flag, int prot, int64_t offset)
94{
95    if (prot == PAGE_PROT_READWRITE) {
96        flag |= FILE_RDONLY | FILE_WRONLY;
97    }
98    fd_t fd = CreateFile(fileName, flag, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
99    if (fd == INVALID_FD) {
100        LOG_ECMA(ERROR) << fileName << " file open failed";
101        return MemMap();
102    }
103
104    LARGE_INTEGER fileSize;
105    if (!GetFileSizeEx(fd, &fileSize)) {
106        CloseHandle(fd);
107        LOG_ECMA(ERROR) << "GetFileSize failed with error code:" << GetLastError();
108        return MemMap();
109    }
110    auto size = fileSize.QuadPart;
111    if (size <= 0) {
112        CloseHandle(fd);
113        LOG_HOST_TOOL_ERROR << fileName << " file is empty";
114        return MemMap();
115    }
116
117    // 32: high 32 bits
118    fd_t extra = CreateFileMapping(fd, NULL, prot, size >> 32, size & 0xffffffff, nullptr);
119    if (extra == nullptr) {
120        CloseHandle(fd);
121        LOG_ECMA(ERROR) << "CreateFileMapping failed with error code:" << GetLastError();
122        return MemMap();
123    }
124    int accessor = (prot == PAGE_PROT_READ) ? FILE_MAP_READ : FILE_MAP_WRITE;
125    void *addr = MapViewOfFile(extra, accessor, offset >> 32, offset & 0xffffffff, size);
126    CloseHandle(extra);
127    CloseHandle(fd);
128    if (addr == nullptr) {
129        LOG_ECMA(ERROR) << "MapViewOfFile failed with error code:" << GetLastError();
130    }
131    return MemMap(addr, size);
132}
133
134MemMap FileMapForAlignAddress(const char *fileName, int flag, int prot,
135                              int64_t offset, uint32_t offStart)
136{
137    // AOT not used, previewer used
138    LOG_ECMA(INFO) << "Don't used fileName:" << fileName << " flag:" << flag
139                   << " prot:" << prot << " offset:" << offset << " offStart:" << offStart;
140    return MemMap();
141}
142
143int FileUnMap(MemMap addr)
144{
145    if (UnmapViewOfFile(addr.GetOriginAddr()) == 0) {
146        return FILE_FAILED;
147    }
148    return FILE_SUCCESS;
149}
150
151CString ResolveFilenameFromNative(JSThread *thread, const CString &dirname,
152                                  CString request)
153{
154    std::string relativePath;
155    int suffixEnd = static_cast<int>(request.find_last_of('.'));
156    if (request[1] == ':') { // absoluteFilePath
157        relativePath = request.substr(0, suffixEnd) + ".abc";
158    } else {
159        int pos = static_cast<int>(dirname.find_last_of('\\'));
160        relativePath = dirname.substr(0, pos + 1) + request.substr(0, suffixEnd) + ".abc";
161    }
162
163    std::string absPath;
164    if (RealPath(relativePath, absPath)) {
165        return absPath.c_str();
166    }
167    THROW_REFERENCE_ERROR_AND_RETURN(thread, "resolve absolute path fail", CString());
168}
169
170bool FileExist(const char *filename)
171{
172    return (_access(filename, 0) != -1);
173}
174
175int Unlink(const char *filename)
176{
177    return _unlink(filename);
178}
179
180bool TryToRemoveSO([[maybe_unused]] JSThread *thread, [[maybe_unused]] JSHandle<SourceTextModule> module)
181{
182    return false;
183}
184
185void *LoadLib([[maybe_unused]] const std::string &liname)
186{
187    LOG_ECMA(INFO) << "Unsupport LoadLib";
188    return nullptr;
189}
190
191void *FindSymbol([[maybe_unused]] void *handle, [[maybe_unused]] const char *symbol)
192{
193    LOG_ECMA(INFO) << "Unsupport FindSymbol";
194    return nullptr;
195}
196
197int CloseLib([[maybe_unused]] void *handle)
198{
199    LOG_ECMA(INFO) << "Unsupport CloseLib";
200    return 0;
201}
202
203char *LoadLibError()
204{
205    LOG_ECMA(INFO) << "Unsupport LoadLibError";
206    return nullptr;
207}
208}  // namespace panda::ecmascript
209