/src/runtime/base/file/plain_file.cpp

https://github.com/kevlund/hiphop-php · C++ · 266 lines · 199 code · 36 blank · 31 comment · 46 complexity · ccaff42bc9fb48efcddeb71b3c18de6e MD5 · raw file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <unistd.h>
  17. #include <runtime/base/file/plain_file.h>
  18. #include <runtime/base/complex_types.h>
  19. #include <runtime/base/util/request_local.h>
  20. namespace HPHP {
  21. IMPLEMENT_OBJECT_ALLOCATION(PlainFile)
  22. ///////////////////////////////////////////////////////////////////////////////
  23. StaticString PlainFile::s_class_name("PlainFile");
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // constructor and destructor
  26. PlainFile::PlainFile(FILE *stream, bool nonblocking)
  27. : File(nonblocking), m_stream(stream), m_eof(false) {
  28. if (stream) m_fd = fileno(stream);
  29. }
  30. PlainFile::PlainFile(int fd, bool nonblocking)
  31. : File(nonblocking), m_stream(NULL), m_eof(false) {
  32. m_fd = fd;
  33. }
  34. PlainFile::~PlainFile() {
  35. closeImpl();
  36. }
  37. bool PlainFile::open(CStrRef filename, CStrRef mode) {
  38. int fd;
  39. FILE *f;
  40. ASSERT(m_stream == NULL);
  41. ASSERT(m_fd == -1);
  42. // For these definded in php fopen but C stream have different modes
  43. switch (mode[0]) {
  44. case 'x':
  45. if (mode.find('+') == -1) {
  46. fd = ::open(filename.data(), O_WRONLY|O_CREAT|O_EXCL, 0666);
  47. if (fd < 0) return false;
  48. f = fdopen(fd, "w");
  49. } else {
  50. fd = ::open(filename.data(), O_RDWR|O_CREAT|O_EXCL, 0666);
  51. if (fd < 0) return false;
  52. f = fdopen(fd, "w+");
  53. }
  54. break;
  55. case 'c':
  56. if (mode.find('+') == -1) {
  57. fd = ::open(filename.data(), O_WRONLY|O_CREAT, 0666);
  58. if (fd < 0) return false;
  59. f = fdopen(fd, "w");
  60. } else {
  61. fd = ::open(filename.data(), O_RDWR|O_CREAT, 0666);
  62. if (fd < 0) return false;
  63. f = fdopen(fd, "w+");
  64. }
  65. break;
  66. default:
  67. f = fopen(filename.data(), mode.data());
  68. }
  69. if (!f) {
  70. return false;
  71. }
  72. m_stream = f;
  73. m_fd = fileno(f);
  74. return true;
  75. }
  76. bool PlainFile::close() {
  77. return closeImpl();
  78. }
  79. bool PlainFile::closeImpl() {
  80. bool ret = true;
  81. s_file_data->m_pcloseRet = 0;
  82. if (!m_closed) {
  83. if (m_stream) {
  84. s_file_data->m_pcloseRet = fclose(m_stream);
  85. m_stream = NULL;
  86. } else if (m_fd >= 0) {
  87. s_file_data->m_pcloseRet = ::close(m_fd);
  88. }
  89. ret = (s_file_data->m_pcloseRet == 0);
  90. m_closed = true;
  91. m_fd = -1;
  92. }
  93. File::closeImpl();
  94. return ret;
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////
  97. // virtual functions
  98. int64 PlainFile::readImpl(char *buffer, int64 length) {
  99. ASSERT(valid());
  100. ASSERT(length > 0);
  101. // use read instead of fread to handle EOL in stdin
  102. size_t ret = ::read(m_fd, buffer, length);
  103. if (ret == 0
  104. || (ret == (size_t)-1
  105. && errno != EWOULDBLOCK && errno != EINTR && errno != EBADF)) {
  106. m_eof = true;
  107. }
  108. return ret == (size_t)-1 ? 0 : ret;
  109. }
  110. int PlainFile::getc() {
  111. ASSERT(valid());
  112. return File::getc();
  113. }
  114. int64 PlainFile::writeImpl(const char *buffer, int64 length) {
  115. ASSERT(valid());
  116. ASSERT(length > 0);
  117. // use write instead of fwrite to be consistent with read
  118. // o.w., read-and-write files would not work
  119. int64 written = ::write(m_fd, buffer, length);
  120. return written < 0 ? 0 : written;
  121. }
  122. bool PlainFile::seek(int64 offset, int whence /* = SEEK_SET */) {
  123. ASSERT(valid());
  124. if (whence == SEEK_CUR) {
  125. if (offset > 0 && offset < m_writepos - m_readpos) {
  126. m_readpos += offset;
  127. m_position += offset;
  128. return true;
  129. }
  130. offset += m_position;
  131. whence = SEEK_SET;
  132. }
  133. // invalidate the current buffer
  134. m_writepos = 0;
  135. m_readpos = 0;
  136. // clear the eof flag
  137. m_eof = false;
  138. flush();
  139. // lseek instead of seek to be consistent with read
  140. off_t result = lseek(m_fd, offset, whence);
  141. m_position = result;
  142. return result != (off_t)-1;
  143. }
  144. int64 PlainFile::tell() {
  145. ASSERT(valid());
  146. return m_position;
  147. }
  148. bool PlainFile::eof() {
  149. ASSERT(valid());
  150. int64 avail = m_writepos - m_readpos;
  151. if (avail > 0) {
  152. return false;
  153. }
  154. return m_eof;
  155. }
  156. bool PlainFile::rewind() {
  157. ASSERT(valid());
  158. seek(0);
  159. m_writepos = 0;
  160. m_readpos = 0;
  161. m_position = 0;
  162. return true;
  163. }
  164. bool PlainFile::flush() {
  165. if (m_stream) {
  166. return fflush(m_stream) == 0;
  167. }
  168. ASSERT(valid());
  169. // No need to flush a file descriptor.
  170. return true;
  171. }
  172. bool PlainFile::truncate(int64 size) {
  173. ASSERT(valid());
  174. return ftruncate(m_fd, size) == 0;
  175. }
  176. ///////////////////////////////////////////////////////////////////////////////
  177. // BuiltinFiles
  178. BuiltinFile::~BuiltinFile() {
  179. m_closed = true;
  180. m_stream = NULL;
  181. m_fd = -1;
  182. }
  183. bool BuiltinFile::close() {
  184. ::fclose(m_stream);
  185. m_closed = true;
  186. m_stream = NULL;
  187. m_fd = -1;
  188. File::closeImpl();
  189. return true;
  190. }
  191. IMPLEMENT_REQUEST_LOCAL(BuiltinFiles, g_builtin_files);
  192. void BuiltinFiles::requestInit() {
  193. GetSTDIN();
  194. GetSTDOUT();
  195. GetSTDERR();
  196. }
  197. void BuiltinFiles::requestShutdown() {
  198. m_stdin.reset();
  199. m_stdout.reset();
  200. m_stderr.reset();
  201. }
  202. CVarRef BuiltinFiles::GetSTDIN() {
  203. if (g_builtin_files->m_stdin.isNull()) {
  204. BuiltinFile *f = NEWOBJ(BuiltinFile)(stdin);
  205. g_builtin_files->m_stdin = f;
  206. f->o_setId(1);
  207. ASSERT(f->o_getId() == 1);
  208. }
  209. return g_builtin_files->m_stdin;
  210. }
  211. CVarRef BuiltinFiles::GetSTDOUT() {
  212. if (g_builtin_files->m_stdout.isNull()) {
  213. BuiltinFile *f = NEWOBJ(BuiltinFile)(stdout);
  214. g_builtin_files->m_stdout = f;
  215. f->o_setId(2);
  216. ASSERT(f->o_getId() == 2);
  217. }
  218. return g_builtin_files->m_stdout;
  219. }
  220. CVarRef BuiltinFiles::GetSTDERR() {
  221. if (g_builtin_files->m_stderr.isNull()) {
  222. BuiltinFile *f = NEWOBJ(BuiltinFile)(stderr);
  223. g_builtin_files->m_stderr = f;
  224. f->o_setId(3);
  225. ASSERT(f->o_getId() == 3);
  226. }
  227. return g_builtin_files->m_stderr;
  228. }
  229. ///////////////////////////////////////////////////////////////////////////////
  230. }