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 <cerrno>
19 #include <climits>
20 #include <sys/mman.h>
21 #include <unistd.h>
22
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/ecma_macros.h"
25 #include "ecmascript/log_wrapper.h"
26 #include "ecmascript/platform/map.h"
27
28 namespace panda::ecmascript {
GetFileDelimiter()29 std::string GetFileDelimiter()
30 {
31 return ":";
32 }
33
RealPath(const std::string & path,std::string & realPath,bool readOnly)34 bool RealPath(const std::string &path, std::string &realPath, bool readOnly)
35 {
36 if (path.empty() || path.size() > PATH_MAX) {
37 LOG_ECMA(WARN) << "File path is illeage";
38 return false;
39 }
40 char buffer[PATH_MAX] = { '\0' };
41 if (!realpath(path.c_str(), buffer)) {
42 // Maybe file does not exist.
43 if (!readOnly && errno == ENOENT) {
44 realPath = path;
45 return true;
46 }
47 LOG_ECMA(ERROR) << "File path:" << path << " realpath failure";
48 return false;
49 }
50 realPath = std::string(buffer);
51 return true;
52 }
53
DPrintf(fd_t fd,const std::string & buffer)54 void DPrintf(fd_t fd, const std::string &buffer)
55 {
56 int ret = dprintf(fd, "%s", buffer.c_str());
57 if (ret < 0) {
58 LOG_ECMA(DEBUG) << "dprintf fd(" << fd << ") failed";
59 }
60 }
61
FSync(fd_t fd)62 void FSync(fd_t fd)
63 {
64 int ret = fsync(fd);
65 if (ret < 0) {
66 LOG_ECMA(DEBUG) << "fsync fd(" << fd << ") failed";
67 }
68 }
69
Close(fd_t fd)70 void Close(fd_t fd)
71 {
72 close(fd);
73 }
74
FileMap(const char * fileName,int flag,int prot,int64_t offset)75 MemMap FileMap(const char *fileName, int flag, int prot, int64_t offset)
76 {
77 fd_t fd = open(fileName, flag);
78 if (fd == INVALID_FD) {
79 LOG_ECMA(ERROR) << fileName << " file open failed";
80 return MemMap();
81 }
82
83 size_t size = static_cast<size_t>(lseek(fd, 0, SEEK_END));
84 if (size <= 0) {
85 close(fd);
86 LOG_ECMA(ERROR) << fileName << " file is empty";
87 return MemMap();
88 }
89
90 void *addr = mmap(nullptr, size, prot, MAP_PRIVATE, fd, offset);
91 close(fd);
92 return MemMap(addr, size);
93 }
94
FileUnMap(MemMap addr)95 int FileUnMap(MemMap addr)
96 {
97 return munmap(addr.GetOriginAddr(), addr.GetSize());
98 }
99
ResolveFilenameFromNative(JSThread * thread,JSTaggedValue dirname,JSTaggedValue request)100 JSHandle<EcmaString> ResolveFilenameFromNative(JSThread *thread, JSTaggedValue dirname,
101 JSTaggedValue request)
102 {
103 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
104 CString fullname;
105 CString resolvedFilename;
106 CString dirnameStr = ConvertToString(EcmaString::Cast(dirname.GetTaggedObject()));
107 CString requestStr = ConvertToString(EcmaString::Cast(request.GetTaggedObject()));
108
109 if (requestStr.find("./") == 0) {
110 requestStr = requestStr.substr(2); // 2 : delete './'
111 }
112 int suffixEnd = static_cast<int>(requestStr.find_last_of('.'));
113 if (suffixEnd == -1) {
114 RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
115 }
116 if (requestStr[0] == '/') { // absolute FilePath
117 fullname = requestStr.substr(0, suffixEnd) + ".abc";
118 } else {
119 int pos = static_cast<int>(dirnameStr.find_last_of('/'));
120 if (pos == -1) {
121 RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
122 }
123 fullname = dirnameStr.substr(0, pos + 1) + requestStr.substr(0, suffixEnd) + ".abc";
124 }
125
126 std::string relativePath = CstringConvertToStdString(fullname);
127 std::string absPath = "";
128 if (RealPath(relativePath, absPath)) {
129 resolvedFilename = ConvertToString(absPath);
130 return factory->NewFromUtf8(resolvedFilename);
131 }
132 CString msg = "resolve absolute path fail";
133 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, EcmaString, msg.c_str());
134 }
135 } // namespace panda::ecmascript
136