FileHandle.cpp revision affc150dc44fab1911775a49636d0ce85333b634
1//===- FileHandle.cpp -----------------------------------------------------===//
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/FileSystem.h>
11#include <errno.h>
12#include <fcntl.h>
13#include <sys/stat.h>
14#include <sys/mman.h>
15
16using namespace mcld;
17
18//===----------------------------------------------------------------------===//
19// FileHandle
20FileHandle::FileHandle()
21  : m_Path(),
22    m_Handler(-1),
23    m_Size(0),
24    m_State(GoodBit),
25    m_OpenMode(NotOpen) {
26}
27
28FileHandle::~FileHandle()
29{
30  if (isOpened())
31    close();
32}
33
34inline static int oflag(FileHandle::OpenMode pMode)
35{
36  int result = 0x0;
37  if (FileHandle::Unknown == pMode)
38    return result;
39
40  if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
41    result |= O_RDWR;
42  else if (pMode & FileHandle::ReadOnly)
43    result |= O_RDONLY;
44  else if (pMode & FileHandle::WriteOnly)
45    result |= O_WRONLY;
46
47  if (pMode & FileHandle::Append)
48    result |= O_APPEND;
49
50  if (pMode & FileHandle::Create)
51    result |= O_CREAT;
52
53  if (pMode & FileHandle::Truncate)
54    result |= O_TRUNC;
55
56  return result;
57}
58
59inline static bool get_size(int pHandler, unsigned int &pSize)
60{
61  struct ::stat file_stat;
62  if (-1 == ::fstat(pHandler, &file_stat)) {
63    pSize = 0;
64    return false;
65  }
66  pSize = file_stat.st_size;
67  return true;
68}
69
70bool FileHandle::open(const sys::fs::Path& pPath,
71                      FileHandle::OpenMode pMode)
72{
73  if (isOpened() || Unknown == pMode) {
74    setState(BadBit);
75    return false;
76  }
77
78  m_OpenMode = pMode;
79  m_Handler = ::open(pPath.native().c_str(), oflag(pMode));
80  m_Path = pPath;
81  if (-1 == m_Handler) {
82    m_OpenMode = NotOpen;
83    setState(FailBit);
84    return false;
85  }
86
87  if (!get_size(m_Handler, m_Size)) {
88    setState(FailBit);
89    return false;
90  }
91
92  return true;
93}
94
95bool FileHandle::open(const sys::fs::Path& pPath,
96                      FileHandle::OpenMode pMode,
97                      FileHandle::Permission pPerm)
98{
99  if (isOpened() || Unknown == pMode) {
100    setState(BadBit);
101    return false;
102  }
103
104  m_OpenMode = pMode;
105  m_Handler = sys::fs::detail::open(pPath, oflag(pMode), (int)pPerm);
106  m_Path = pPath;
107  if (-1 == m_Handler) {
108    m_OpenMode = NotOpen;
109    setState(FailBit);
110    return false;
111  }
112
113  if (!get_size(m_Handler, m_Size)) {
114    setState(FailBit);
115    return false;
116  }
117
118  return true;
119}
120
121bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
122{
123  if (isOpened()) {
124    setState(BadBit);
125    return false;
126  }
127
128  m_Handler = pFD;
129  m_OpenMode = pMode;
130  m_State = GoodBit;
131
132  if (!get_size(m_Handler, m_Size)) {
133    setState(FailBit);
134    return false;
135  }
136
137  return true;
138}
139
140bool FileHandle::close()
141{
142  if (!isOpened()) {
143    setState(BadBit);
144    return false;
145  }
146
147  if (-1 == ::close(m_Handler)) {
148    setState(FailBit);
149    return false;
150  }
151
152  m_Path.native().clear();
153  m_Size = 0;
154  m_OpenMode = NotOpen;
155  cleanState();
156  return true;
157}
158
159bool FileHandle::truncate(size_t pSize)
160{
161  if (!isOpened() || !isWritable()) {
162    setState(BadBit);
163    return false;
164  }
165
166  if (-1 == sys::fs::detail::ftruncate(m_Handler, pSize)) {
167    setState(FailBit);
168    return false;
169  }
170
171  m_Size = pSize;
172  return true;
173}
174
175bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength)
176{
177  if (!isOpened() || !isReadable()) {
178    setState(BadBit);
179    return false;
180  }
181
182  if (0 == pLength)
183    return true;
184
185  ssize_t read_bytes = sys::fs::detail::pread(m_Handler,
186                                              pMemBuffer,
187                                              pLength,
188                                              pStartOffset);
189
190  if (-1 == read_bytes) {
191    setState(FailBit);
192    return false;
193  }
194
195  return true;
196}
197
198bool FileHandle::write(const void* pMemBuffer, size_t pStartOffset, size_t pLength)
199{
200  if (!isOpened() || !isWritable()) {
201    setState(BadBit);
202    return false;
203  }
204
205  if (0 == pLength)
206    return true;
207
208
209  ssize_t write_bytes = sys::fs::detail::pwrite(m_Handler,
210                                                pMemBuffer,
211                                                pLength,
212                                                pStartOffset);
213
214  if (-1 == write_bytes) {
215    setState(FailBit);
216    return false;
217  }
218
219  return true;
220}
221
222#include <iostream>
223using namespace std;
224
225bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength)
226{
227  if (!isOpened()) {
228    setState(BadBit);
229    return false;
230  }
231
232  if (0 == pLength)
233    return true;
234
235  int prot, flag;
236  if (isReadable() && !isWritable()) {
237    // read-only
238    prot = PROT_READ;
239    flag = MAP_FILE | MAP_PRIVATE;
240  }
241  else if (!isReadable() && isWritable()) {
242    // write-only
243    prot = PROT_WRITE;
244    flag = MAP_FILE | MAP_SHARED;
245  }
246  else if (isReadWrite()) {
247    // read and write
248    prot = PROT_READ | PROT_WRITE;
249    flag = MAP_FILE | MAP_SHARED;
250  }
251  else {
252    // can not read/write
253    setState(BadBit);
254    return false;
255  }
256
257  pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset);
258
259  if (MAP_FAILED == pMemBuffer) {
260    setState(FailBit);
261    return false;
262  }
263
264  return true;
265}
266
267bool FileHandle::munmap(void* pMemBuffer, size_t pLength)
268{
269  if (!isOpened()) {
270    setState(BadBit);
271    return false;
272  }
273
274  if (-1 == ::munmap(pMemBuffer, pLength)) {
275    setState(FailBit);
276    return false;
277  }
278
279  return true;
280}
281
282void FileHandle::setState(FileHandle::IOState pState)
283{
284  m_State |= pState;
285}
286
287void FileHandle::cleanState(FileHandle::IOState pState)
288{
289  m_State = pState;
290}
291
292bool FileHandle::isOpened() const
293{
294  if (-1 != m_Handler && m_OpenMode != NotOpen && isGood())
295    return true;
296
297  return false;
298}
299
300// Assume Unknown OpenMode is readable
301bool FileHandle::isReadable() const
302{
303  return (m_OpenMode & ReadOnly);
304}
305
306// Assume Unknown OpenMode is writable
307bool FileHandle::isWritable() const
308{
309  return (m_OpenMode & WriteOnly);
310}
311
312// Assume Unknown OpenMode is both readable and writable
313bool FileHandle::isReadWrite() const
314{
315  return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
316}
317
318bool FileHandle::isGood() const
319{
320  return !(m_State & (BadBit | FailBit));
321}
322
323bool FileHandle::isBad() const
324{
325  return (m_State & BadBit);
326}
327
328bool FileHandle::isFailed() const
329{
330  return (m_State & (BadBit | FailBit));
331}
332
333