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