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