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