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