read.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Debug.h>
  7. #include <Kernel/FileSystem/FileDescription.h>
  8. #include <Kernel/Process.h>
  9. namespace Kernel {
  10. using BlockFlags = Thread::FileBlocker::BlockFlags;
  11. KResultOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count)
  12. {
  13. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
  14. REQUIRE_PROMISE(stdio);
  15. if (iov_count < 0)
  16. return EINVAL;
  17. // Arbitrary pain threshold.
  18. if (iov_count > (int)MiB)
  19. return EFAULT;
  20. u64 total_length = 0;
  21. Vector<iovec, 32> vecs;
  22. if (!vecs.try_resize(iov_count))
  23. return ENOMEM;
  24. if (!copy_n_from_user(vecs.data(), iov, iov_count))
  25. return EFAULT;
  26. for (auto& vec : vecs) {
  27. total_length += vec.iov_len;
  28. if (total_length > NumericLimits<i32>::max())
  29. return EINVAL;
  30. }
  31. auto description = fds().file_description(fd);
  32. if (!description)
  33. return EBADF;
  34. if (!description->is_readable())
  35. return EBADF;
  36. if (description->is_directory())
  37. return EISDIR;
  38. int nread = 0;
  39. for (auto& vec : vecs) {
  40. if (description->is_blocking()) {
  41. if (!description->can_read()) {
  42. auto unblock_flags = BlockFlags::None;
  43. if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
  44. return EINTR;
  45. if (!has_flag(unblock_flags, BlockFlags::Read))
  46. return EAGAIN;
  47. // TODO: handle exceptions in unblock_flags
  48. }
  49. }
  50. auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len);
  51. if (!buffer.has_value())
  52. return EFAULT;
  53. auto result = description->read(buffer.value(), vec.iov_len);
  54. if (result.is_error())
  55. return result.error();
  56. nread += result.value();
  57. }
  58. return nread;
  59. }
  60. KResultOr<FlatPtr> Process::sys$read(int fd, Userspace<u8*> buffer, size_t size)
  61. {
  62. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
  63. REQUIRE_PROMISE(stdio);
  64. if (size == 0)
  65. return 0;
  66. if (size > NumericLimits<ssize_t>::max())
  67. return EINVAL;
  68. dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size);
  69. auto description = fds().file_description(fd);
  70. if (!description)
  71. return EBADF;
  72. if (!description->is_readable())
  73. return EBADF;
  74. if (description->is_directory())
  75. return EISDIR;
  76. if (description->is_blocking()) {
  77. if (!description->can_read()) {
  78. auto unblock_flags = BlockFlags::None;
  79. if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
  80. return EINTR;
  81. if (!has_flag(unblock_flags, BlockFlags::Read))
  82. return EAGAIN;
  83. // TODO: handle exceptions in unblock_flags
  84. }
  85. }
  86. auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size);
  87. if (!user_buffer.has_value())
  88. return EFAULT;
  89. auto result = description->read(user_buffer.value(), size);
  90. if (result.is_error())
  91. return result.error();
  92. return result.value();
  93. }
  94. }