FileHandle.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include "FileHandle.h"
  2. #include "FileSystem.h"
  3. #include "CharacterDevice.h"
  4. #include "sys-errno.h"
  5. #include "UnixTypes.h"
  6. #include "TTY.h"
  7. #include <AK/BufferStream.h>
  8. FileHandle::FileHandle(RetainPtr<VirtualFileSystem::Node>&& vnode)
  9. : m_vnode(move(vnode))
  10. {
  11. }
  12. FileHandle::~FileHandle()
  13. {
  14. }
  15. #ifndef SERENITY
  16. bool additionWouldOverflow(Unix::off_t a, Unix::off_t b)
  17. {
  18. ASSERT(a > 0);
  19. uint64_t ua = a;
  20. return (ua + b) > maxFileOffset;
  21. }
  22. #endif
  23. int FileHandle::stat(Unix::stat* buffer)
  24. {
  25. if (!m_vnode)
  26. return -EBADF;
  27. auto metadata = m_vnode->metadata();
  28. if (!metadata.isValid())
  29. return -EIO;
  30. buffer->st_dev = 0; // FIXME
  31. buffer->st_ino = metadata.inode.index();
  32. buffer->st_mode = metadata.mode;
  33. buffer->st_nlink = metadata.linkCount;
  34. buffer->st_uid = metadata.uid;
  35. buffer->st_gid = metadata.gid;
  36. buffer->st_rdev = 0; // FIXME
  37. buffer->st_size = metadata.size;
  38. buffer->st_blksize = metadata.blockSize;
  39. buffer->st_blocks = metadata.blockCount;
  40. buffer->st_atime = metadata.atime;
  41. buffer->st_mtime = metadata.mtime;
  42. buffer->st_ctime = metadata.ctime;
  43. return 0;
  44. }
  45. Unix::off_t FileHandle::seek(Unix::off_t offset, int whence)
  46. {
  47. if (!m_vnode)
  48. return -EBADF;
  49. // FIXME: The file type should be cached on the vnode.
  50. // It's silly that we have to do a full metadata lookup here.
  51. auto metadata = m_vnode->metadata();
  52. if (!metadata.isValid())
  53. return -EIO;
  54. if (metadata.isSocket() || metadata.isFIFO())
  55. return -ESPIPE;
  56. Unix::off_t newOffset;
  57. switch (whence) {
  58. case SEEK_SET:
  59. newOffset = offset;
  60. break;
  61. case SEEK_CUR:
  62. newOffset = m_currentOffset + offset;
  63. #ifndef SERENITY
  64. if (additionWouldOverflow(m_currentOffset, offset))
  65. return -EOVERFLOW;
  66. #endif
  67. if (newOffset < 0)
  68. return -EINVAL;
  69. break;
  70. case SEEK_END:
  71. // FIXME: Implement!
  72. notImplemented();
  73. newOffset = 0;
  74. break;
  75. default:
  76. return -EINVAL;
  77. }
  78. m_currentOffset = newOffset;
  79. return m_currentOffset;
  80. }
  81. Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count)
  82. {
  83. if (m_vnode->isCharacterDevice()) {
  84. // FIXME: What should happen to m_currentOffset?
  85. return m_vnode->characterDevice()->read(buffer, count);
  86. }
  87. Unix::ssize_t nread = m_vnode->fileSystem()->readInodeBytes(m_vnode->inode, m_currentOffset, count, buffer, this);
  88. m_currentOffset += nread;
  89. return nread;
  90. }
  91. Unix::ssize_t FileHandle::write(const byte* data, Unix::size_t size)
  92. {
  93. if (m_vnode->isCharacterDevice()) {
  94. // FIXME: What should happen to m_currentOffset?
  95. return m_vnode->characterDevice()->write(data, size);
  96. }
  97. // FIXME: Implement non-device writes.
  98. ASSERT_NOT_REACHED();
  99. return -1;
  100. }
  101. bool FileHandle::hasDataAvailableForRead()
  102. {
  103. if (m_vnode->isCharacterDevice())
  104. return m_vnode->characterDevice()->hasDataAvailableForRead();
  105. return true;
  106. }
  107. ByteBuffer FileHandle::readEntireFile()
  108. {
  109. if (m_vnode->isCharacterDevice()) {
  110. auto buffer = ByteBuffer::createUninitialized(1024);
  111. Unix::ssize_t nread = m_vnode->characterDevice()->read(buffer.pointer(), buffer.size());
  112. buffer.trim(nread);
  113. return buffer;
  114. }
  115. return m_vnode->fileSystem()->readEntireInode(m_vnode->inode, this);
  116. }
  117. bool FileHandle::isDirectory() const
  118. {
  119. return m_vnode->metadata().isDirectory();
  120. }
  121. ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size)
  122. {
  123. auto metadata = m_vnode->metadata();
  124. if (!metadata.isValid())
  125. return -EIO;
  126. if (!metadata.isDirectory())
  127. return -ENOTDIR;
  128. // FIXME: Compute the actual size needed.
  129. auto tempBuffer = ByteBuffer::createUninitialized(2048);
  130. BufferStream stream(tempBuffer);
  131. m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (const FileSystem::DirectoryEntry& entry) {
  132. stream << (dword)entry.inode.index();
  133. stream << (byte)entry.fileType;
  134. stream << (dword)entry.name.length();
  135. stream << entry.name;
  136. return true;
  137. });
  138. if (size < stream.offset())
  139. return -1;
  140. memcpy(buffer, tempBuffer.pointer(), stream.offset());
  141. return stream.offset();
  142. }
  143. bool FileHandle::isTTY() const
  144. {
  145. if (auto* device = m_vnode->characterDevice())
  146. return device->isTTY();
  147. return false;
  148. }
  149. const TTY* FileHandle::tty() const
  150. {
  151. if (auto* device = m_vnode->characterDevice())
  152. return static_cast<const TTY*>(device);
  153. return nullptr;
  154. }