FileDescriptor.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #include "FileDescriptor.h"
  2. #include "FileSystem.h"
  3. #include "CharacterDevice.h"
  4. #include <LibC/errno_numbers.h>
  5. #include "UnixTypes.h"
  6. #include <AK/BufferStream.h>
  7. #include "FIFO.h"
  8. #ifdef SERENITY
  9. #include "TTY.h"
  10. #include "MasterPTY.h"
  11. #endif
  12. RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Vnode>&& vnode)
  13. {
  14. return adopt(*new FileDescriptor(move(vnode)));
  15. }
  16. RetainPtr<FileDescriptor> FileDescriptor::create_pipe_writer(FIFO& fifo)
  17. {
  18. return adopt(*new FileDescriptor(fifo, FIFO::Writer));
  19. }
  20. RetainPtr<FileDescriptor> FileDescriptor::create_pipe_reader(FIFO& fifo)
  21. {
  22. return adopt(*new FileDescriptor(fifo, FIFO::Reader));
  23. }
  24. FileDescriptor::FileDescriptor(RetainPtr<Vnode>&& vnode)
  25. : m_vnode(move(vnode))
  26. {
  27. }
  28. FileDescriptor::~FileDescriptor()
  29. {
  30. if (m_fifo)
  31. m_fifo->close(fifo_direction());
  32. }
  33. RetainPtr<FileDescriptor> FileDescriptor::clone()
  34. {
  35. RetainPtr<FileDescriptor> descriptor;
  36. if (is_fifo()) {
  37. descriptor = fifo_direction() == FIFO::Reader
  38. ? FileDescriptor::create_pipe_reader(*m_fifo)
  39. : FileDescriptor::create_pipe_writer(*m_fifo);
  40. } else {
  41. descriptor = FileDescriptor::create(m_vnode.copyRef());
  42. }
  43. if (!descriptor)
  44. return nullptr;
  45. descriptor->m_current_offset = m_current_offset;
  46. #ifdef SERENITY
  47. descriptor->m_is_blocking = m_is_blocking;
  48. descriptor->m_file_flags = m_file_flags;
  49. #endif
  50. return descriptor;
  51. }
  52. #ifndef SERENITY
  53. bool additionWouldOverflow(Unix::off_t a, Unix::off_t b)
  54. {
  55. ASSERT(a > 0);
  56. uint64_t ua = a;
  57. return (ua + b) > maxFileOffset;
  58. }
  59. #endif
  60. int FileDescriptor::stat(Unix::stat* buffer)
  61. {
  62. ASSERT(!is_fifo());
  63. if (!m_vnode)
  64. return -EBADF;
  65. auto metadata = m_vnode->metadata();
  66. if (!metadata.isValid())
  67. return -EIO;
  68. buffer->st_dev = 0; // FIXME
  69. buffer->st_ino = metadata.inode.index();
  70. buffer->st_mode = metadata.mode;
  71. buffer->st_nlink = metadata.linkCount;
  72. buffer->st_uid = metadata.uid;
  73. buffer->st_gid = metadata.gid;
  74. buffer->st_rdev = 0; // FIXME
  75. buffer->st_size = metadata.size;
  76. buffer->st_blksize = metadata.blockSize;
  77. buffer->st_blocks = metadata.blockCount;
  78. buffer->st_atime = metadata.atime;
  79. buffer->st_mtime = metadata.mtime;
  80. buffer->st_ctime = metadata.ctime;
  81. return 0;
  82. }
  83. Unix::off_t FileDescriptor::seek(Unix::off_t offset, int whence)
  84. {
  85. ASSERT(!is_fifo());
  86. if (!m_vnode)
  87. return -EBADF;
  88. // FIXME: The file type should be cached on the vnode.
  89. // It's silly that we have to do a full metadata lookup here.
  90. auto metadata = m_vnode->metadata();
  91. if (!metadata.isValid())
  92. return -EIO;
  93. if (metadata.isSocket() || metadata.isFIFO())
  94. return -ESPIPE;
  95. Unix::off_t newOffset;
  96. switch (whence) {
  97. case SEEK_SET:
  98. newOffset = offset;
  99. break;
  100. case SEEK_CUR:
  101. newOffset = m_current_offset + offset;
  102. #ifndef SERENITY
  103. if (additionWouldOverflow(m_currentOffset, offset))
  104. return -EOVERFLOW;
  105. #endif
  106. if (newOffset < 0)
  107. return -EINVAL;
  108. break;
  109. case SEEK_END:
  110. ASSERT(metadata.size); // FIXME: What do I do?
  111. newOffset = metadata.size;
  112. break;
  113. default:
  114. return -EINVAL;
  115. }
  116. m_current_offset = newOffset;
  117. return m_current_offset;
  118. }
  119. ssize_t FileDescriptor::read(Process& process, byte* buffer, size_t count)
  120. {
  121. if (is_fifo()) {
  122. ASSERT(fifo_direction() == FIFO::Reader);
  123. return m_fifo->read(buffer, count);
  124. }
  125. if (m_vnode->isCharacterDevice()) {
  126. // FIXME: What should happen to m_currentOffset?
  127. return m_vnode->characterDevice()->read(process, buffer, count);
  128. }
  129. ASSERT(inode());
  130. ssize_t nread = inode()->read_bytes(m_current_offset, count, buffer, this);
  131. m_current_offset += nread;
  132. return nread;
  133. }
  134. ssize_t FileDescriptor::write(Process& process, const byte* data, size_t size)
  135. {
  136. if (is_fifo()) {
  137. ASSERT(fifo_direction() == FIFO::Writer);
  138. return m_fifo->write(data, size);
  139. }
  140. if (m_vnode->isCharacterDevice()) {
  141. // FIXME: What should happen to m_currentOffset?
  142. return m_vnode->characterDevice()->write(process, data, size);
  143. }
  144. // FIXME: Implement non-device writes.
  145. ASSERT_NOT_REACHED();
  146. return -1;
  147. }
  148. bool FileDescriptor::can_write(Process& process)
  149. {
  150. if (is_fifo()) {
  151. ASSERT(fifo_direction() == FIFO::Writer);
  152. return m_fifo->can_write();
  153. }
  154. if (m_vnode->isCharacterDevice())
  155. return m_vnode->characterDevice()->can_write(process);
  156. return true;
  157. }
  158. bool FileDescriptor::has_data_available_for_reading(Process& process)
  159. {
  160. if (is_fifo()) {
  161. ASSERT(fifo_direction() == FIFO::Reader);
  162. return m_fifo->can_read();
  163. }
  164. if (m_vnode->isCharacterDevice())
  165. return m_vnode->characterDevice()->can_read(process);
  166. return true;
  167. }
  168. ByteBuffer FileDescriptor::read_entire_file(Process& process)
  169. {
  170. ASSERT(!is_fifo());
  171. if (m_vnode->isCharacterDevice()) {
  172. auto buffer = ByteBuffer::create_uninitialized(1024);
  173. ssize_t nread = m_vnode->characterDevice()->read(process, buffer.pointer(), buffer.size());
  174. buffer.trim(nread);
  175. return buffer;
  176. }
  177. ASSERT(inode());
  178. return inode()->read_entire(this);
  179. }
  180. bool FileDescriptor::is_directory() const
  181. {
  182. ASSERT(!is_fifo());
  183. return m_vnode->metadata().isDirectory();
  184. }
  185. ssize_t FileDescriptor::get_dir_entries(byte* buffer, size_t size)
  186. {
  187. auto metadata = m_vnode->metadata();
  188. if (!metadata.isValid())
  189. return -EIO;
  190. if (!metadata.isDirectory())
  191. return -ENOTDIR;
  192. // FIXME: Compute the actual size needed.
  193. auto tempBuffer = ByteBuffer::create_uninitialized(2048);
  194. BufferStream stream(tempBuffer);
  195. m_vnode->vfs()->traverse_directory_inode(*m_vnode->core_inode(), [&stream] (auto& entry) {
  196. stream << (dword)entry.inode.index();
  197. stream << (byte)entry.fileType;
  198. stream << (dword)entry.name_length;
  199. stream << entry.name;
  200. return true;
  201. });
  202. if (size < stream.offset())
  203. return -1;
  204. memcpy(buffer, tempBuffer.pointer(), stream.offset());
  205. return stream.offset();
  206. }
  207. \
  208. #ifdef SERENITY
  209. bool FileDescriptor::is_tty() const
  210. {
  211. if (is_fifo())
  212. return false;
  213. if (auto* device = m_vnode->characterDevice())
  214. return device->is_tty();
  215. return false;
  216. }
  217. const TTY* FileDescriptor::tty() const
  218. {
  219. if (is_fifo())
  220. return nullptr;
  221. if (auto* device = m_vnode->characterDevice())
  222. return static_cast<const TTY*>(device);
  223. return nullptr;
  224. }
  225. TTY* FileDescriptor::tty()
  226. {
  227. if (is_fifo())
  228. return nullptr;
  229. if (auto* device = m_vnode->characterDevice())
  230. return static_cast<TTY*>(device);
  231. return nullptr;
  232. }
  233. bool FileDescriptor::is_master_pty() const
  234. {
  235. if (is_fifo())
  236. return false;
  237. if (auto* device = m_vnode->characterDevice())
  238. return device->is_master_pty();
  239. return false;
  240. }
  241. const MasterPTY* FileDescriptor::master_pty() const
  242. {
  243. if (!is_master_pty())
  244. return nullptr;
  245. return static_cast<const MasterPTY*>(m_vnode->characterDevice());
  246. }
  247. MasterPTY* FileDescriptor::master_pty()
  248. {
  249. if (!is_master_pty())
  250. return nullptr;
  251. return static_cast<MasterPTY*>(m_vnode->characterDevice());
  252. }
  253. #endif
  254. int FileDescriptor::close()
  255. {
  256. return 0;
  257. }
  258. String FileDescriptor::absolute_path()
  259. {
  260. Stopwatch sw("absolute_path");
  261. #ifdef SERENITY
  262. if (is_tty())
  263. return tty()->tty_name();
  264. #endif
  265. if (is_fifo()) {
  266. char buf[32];
  267. ksprintf(buf, "fifo:%x", m_fifo.ptr());
  268. return buf;
  269. }
  270. ASSERT(m_vnode->core_inode());
  271. return VFS::the().absolute_path(*m_vnode->core_inode());
  272. }
  273. FileDescriptor::FileDescriptor(FIFO& fifo, FIFO::Direction direction)
  274. : m_is_blocking(true)
  275. , m_fifo(fifo)
  276. , m_fifo_direction(direction)
  277. {
  278. m_fifo->open(direction);
  279. }