FileHandle.cpp revision cedee4b38f4786845183be7f5916dd520a170ae0
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
222bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength)
223{
224  if (!isOpened()) {
225    setState(BadBit);
226    return false;
227  }
228
229  if (0 == pLength)
230    return true;
231
232  int prot, flag;
233  if (isReadable() && !isWritable()) {
234    // read-only
235    prot = PROT_READ;
236    flag = MAP_FILE | MAP_PRIVATE;
237  }
238  else if (!isReadable() && isWritable()) {
239    // write-only
240    prot = PROT_WRITE;
241    flag = MAP_FILE | MAP_SHARED;
242  }
243  else if (isReadWrite()) {
244    // read and write
245    prot = PROT_READ | PROT_WRITE;
246    flag = MAP_FILE | MAP_SHARED;
247  }
248  else {
249    // can not read/write
250    setState(BadBit);
251    return false;
252  }
253
254  pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset);
255
256  if (MAP_FAILED == pMemBuffer) {
257    setState(FailBit);
258    return false;
259  }
260
261  return true;
262}
263
264bool FileHandle::munmap(void* pMemBuffer, size_t pLength)
265{
266  if (!isOpened()) {
267    setState(BadBit);
268    return false;
269  }
270
271  if (-1 == ::munmap(pMemBuffer, pLength)) {
272    setState(FailBit);
273    return false;
274  }
275
276  return true;
277}
278
279void FileHandle::setState(FileHandle::IOState pState)
280{
281  m_State |= pState;
282}
283
284void FileHandle::cleanState(FileHandle::IOState pState)
285{
286  m_State = pState;
287}
288
289bool FileHandle::isOpened() const
290{
291  if (-1 != m_Handler && m_OpenMode != NotOpen && isGood())
292    return true;
293
294  return false;
295}
296
297// Assume Unknown OpenMode is readable
298bool FileHandle::isReadable() const
299{
300  return (m_OpenMode & ReadOnly);
301}
302
303// Assume Unknown OpenMode is writable
304bool FileHandle::isWritable() const
305{
306  return (m_OpenMode & WriteOnly);
307}
308
309// Assume Unknown OpenMode is both readable and writable
310bool FileHandle::isReadWrite() const
311{
312  return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
313}
314
315bool FileHandle::isGood() const
316{
317  return !(m_State & (BadBit | FailBit));
318}
319
320bool FileHandle::isBad() const
321{
322  return (m_State & BadBit);
323}
324
325bool FileHandle::isFailed() const
326{
327  return (m_State & (BadBit | FailBit));
328}
329
330