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