FileHandle.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
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/Config/Config.h"
10#include <mcld/Support/FileHandle.h>
11#include <mcld/Support/FileSystem.h>
12#include <errno.h>
13
14#if defined(HAVE_UNISTD_H)
15# include <unistd.h>
16#endif
17#if defined(HAVE_FCNTL_H)
18# include <fcntl.h>
19#endif
20
21#include <sys/stat.h>
22#include <sys/mman.h>
23
24#if defined(_MSC_VER)
25#include <io.h>
26#include <fcntl.h>
27#ifndef STDIN_FILENO
28# define STDIN_FILENO 0
29#endif
30#ifndef STDOUT_FILENO
31# define STDOUT_FILENO 1
32#endif
33#ifndef STDERR_FILENO
34# define STDERR_FILENO 2
35#endif
36#endif
37
38using namespace mcld;
39
40//===----------------------------------------------------------------------===//
41// FileHandle
42FileHandle::FileHandle()
43  : m_Path(),
44    m_Handler(-1),
45    m_Size(0),
46    m_State(GoodBit),
47    m_OpenMode(NotOpen) {
48}
49
50FileHandle::~FileHandle()
51{
52  if (isOpened())
53    close();
54}
55
56inline static int oflag(FileHandle::OpenMode pMode)
57{
58  int result = 0x0;
59  if (FileHandle::Unknown == pMode)
60    return result;
61
62  if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
63    result |= O_RDWR;
64  else if (FileHandle::ReadOnly == (pMode & FileHandle::ReadOnly))
65    result |= O_RDONLY;
66  else if (FileHandle::WriteOnly == (pMode & FileHandle::WriteOnly))
67    result |= O_WRONLY;
68
69  if (FileHandle::Append == (pMode & FileHandle::Append))
70    result |= O_APPEND;
71
72  if (FileHandle::Create == (pMode & FileHandle::Create))
73    result |= O_CREAT;
74
75  if (FileHandle::Truncate == (pMode & FileHandle::Truncate))
76    result |= O_TRUNC;
77
78  return result;
79}
80
81inline static bool get_size(int pHandler, unsigned int &pSize)
82{
83  struct ::stat file_stat;
84  if (-1 == ::fstat(pHandler, &file_stat)) {
85    pSize = 0;
86    return false;
87  }
88  pSize = file_stat.st_size;
89  return true;
90}
91
92bool FileHandle::open(const sys::fs::Path& pPath,
93                      FileHandle::OpenMode pMode,
94                      FileHandle::Permission pPerm)
95{
96  if (isOpened() || Unknown == pMode) {
97    setState(BadBit);
98    return false;
99  }
100
101  m_OpenMode = pMode;
102  if (System == pPerm)
103    m_Handler = sys::fs::detail::open(pPath, oflag(pMode));
104  else
105    m_Handler = sys::fs::detail::open(pPath, oflag(pMode), (int)pPerm);
106
107  m_Path = pPath;
108  if (-1 == m_Handler) {
109    m_OpenMode = NotOpen;
110    setState(FailBit);
111    return false;
112  }
113
114  if (!get_size(m_Handler, m_Size)) {
115    setState(FailBit);
116    return false;
117  }
118
119  return true;
120}
121
122bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
123{
124  if (isOpened()) {
125    setState(BadBit);
126    return false;
127  }
128
129  m_Handler = pFD;
130  m_OpenMode = pMode;
131  m_State = (GoodBit | DeputedBit);
132
133  if (!get_size(m_Handler, m_Size)) {
134    setState(FailBit);
135    return false;
136  }
137
138  return true;
139}
140
141bool FileHandle::close()
142{
143  if (!isOpened()) {
144    setState(BadBit);
145    return false;
146  }
147
148  if (isOwned()) {
149    if (-1 == ::close(m_Handler)) {
150      setState(FailBit);
151      return false;
152    }
153  }
154
155  m_Path.native().clear();
156  m_Size = 0;
157  m_OpenMode = NotOpen;
158  cleanState();
159  return true;
160}
161
162bool FileHandle::truncate(size_t pSize)
163{
164  if (!isOpened() || !isWritable()) {
165    setState(BadBit);
166    return false;
167  }
168
169  if (-1 == sys::fs::detail::ftruncate(m_Handler, pSize)) {
170    setState(FailBit);
171    return false;
172  }
173
174  m_Size = pSize;
175  return true;
176}
177
178bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength)
179{
180  if (!isOpened() || !isReadable()) {
181    setState(BadBit);
182    return false;
183  }
184
185  if (0 == pLength)
186    return true;
187
188  ssize_t read_bytes = sys::fs::detail::pread(m_Handler,
189                                              pMemBuffer,
190                                              pLength,
191                                              pStartOffset);
192
193  if (-1 == read_bytes) {
194    setState(FailBit);
195    return false;
196  }
197
198  return true;
199}
200
201bool FileHandle::write(const void* pMemBuffer, size_t pStartOffset, size_t pLength)
202{
203  if (!isOpened() || !isWritable()) {
204    setState(BadBit);
205    return false;
206  }
207
208  if (0 == pLength)
209    return true;
210
211
212  ssize_t write_bytes = sys::fs::detail::pwrite(m_Handler,
213                                                pMemBuffer,
214                                                pLength,
215                                                pStartOffset);
216
217  if (-1 == write_bytes) {
218    setState(FailBit);
219    return false;
220  }
221
222  return true;
223}
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
333bool FileHandle::isOwned() const
334{
335  return !(m_State & DeputedBit);
336}
337
338