15460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//===- FileSystem.inc -----------------------------------------------------===// 25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// 35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// The MCLinker Project 45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// 55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// This file is distributed under the University of Illinois Open Source 65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// License. See LICENSE.TXT for details. 75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// 85460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//===----------------------------------------------------------------------===// 95460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <string> 105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <sys/types.h> 115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <sys/stat.h> 12f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include <sys/mman.h> 13f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include <dirent.h> 14affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <unistd.h> 155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <fcntl.h> 16f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include <mcld/Support/FileHandle.h> 17f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include <mcld/Support/Directory.h> 18f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines#include <llvm/Support/ErrorHandling.h> 195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaonamespace mcld{ 215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaonamespace sys{ 225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaonamespace fs{ 235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaonamespace detail{ 245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostd::string static_library_extension = ".a"; 265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostd::string shared_library_extension = ".so"; 27f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstd::string executable_extension = ""; 28f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstd::string relocatable_extension = ".o"; 29f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstd::string assembly_extension = ".s"; 30f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstd::string bitcode_extension = ".bc"; 31f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 32f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===// 33f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// Helper Functions 34f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===// 35f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// read_dir - return true if we read one entry 36f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// @return value -1: read error 37f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// 0: read the end 38f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// 1: success 39f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstatic int read_dir(intptr_t& pDir, std::string& pOutFilename) 40f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines{ 41f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines errno = 0; 42f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines dirent *cur_dir = ::readdir(reinterpret_cast<DIR*>(pDir)); 43f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (0 == cur_dir && 0 != errno) 44f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return -1; 45f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 46f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // idx does not stay at the end, but all elements had beed put into cache. 47f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (NULL == cur_dir) { 48f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return 0; 49f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 50f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 51f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines llvm::StringRef name(cur_dir->d_name, strlen(cur_dir->d_name)); 52f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if ((name.size() == 1 && name[0] == '.') || 53f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines (name.size() == 2 && name[0] == '.' && name[1] == '.')) 54f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return read_dir(pDir, pOutFilename); 55f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 56f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // find a new directory 57f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pOutFilename.append(name.data(), name.size()); 58f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return 1; 59f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 60f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 61f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesvoid open_dir(Directory& pDir) 62f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines{ 63f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pDir.m_Handler = reinterpret_cast<intptr_t>(opendir(pDir.path().c_str())); 64f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (0 == pDir.m_Handler) { 65f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines errno = 0; // opendir() will set errno if it failed to open directory. 66f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // set cache is full, then Directory::begin() can return end(). 67f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pDir.m_CacheFull = true; 68f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return; 69f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 70f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // read one entry for advance the end element of the cache. 71f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines std::string path(pDir.path().native()); 72f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines switch (read_dir(pDir.m_Handler, path)) { 73f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines case 1: { 74f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // find a new directory 75f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines bool exist = false; 76f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines mcld::sys::fs::PathCache::entry_type* entry = pDir.m_Cache.insert(path, exist); 77f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (!exist) 78f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines entry->setValue(path); 79f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return; 80f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 81f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines case 0: 82f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // FIXME: a warning function 83f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pDir.m_CacheFull = true; 84f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return; 85f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines default: 86f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines case -1: 87f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines llvm::report_fatal_error(std::string("Can't read directory: ")+ 88f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pDir.path().native()); 89f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 90f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 91f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 92f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesvoid close_dir(Directory& pDir) 93f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines{ 94f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pDir.m_Handler) 95f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines closedir(reinterpret_cast<DIR *>(pDir.m_Handler)); 96f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pDir.m_Handler = 0; 97f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 99affc150dc44fab1911775a49636d0ce85333b634Zonr Changint open(const Path& pPath, int pOFlag) 1005460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{ 101affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return ::open(pPath.native().c_str(), pOFlag); 1025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 1035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 104affc150dc44fab1911775a49636d0ce85333b634Zonr Changint open(const Path& pPath, int pOFlag, int pPerm) 1055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{ 106f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines mode_t perm = 0; 107f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::ReadOwner) 108f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IRUSR; 109f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::WriteOwner) 110f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IWUSR; 111f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::ExeOwner) 112f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IXUSR; 113f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::ReadGroup) 114f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IRGRP; 115f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::WriteGroup) 116f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IWGRP; 117f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::ExeGroup) 118f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IXGRP; 119f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::ReadOther) 120f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IROTH; 121f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::WriteOther) 122f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IWOTH; 123f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (pPerm & FileHandle::ExeOther) 124f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines perm |= S_IXOTH; 125f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 126f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return ::open(pPath.native().c_str(), pOFlag, perm); 1275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 1285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 129f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesssize_t pread(int pFD, void* pBuf, size_t pCount, off_t pOffset) 1305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{ 131affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return ::pread(pFD, pBuf, pCount, pOffset); 132affc150dc44fab1911775a49636d0ce85333b634Zonr Chang} 133affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 134f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesssize_t pwrite(int pFD, const void* pBuf, size_t pCount, off_t pOffset) 135affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{ 136affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return ::pwrite(pFD, pBuf, pCount, pOffset); 137affc150dc44fab1911775a49636d0ce85333b634Zonr Chang} 138affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 139affc150dc44fab1911775a49636d0ce85333b634Zonr Changint ftruncate(int pFD, size_t pLength) 140affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{ 141affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return ::ftruncate(pFD, pLength); 1425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 1435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 144f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesvoid get_pwd(Path& pPWD) 145f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines{ 146f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines char* pwd = (char*)malloc(PATH_MAX); 147f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pPWD.assign(getcwd(pwd, PATH_MAX)); 148f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines free(pwd); 149f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 150f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 1515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} // namespace of detail 1525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} // namespace of fs 1535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} // namespace of sys 154f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 155f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===// 156f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// FileHandler 157f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===// 158f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesbool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength) 159f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines{ 160f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (!isOpened()) { 161f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines setState(BadBit); 162f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return false; 163f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 164f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 165f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (0 == pLength) 166f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return true; 167f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 168f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines int prot, flag; 169f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (isReadable() && !isWritable()) { 170f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // read-only 171f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines prot = PROT_READ; 172f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines flag = MAP_FILE | MAP_PRIVATE; 173f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 174f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines else if (!isReadable() && isWritable()) { 175f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // write-only 176f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines prot = PROT_WRITE; 177f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines flag = MAP_FILE | MAP_SHARED; 178f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 179f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines else if (isReadWrite()) { 180f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // read and write 181f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines prot = PROT_READ | PROT_WRITE; 182f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines flag = MAP_FILE | MAP_SHARED; 183f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 184f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines else { 185f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // can not read/write 186f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines setState(BadBit); 187f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return false; 188f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 189f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 190f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset); 191f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 192f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (MAP_FAILED == pMemBuffer) { 193f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines setState(FailBit); 194f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return false; 195f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 196f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 197f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return true; 198f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 199f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 200f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesbool FileHandle::munmap(void* pMemBuffer, size_t pLength) 201f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines{ 202f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (!isOpened()) { 203f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines setState(BadBit); 204f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return false; 205f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 206f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 207f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (-1 == ::munmap(pMemBuffer, pLength)) { 208f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines setState(FailBit); 209f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return false; 210f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 211f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 212f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return true; 213f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 214f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 2155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} // namespace of mcld 2165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 217