Repository: google/gvisor
File: test/syscalls/linux/write.cc (C++)

Code before:
  FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_RDONLY));

  char buf[16];
  EXPECT_THAT(write(fd.get(), buf, sizeof(buf)), SyscallFailsWithErrno(EBADF));
}

// Test that pwrite to a read-only fd fails with EBADF.
TEST_F(WriteTest, PwriteReadOnlyFd) {
  TempPath tmpfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_RDONLY));

  char buf[16];
  EXPECT_THAT(pwrite(fd.get(), buf, sizeof(buf), 0),
              SyscallFailsWithErrno(EBADF));
}

// Test that write to a directory fails with EBADF.
TEST_F(WriteTest, WriteDirectory) {
  const FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(GetAbsoluteTestTmpdir(), O_RDONLY));

  char buf[16];
  EXPECT_THAT(write(fd.get(), buf, sizeof(buf)), SyscallFailsWithErrno(EBADF));
}

// Test that pwrite with a negative offset fails with EINVAL.
TEST_F(WriteTest, PwriteNegativeOffset) {
  TempPath tmpfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_WRONLY));

  char buf[16];
  EXPECT_THAT(pwrite(fd.get(), buf, sizeof(buf), -1),
              SyscallFailsWithErrno(EINVAL));
}

// Test writing to a pipe.
TEST_F(WriteTest, WriteToPipe) {
  int pipe_fds[2];
  ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds());
  auto cleanup = Cleanup([&pipe_fds] {
    close(pipe_fds[0]);
    close(pipe_fds[1]);
  });

  const std::string data = "hello pipe";
  EXPECT_THAT(write(pipe_fds[1], data.data(), data.size()),
              SyscallSucceedsWithValue(data.size()));


Review comment (bug):
I think this is a bit misleading. The write fails with EBADF, not because it is a directory, but because the FD is opened in read-only mode. This is already tested in the `WriteReadOnlyFd` test you added. (If it were possible to open a directory with O_WRONLY, write would return EISDIR, but open fails with EISDIR first)

Code after:
  EXPECT_THAT(write(-1, buf, sizeof(buf)), SyscallFailsWithErrno(EBADF));
}

// Test that pwrite to a negative fd fails with EBADF.
TEST_F(WriteTest, PwriteNegativeFd) {
  char buf[16] = {};
  EXPECT_THAT(pwrite(-1, buf, sizeof(buf), 0), SyscallFailsWithErrno(EBADF));
}

// Test that write to a read-only fd fails with EBADF.
TEST_F(WriteTest, WriteReadOnlyFd) {
  TempPath tmpfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_RDONLY));

  char buf[16] = {};
  EXPECT_THAT(write(fd.get(), buf, sizeof(buf)), SyscallFailsWithErrno(EBADF));
}

// Test that pwrite to a read-only fd fails with EBADF.
TEST_F(WriteTest, PwriteReadOnlyFd) {
  TempPath tmpfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_RDONLY));

  char buf[16] = {};
  EXPECT_THAT(pwrite(fd.get(), buf, sizeof(buf), 0),
              SyscallFailsWithErrno(EBADF));
}

// Test that pwrite with a negative offset fails with EINVAL.
TEST_F(WriteTest, PwriteNegativeOffset) {
  TempPath tmpfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  FileDescriptor fd =
      ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_WRONLY));

  char buf[16] = {};
  EXPECT_THAT(pwrite(fd.get(), buf, sizeof(buf), -1),
              SyscallFailsWithErrno(EINVAL));
}

// Test writing to a pipe.
TEST_F(WriteTest, WriteToPipe) {
  int pipe_fds[2];
  ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds());
  auto cleanup = Cleanup([&pipe_fds] {
    close(pipe_fds[0]);
    close(pipe_fds[1]);
  });

  const std::string data = "hello pipe";