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