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/base/path_helper.h" 24#include "ecmascript/module/js_module_source_text.h" 25 26namespace panda::ecmascript { 27std::string GetFileDelimiter() 28{ 29 return ":"; 30} 31 32std::string GetPathSeparator() 33{ 34 return "/"; 35} 36 37bool RealPath(const std::string &path, std::string &realPath, bool readOnly) 38{ 39 if (path.empty() || path.size() > PATH_MAX) { 40 LOG_ECMA(WARN) << "File path is illegal"; 41 return false; 42 } 43 char buffer[PATH_MAX] = { '\0' }; 44 if (!realpath(path.c_str(), buffer)) { 45 // Maybe file does not exist. 46 if (!readOnly && errno == ENOENT) { 47 realPath = path; 48 return true; 49 } 50 LOG_ECMA(ERROR) << "File path: " << path << " realpath failure. errno: " << errno; 51 return false; 52 } 53 realPath = std::string(buffer); 54 return true; 55} 56 57bool RealPathByChar(const char *path, char *realPath, int rowLength, bool readOnly) 58{ 59 if (strlen(path) == 0 || strlen(path) > PATH_MAX) { 60 return false; 61 } 62 char buffer[PATH_MAX] = { '\0' }; 63 if (!realpath(path, buffer)) { 64 // Maybe file does not exist. 65 if (!readOnly && errno == ENOENT) { 66 if (strcpy_s(realPath, rowLength, path) != 0) { 67 return false; 68 } 69 return true; 70 } 71 return false; 72 } 73 if (strcpy_s(realPath, rowLength, buffer) != 0) { 74 return false; 75 } 76 return true; 77} 78 79void DPrintf(fd_t fd, const std::string &buffer) 80{ 81 int ret = dprintf(fd, "%s", buffer.c_str()); 82 if (ret < 0) { 83 LOG_ECMA(DEBUG) << "dprintf fd(" << fd << ") failed"; 84 } 85} 86 87void FSync(fd_t fd) 88{ 89 int ret = fsync(fd); 90 if (ret < 0) { 91 LOG_ECMA(DEBUG) << "fsync fd(" << fd << ") failed"; 92 } 93} 94 95void Close(fd_t fd) 96{ 97 close(fd); 98} 99 100MemMap FileMap(const char *fileName, int flag, int prot, int64_t offset) 101{ 102 fd_t fd = open(fileName, flag); 103 if (fd == INVALID_FD) { 104 LOG_ECMA(ERROR) << fileName << " file open failed"; 105 return MemMap(); 106 } 107 108 off_t size = lseek(fd, 0, SEEK_END); 109 if (size <= 0) { 110 close(fd); 111 LOG_ECMA(ERROR) << fileName << " file is empty"; 112 return MemMap(); 113 } 114 115 void *addr = mmap(nullptr, size, prot, MAP_PRIVATE, fd, offset); 116 close(fd); 117 return MemMap(addr, size); 118} 119 120MemMap FileMapForAlignAddress(const char *fileName, int flag, int prot, 121 int64_t offset, uint32_t offStart) 122{ 123 fd_t fd = open(fileName, flag); 124 if (fd == INVALID_FD) { 125 LOG_ECMA(ERROR) << fileName << " file open failed"; 126 return MemMap(); 127 } 128 129 off_t size = lseek(fd, 0, SEEK_END); 130 if (size <= 0) { 131 close(fd); 132 LOG_ECMA(ERROR) << fileName << " file is empty"; 133 return MemMap(); 134 } 135 void *addr = mmap(nullptr, size + offset - offStart, prot, MAP_PRIVATE, fd, offStart); 136 close(fd); 137 return MemMap(addr, size); 138} 139 140int FileUnMap(MemMap addr) 141{ 142 return munmap(addr.GetOriginAddr(), addr.GetSize()); 143} 144 145CString ResolveFilenameFromNative(JSThread *thread, const CString &dirname, 146 CString request) 147{ 148 std::string relativePath; 149 if (request.find("./") == 0) { 150 request = request.substr(2); // 2 : delete './' 151 } 152 int suffixEnd = static_cast<int>(request.find_last_of('.')); 153 if (request[0] == '/') { // absolute FilePath 154 relativePath = request.substr(0, suffixEnd) + ".abc"; 155 } else { 156 int pos = static_cast<int>(dirname.find_last_of('/')); 157 relativePath = dirname.substr(0, pos + 1) + request.substr(0, suffixEnd) + ".abc"; 158 } 159 160 std::string absPath = ""; 161 if (RealPath(relativePath.c_str(), absPath)) { 162 return absPath.c_str(); 163 } 164 THROW_REFERENCE_ERROR_AND_RETURN(thread, "resolve absolute path fail", CString()); 165} 166 167bool FileExist(const char *filename) 168{ 169 return (access(filename, F_OK) != -1); 170} 171 172int Unlink(const char *filename) 173{ 174 return unlink(filename); 175} 176 177bool TryToRemoveSO(JSThread *thread, JSHandle<SourceTextModule> module) 178{ 179 UnloadNativeModuleCallback unloadNativeModuleCallback = thread->GetEcmaVM()->GetUnloadNativeModuleCallback(); 180 if (unloadNativeModuleCallback == nullptr) { 181 LOG_ECMA(ERROR) << "unloadNativeModuleCallback is nullptr"; 182 return false; 183 } 184 185 CString soName = base::PathHelper::GetStrippedModuleName(module->GetEcmaModuleRecordNameString()); 186 return unloadNativeModuleCallback(soName.c_str()); 187} 188 189void *LoadLib(const std::string &libname) 190{ 191 return dlopen(libname.c_str(), RTLD_NOW); 192} 193 194void *FindSymbol(void *handle, const char *symbol) 195{ 196 return dlsym(handle, symbol); 197} 198 199int CloseLib(void *handle) 200{ 201 return dlclose(handle); 202} 203 204char *LoadLibError() 205{ 206 return dlerror(); 207} 208 209} // namespace panda::ecmascript 210