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